Toplevel eine andere Position zuweisen

Fragen zu Tkinter.
Antworten
DMD-OS
User
Beiträge: 165
Registriert: Freitag 28. Dezember 2018, 13:52

hi nochma
ich bin grad dabei einem Toplevel eine andere Position zuzuweisen.
Mein Toplevel sieht so aus:

Code: Alles auswählen

self.operate_outside = tk.Toplevel(self, highlightbackground=self.border_color, highlightcolor=self.border_color, highlightthickness=2, relief=tk.GROOVE)
self.operate_outside.geometry("%dx%d+%d+%d" % (1400, 150, 210, 265))
Soweit ist das richtig.
Jetzt möchte ich per Button das Toplevel auf eine andere Position eines zweiten Bildschirms setzen.
Heißt: Wenn ich den Button drück, wechselt die gesamte Programm-GUI auf einen zweiten Bildschirm. (Läuft)
Das Toplevel bleibt aber auf dem alten Bildschirm.
Das Toplevel versuche ich jetzt mit:

Code: Alles auswählen

    def set_monitor(self, _):
        if len(win32api.EnumDisplayMonitors()) > 1:
        #### Monitorwechsel funktioniert.
            for key, monitor in self.monitor_dict.items():
                if windll.user32.MonitorFromWindow(windll.user32.GetForegroundWindow(), 2) in monitor['Active']:
                    self.start = key
            if self.start != self.start_marker.get():
                self.start_marker.set(self.start)
                if self.start >= self.len_monitors:
                    self.actual_number = 0
                else:
                    self.actual_number = self.start + 1
            else:
                if self.actual_number == self.len_monitors:
                    self.actual_number = 0
                else:
                    self.actual_number += 1
            x_position, y_position, _, _ = self.monitor_dict[self.actual_number]['Work']
            win32gui.MoveWindow(win32gui.GetForegroundWindow(),
                                x_position,
                                y_position,
                                win32api.GetSystemMetrics(0),
                                win32api.GetSystemMetrics(1),
                                True
                                )
	###################################################
	> Hier funktioniert es nicht:
            x, y = x_position+self.operate_outside.winfo_rootx(), y_position+self.operate_outside.winfo_y()
            print(x, y)  # 2130 268
            self.operate_outside.configure(x_position=x, y_position=y)
Ich bekomme eine Fehlermeldung:

Code: Alles auswählen

2130 268
Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Program Files\Python37\lib\tkinter\__init__.py", line 1705, in __call__
    return self.func(*args)
  File "C:\Users\colling\Desktop\DM-Import_TEST\Frontend.py", line 437, in set_monitor
    self.operate_outside.configure(x_position=x, y_position=y)
  File "C:\Program Files\Python37\lib\tkinter\__init__.py", line 1485, in configure
    return self._configure('configure', cnf, kw)
  File "C:\Program Files\Python37\lib\tkinter\__init__.py", line 1476, in _configure
    self.tk.call(_flatten((self._w, cmd)) + self._options(cnf))
_tkinter.TclError: unknown option "-x_position"
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Woher hast du denn, das es x_position gibt?

Was dir bewusst sein muss: Tkinter ist nur eine duenne Schicht ueber Tcl/Tk. Es reicht Dinge nur durch. Wie hier. Du koenntest dein Argument auch schnibbelbirz nennen, und du wuerdest die gleiche Fehlermeldung bekommen.

Du musst also in der Dokumentation schauen, was es *wirklich* gibt.
DMD-OS
User
Beiträge: 165
Registriert: Freitag 28. Dezember 2018, 13:52

ich hab schon rausbekommen, daß ich mit .geometry nur innerhalb des bildschirms die position setzen kann.
da ich aber den bildschirm wechsel, ist die x-position unbekannt, da der monitor nicht so groß ist.
Damit müßte es aber gehn.

Code: Alles auswählen

            win32gui.MoveWindow(--PyHANDLE object of self.operate_outside--,
                                x_pos,
                                y_pos,
                                win32api.GetSystemMetrics(0),
                                win32api.GetSystemMetrics(1),
                                True
                                )
Kann mir jmd sagen, wie ich das PyHANDLE object von dem Toplevel-Widget self.operate_outside erhalte???
DMD-OS
User
Beiträge: 165
Registriert: Freitag 28. Dezember 2018, 13:52

hmmm, ist den die HWND die PyHANDLE objekt nummer?
Sind die beiden dieselben?
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ja.
DMD-OS
User
Beiträge: 165
Registriert: Freitag 28. Dezember 2018, 13:52

Das auskommentierte funktioniert.
Die gesamte GUI wechselt damit den Monitor.
Warum funktioniert das für das Toplevel nicht.
Die HWND erhalte ich mit self.operate_outside.winfo_id().

Code: Alles auswählen

            x_position, y_position, _, _ = self.monitor_dict[self.actual_number]['Work']
            # win32gui.MoveWindow(win32gui.GetForegroundWindow(),
            #                     x_position,
            #                     y_position,
            #                     win32api.GetSystemMetrics(0),
            #                     win32api.GetSystemMetrics(1),
            #                     True
            #                     )

            win32gui.MoveWindow(self.operate_outside.winfo_id(),  # HWND des Toplevels (also die ID)
                                x_position, # Position x des neuen Monitors
                                y_position, # Position y des neuen Monitors
                                self.operate_outside.winfo_width(),  # Breite des Toplevels
                                self.operate_outside.winfo_height(), # Höhe des Toplevels
                                True
                                )
Es passiert nichts, auch keine Fehlermeldung. Das Toplevel rührt sich nicht vom Fleck :(
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ich sehe nicht, wo du das - wie in den Links angegeben - in einen integer wandelst.

Und gibt die win32 Funktion kein rückgabewert Zurück, mit dem man mal arbeiten kann?
DMD-OS
User
Beiträge: 165
Registriert: Freitag 28. Dezember 2018, 13:52

Doch hier:

Code: Alles auswählen

print(type(self.operate_outside.winfo_id()), self.operate_outside.winfo_id())
<class 'int'> 394556
Ich hab das aber glaub ich nicht ganz verstanden.
In dem auskommentierten funktionierenden Teil ist der neue Monitor vorhanden.
Das was ich mich immer frage ist, wo steht das, was gewechselt werden soll?
Eigentlich müsste ich doch im funktionierden Teil die Angaben:
1. auf welchen Monitor soll gewechselt werden,
2. WELCHES WIDGET soll gewechselt werden, also die gesamte GUI (FEHLT DA ABER)
3. x_position,
4. y_position,
5. Widget-Breite,
6. Widget-Höhe

Mir fehlt im funktionierenden Teil (o.a.) die Angabe des Widgets, das gewechselt werden soll. Da steht nirgendwo, das die gesamte GUI gewechselt werden soll.
Nur win32gui.GetForegroundWindow(), der neue Monitor.
Im nicht funktionieren Teil seht hingegen, WELCHES WIDGET gewechselt werden soll, hier fehlt die Angabe des Monitors.
Schnall ich nicht :(
DMD-OS
User
Beiträge: 165
Registriert: Freitag 28. Dezember 2018, 13:52

PS: Ich kann mich leider erst morgen Abend wieder zurückmelden. :)
PEACE
Antworten