Probleme mit Form ohne Border

  • C#

Es gibt 20 Antworten in diesem Thema. Der letzte Beitrag () ist von Artentus.

    Probleme mit Form ohne Border

    Hey,

    ich wollte gerade mal versuchen, einen eigenen Formrand mit GDI+ zu zeichnen. Dafür habe ich den FormBorderStyle auf None gesetzt (logisch).
    Nun wollte ich diese Form aber trotzdem verschieben können, sowie ihre Größe ändern können. Dafür verwende ich folgenden Code:
    Spoiler anzeigen

    C#-Quellcode

    1. [DllImport("user32.dll")]
    2. public static extern int SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
    3. private const int WM_NCLBUTTONDOWN = 0xA1;
    4. private const int HT_CAPTION = 2;
    5. private const int HT_LEFT = 10;
    6. private const int HT_RIGHT = 11;
    7. private const int HT_TOP = 12;
    8. private const int HT_TOPLEFT = 13;
    9. private const int HT_TOPRIGHT = 14;
    10. private const int HT_BOTTOM = 15;
    11. private const int HT_BOTTOMLEFT = 16;
    12. private const int HT_BOTTOMRIGHT = 17;
    13. protected override void OnMouseDown(MouseEventArgs e)
    14. {
    15. base.OnMouseDown(e);
    16. if (e.Button == MouseButtons.Left)
    17. {
    18. Capture = false;
    19. var wParam = 0;
    20. if (e.Y <= borderSize && e.X <= borderSize)
    21. wParam = HT_TOPLEFT;
    22. else if (e.Y <= borderSize && e.X >= ClientSize.Width - borderSize)
    23. wParam = HT_TOPRIGHT;
    24. else if (e.Y <= borderSize)
    25. wParam = HT_TOP;
    26. else if (e.Y >= ClientSize.Height - borderSize && e.X <= borderSize)
    27. wParam = HT_BOTTOMLEFT;
    28. else if (e.Y >= ClientSize.Height - borderSize && e.X >= ClientSize.Width - borderSize)
    29. wParam = HT_BOTTOMRIGHT;
    30. else if (e.Y >= ClientSize.Height - borderSize)
    31. wParam = HT_BOTTOM;
    32. else if (e.X <= borderSize)
    33. wParam = HT_LEFT;
    34. else if (e.X >= ClientSize.Width - borderSize)
    35. wParam = HT_RIGHT;
    36. else if (e.Y <= 30)
    37. wParam = HT_CAPTION;
    38. else
    39. return;
    40. SendMessage(Handle, WM_NCLBUTTONDOWN, new IntPtr(wParam), IntPtr.Zero);
    41. }
    42. }

    Das funktioniert auch alles so wie gewollt.

    Nun besitzt so eine Form ohne Border aber auch kein Systemmenü (das Menü, dass sich bei Alt + Space oder bei Rechtsklick auf das Icon in der Taskleiste öffnet). Dieses kann man sich ebenfalls zurückholen, und zwar mit diesem Code:
    Spoiler anzeigen

    C#-Quellcode

    1. protected override CreateParams CreateParams
    2. {
    3. get
    4. {
    5. CreateParams cp = base.CreateParams;
    6. const int WS_CLIPCHILDREN = 0x2000000;
    7. const int WS_MINIMIZEBOX = 0x20000;
    8. const int WS_MAXIMIZEBOX = 0x10000;
    9. const int WS_SYSMENU = 0x80000;
    10. const int CS_DROPSHADOW = 0x20000;
    11. int classFlags = cp.ClassStyle;
    12. if (Environment.OSVersion.Version.Major >= 6)
    13. classFlags |= CS_DROPSHADOW;
    14. cp.Style |= WS_CLIPCHILDREN | WS_MINIMIZEBOX | WS_SYSMENU | WS_MAXIMIZEBOX;
    15. cp.ClassStyle = classFlags;
    16. return cp;
    17. }
    18. }

    Jetzt ist aber mein Problem, dass wenn ich diesen Code ebenfalls in die Form einfüge, man ihre Größe nicht mehr ändern kann (verschieben geht noch). Weiß jemand, woran das liegt oder was ich anders machen muss/kann?
    Vielleicht musst du noch den Wert "WS_SIZEBOX" hinzufügen zu den Styles (könnte vielleicht der Grund sein).
    Kannst ja mal hier gucken, ob du da noch was findest, was dir weiterhilft. Bin mir grade aber nicht wirklich sicher, ob das dein Problem lösen kann, aber Probieren kostet ja schließlich nichts ;)
    Schau dir doch bei anderen Programmen mal an, welche Window-Styles die gesetzt haben. Geht doch mit einem SysInternals Tool, glaube ich.
    Mir fällt zum Beispiel Steam ein.

    Skybird schrieb:

    Das sind ja Ubisoftmethoden hier !

    So ich habe nun das Resizing komplett selber implementiert, mein Code sieht so aus:
    Spoiler anzeigen

    C#-Quellcode

    1. ResizeDirection sizeDir;
    2. Point lastCursorPos;
    3. protected override void OnMouseDown(MouseEventArgs e)
    4. {
    5. base.OnMouseDown(e);
    6. const int WM_NCLBUTTONDOWN = 0xA1;
    7. const int HT_CAPTION = 0x2;
    8. if (e.Button == MouseButtons.Left)
    9. {
    10. if (e.Y <= borderSize)
    11. sizeDir |= ResizeDirection.Top;
    12. if (e.Y >= ClientSize.Height - borderSize)
    13. sizeDir |= ResizeDirection.Bottom;
    14. if (e.X <= borderSize)
    15. sizeDir |= ResizeDirection.Left;
    16. if (e.X >= ClientSize.Width - borderSize)
    17. sizeDir |= ResizeDirection.Right;
    18. if (e.Y <= 30 && sizeDir == ResizeDirection.None)
    19. {
    20. Capture = false;
    21. SendMessage(Handle, WM_NCLBUTTONDOWN, new IntPtr(HT_CAPTION), IntPtr.Zero);
    22. }
    23. lastCursorPos = e.Location;
    24. }
    25. }
    26. protected override void OnMouseUp(MouseEventArgs e)
    27. {
    28. base.OnMouseUp(e);
    29. sizeDir = ResizeDirection.None;
    30. }
    31. protected override void OnMouseMove(MouseEventArgs e)
    32. {
    33. base.OnMouseMove(e);
    34. if (e.Button == MouseButtons.Left && sizeDir != ResizeDirection.None)
    35. {
    36. var xDif = lastCursorPos.X - e.X;
    37. var yDif = lastCursorPos.Y - e.Y;
    38. var addX = 0;
    39. var addY = 0;
    40. var addWidth = 0;
    41. var addHeight = 0;
    42. if ((sizeDir & ResizeDirection.Left) == ResizeDirection.Left)
    43. {
    44. addX = -xDif;
    45. addWidth = xDif;
    46. }
    47. if ((sizeDir & ResizeDirection.Right) == ResizeDirection.Right)
    48. addWidth = -xDif;
    49. if ((sizeDir & ResizeDirection.Top) == ResizeDirection.Top)
    50. {
    51. addY = -yDif;
    52. addHeight = yDif;
    53. }
    54. if ((sizeDir & ResizeDirection.Bottom) == ResizeDirection.Bottom)
    55. addHeight = -yDif;
    56. SetBounds(Location.X + addX, Location.Y + addY, Width + addWidth, Height + addHeight, BoundsSpecified.All);
    57. lastCursorPos = e.Location;
    58. }
    59. }
    60. [Flags()]
    61. private enum ResizeDirection
    62. {
    63. None = 0x0,
    64. Left = 0x1,
    65. Right = 0x2,
    66. Top = 0x4,
    67. Bottom = 0x8
    68. }


    Wenn ich rechts, unten oder unten-rechts ziehe funktioniert das ganze. Wenn ich aber links, oben oder links-oben ziehe, dann scheint es so, als könne sich die Form nicht schnell genug aktualisieren, jedenfalls flackert sie sehr stark und folgt auch nicht wirklich dem Mauszeiger. Hat jemand ne Idee?

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Artentus“ ()

    Ich habe mal einen Form-Style von vor 2 Jahren ausgegraben, dort habe ich die Bewegung für links und oben so gelöst:
    Bewegung für links und rechts direkt in einem:

    VB.NET-Quellcode

    1. MyBase.ParentForm.Size = New Size(MyBase.ParentForm.Width + (MyBase.ParentForm.Location.X - MousePosition.X), MyBase.ParentForm.Height)
    2. MyBase.ParentForm.Location = New Point(MousePosition.X, MyBase.ParentForm.Location.Y)

    Für oben und unten:

    VB.NET-Quellcode

    1. MyBase.ParentForm.Size = New Size(MyBase.ParentForm.Width, MyBase.ParentForm.Height + (MyBase.ParentForm.Location.Y - MousePosition.Y))
    2. MyBase.ParentForm.Location = New Point(MyBase.ParentForm.Location.X, MousePosition.Y)

    Skybird schrieb:

    Das sind ja Ubisoftmethoden hier !

    Artentus schrieb:

    @vb-checker
    Danke für den Vorschlag, aber mit dem ProcessExplorer gehts schon mal nicht. Weißt du vielleicht, welches Tool genau ich brauche?

    Ich hab jetzt auch kein Programm gefunden, aber eine Funktion: GetWindowLong
    Wenn du als zweites Argument -20 oder -16 übergibst, bekommst du Style oder ExStyle des Fensters zurück. Um da einzelne Style-Konstanten rauszubekommen, braucht man halt wieder Logik-zauberei mit Or/And/Bla, das kann ich mir nie merken, auch wenns um Enums geht ^^
    Funktionierendes Beispiel

    VB.NET-Quellcode

    1. <DllImport("user32.dll", SetLastError:=True)> _
    2. Private Shared Function GetWindowLong(hWnd As IntPtr, nIndex As Integer) As UInt32
    3. End Function
    4. Dim myProcess As New Process()
    5. myProcess.StartInfo.FileName = "notepad"
    6. myProcess.Start()
    7. Dim style As UInt32 = GetWindowLong(myProcess.Handle, -16)

    Skybird schrieb:

    Das sind ja Ubisoftmethoden hier !