Dialog auf dem Bildschirm korrekt platzieren (Multi-Monitor)

  • C#
  • .NET (FX) 4.0

Es gibt 10 Antworten in diesem Thema. Der letzte Beitrag () ist von DTF.

    Dialog auf dem Bildschirm korrekt platzieren (Multi-Monitor)

    Hallo liebe Community,

    ich bin mir aktuell gar nicht sicher, ob ich da gerade nur einen Furz im Kopf habe, oder ob mir das Framework da einen Streich spielt.

    Ich habe einen Dialog mit einer selbst gebauten Menü-Leiste (TableLayoutPanel mit Buttons), die oben angebracht ist:


    Beim Klick auf die Schaltfläche Item3, geht ein weiterer Dialog auf, der einem Dropdown ähneln soll:


    Grundsätzlich soll der Dropdown-Dialog an der unteren linken Ecke des angeklickten Menü-Buttons positioniert werden.

    Da hier der Dropdown-Dialog allerdings so aus dem Hauptdialog herausragt, möchte ich diesen um die "Herausrag-Differenz" zurückschieben.

    Mein Versuch:

    C#-Quellcode

    1. var button = sender as Button;
    2. var dialog = new frmMenu();
    3. dialog.StartPosition = FormStartPosition.Manual;
    4. var ptLowerLeft = new Point(0, button.Height);
    5. ptLowerLeft = button.PointToScreen(ptLowerLeft);
    6. dialog.Location = ptLowerLeft;
    7. var frmRightScreenCoordinate = Location.X + Right;
    8. var menuRightScreenCoordinate = ptLowerLeft.X + dialog.Width;
    9. if (menuRightScreenCoordinate > frmRightScreenCoordinate)
    10. {
    11. var diff = menuRightScreenCoordinate - frmRightScreenCoordinate;
    12. dialog.Location = new Point(dialog.Location.X - diff, dialog.Location.Y);
    13. }
    14. dialog.Show();


    Im Vollbild funktioniert das zwar, allerdings nicht im Nicht-Vollbild.

    Was mache ich falsch?

    Um Euch das Hilfestellung-Geben zu vereinfachen, habe ich das Demo-Projekt angehangen ;)


    Danke für Eure Hilfe!
    Dateien
    • MenuBar.zip

      (20,16 kB, 43 mal heruntergeladen, zuletzt: )

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

    @TRiViUM Machst Du aus this.Right ein this.Width.
    Ggf brauchst Du noch eine kleine System-abhängige Korrektur.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @TRiViUM Das sind die Standard-Breiten der Ränder einer Form in verschiedenen Betriebssystemen.
    Gugst Du SystemInformation wenn Du kannst unter verschiedenen Betriebssystemen.
    learn.microsoft.com/de-de/dotn…n?view=windowsdesktop-7.0
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @RodFromGermany Danke für diese Info, die Klasse SystemInformation kannte ich bislang noch nicht :whistling:

    Ich habe mit folgenden Variablen etwas herumgespielt:
    - SystemInformation.BorderStyle
    - SystemInformation.BorderMultiplierFactor
    - SystemInformation.Border3DSize (wobei meine Form auf FormBorderStyle = Sizable steht)

    Leider bekomme ich den überstehenden Rand nicht "sauber" wegoptimiert, ohne jetzt z.B. immer fix noch 3 Pixel abzuziehen :huh:

    TRiViUM schrieb:

    ohne jetzt z.B. immer fix noch 3 Pixel abzuziehen
    Vergleiche mal die Form-Breite im Designer mit der Breite eines Screenshots dieser Form im IrfanView.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    RodFromGermany schrieb:

    Vergleiche mal die Form-Breite

    Fensterbreite im Designer: 531 Pixel.
    Fensterbreite zur Laufzeit: 517 Pixel.

    Im Designer ist die Rahmen-Breite optisch mit der aus Windows-7 gleichzusetzen würde ich sagen (8 Pixel).
    Ich nutze Windows 11, da ist die Rahmen-Breite zur Laufzeit dann nur 1 Pixel.
    Evtl. hat es damit auch noch was zu tun?!

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

    TRiViUM schrieb:

    Evtl. hat es damit auch noch was zu tun?!
    Konkret, nicht eventuell.
    Du musst die Designer-Breite abziehen und die SystemInformation-Breite addieren (oder anders herum).
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Also PointToScreen gibt dir einen Punkt im ClientRectangle so geändert zurück, das du den Punkt auf dem Screen hast. Gibst du einfach einfach einen Point.Empty(entspricht x = 0, Y = 0), bekommst du folglich die Position des ClientRectangles auf dem Screen, gibst du da dort die Location vom Item3 auf dem oberen Panel bzw. was das ist, hast du dessen koordinaten, dann kannste das menu auch passend linksbündig positionieren. Daraus machst du dann sowas:

    Du kannst aber auch mit AdjustWindowRect was machen(nicht vom Namen irritieren lassen), da kannste RECT-Strukuren ändern lassen, dazu gibst du an, ob das Fenster über ein Menu verfügt, gibst dazu auch noch den Style an, dann kann man alles berechnen anhand des Unterschiedes.

    Aber so wie folgt brauchste keine WinAPI.

    C#-Quellcode

    1. namespace WinFormsApp1
    2. {
    3. public partial class Form1 : Form
    4. {
    5. public Form1()
    6. {
    7. InitializeComponent();
    8. }
    9. Form f = new Form();
    10. private void Form1_Load(object sender, EventArgs e)
    11. {
    12. f.BackColor = SystemColors.ControlDarkDark;
    13. f.FormBorderStyle = FormBorderStyle.None;
    14. f.TopMost = true;
    15. f.Show();
    16. UpdateFormLocation();
    17. }
    18. void UpdateFormLocation()
    19. {
    20. Point p1 = PointToScreen(Point.Empty);
    21. f.Location = new Point(p1.X - f.Width + ClientRectangle.Width - 1, p1.Y + 1);
    22. }
    23. private void Form1_Move(object sender, EventArgs e)
    24. {
    25. UpdateFormLocation();
    26. }
    27. }
    28. }


    Das andere Form ist dann immer 1 Pixel tiefer als das ClientRect beginnt, die Rechte Seite des Forms 1 Pixel vorm Ende des CleintRectangles. Hab den Pixel reingemacht, damit man das deutlich sieht.
    Bilder
    • Unbenannt.png

      1,81 kB, 404×417, 38 mal angesehen
    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D

    Dieser Beitrag wurde bereits 6 mal editiert, zuletzt von „DTF“ ()

    Genau das ist es ja. Da man die Größe des ClientRectangles kennt, braucht man dessen Position auf dem Schirm. Achja, falls du Positionen von Controls verwenden willst, z.B. button1.PointToScreen(Point.Empty);, habs nicht im Kopf in welcher Klasse diese Funktion steckt, aber sollten alle Controls innehaben. Die Funktionen PointToClient und PointToScreen sind quasi "übersetzer" zwischen globaler und lokaler Position(auf ClientRectangle bezogen).
    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D