Multiple monitoring

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

hi
ich habe ein root-window und ein toplevel-window.
ich versuche nun, auszulesen, auf welchem monitor das root-window ist, um das toplevel-window immer auf dem
'nicht-root-window-monitor' anzuzeigen (möglichst auch, wenn man das root-window mit der maus auf einen anderen monitor schiebt).
Hier ist mein bisheriger code:

Code: Alles auswählen

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import os
import tkinter as tk
import win32api
import win32gui


class Multiple_Monitors:
    def __init__(self):
        self.get_MONITORDICT()

    @staticmethod
    def get_MONITORDICT():
        monitor_dict = {}
        monitors = win32api.EnumDisplayMonitors()
        for monitor_idx, monitor in enumerate(monitors):
            monitor_screen = win32api.GetMonitorInfo(monitors[monitor_idx][0])['Monitor']
            monitor_work = win32api.GetMonitorInfo(monitors[monitor_idx][0])['Work']
            monitor_flag = win32api.GetMonitorInfo(monitors[monitor_idx][0])['Flags']
            monitor_name = win32api.GetMonitorInfo(monitors[monitor_idx][0])['Device']
            monitor_dict[monitor_idx] = {'Monitor': monitor_screen,
                                         'Work': monitor_work,
                                         'Flag': monitor_flag,
                                         'Device': monitor_name
                                         }
        return monitor_dict

    @staticmethod
    def get_MONITORACTIVE():
        hwnd = win32gui.GetForegroundWindow()
        return hwnd


class Main(tk.Tk):

    def __init__(self
                 ):
        tk.Tk.__init__(self)
        self.title("Root")
        self.geometry('250x50+250+250')
        self.toplevel = None
        self.counter = 1  # Wenn 0, wechselt das Fenster erst beim zweiten Klick

    def main(self):
        tk.Button(self, text="Set Toplevel-Window", command=self.change_screen).pack()

    def set_toplevel(self):
        self.toplevel = tk.Toplevel(self)
        self.toplevel.title("Toplevel")
        self.toplevel.geometry('250x50+300+100')
        tk.Label(self.toplevel, text="Thank you!").pack()
        tk.Button(self.toplevel, text="Close", command=self.toplevel.destroy).pack()

    def change_screen(self):
        if self.toplevel is None:
            self.set_toplevel()
        else:
            self.toplevel.destroy()
            self.set_toplevel()

        multiple_monitors = Multiple_Monitors()
        monitor_dict = multiple_monitors.get_MONITORDICT()

        if self.counter == len(monitor_dict.items())-1:
            self.counter = 0
        else:
            self.counter += 1

        monitor_active = multiple_monitors.get_MONITORACTIVE()
        for key, value in monitor_dict[self.counter].items():
            if key == 'Work':
                win32gui.MoveWindow(monitor_active,
                                    value[0],                       # Position x
                                    value[1],                       # Position y
                                    self.winfo_rootx(),             # Fensterbreite
                                    75,                             # Fensterhöhe
                                    True                            # ??? (Funktioniert auch mit False)
                                    )


def main():
    root = Main()
    root.main()
    root.mainloop()


if __name__ == '__main__':
    main()
Schon das feststellen, auf welchem monitor sich gerade das root-window befindet, gelingt nicht :oops:
Kann mir bitte jmd unter die arme greifen?
__deets__
User
Beiträge: 14529
Registriert: Mittwoch 14. Oktober 2015, 14:29

Die Klasse Multiple_Monitors ist falsch benannt, und ueberfluessig - denn sie enthaelt nur statische Methoden. Sie ruft auch get_MONITORDICT (auch ganz grauslig benannt) einfach sinnlos zweimal auf. Und in dieser Methode rufst du win32api.GetMonitorInfo mehrmals auf, nur um dann jeweils einen Wert aus dem Ergebnis zu pulen, und den Rest wegzuwerfen. Was den Code repetitiv und ueberkompliziert macht. Warum merkst du dir nicht den Rueckgabewert, und holst die gewuenschten Werte einfach raus? Wobei sich die Frage stellt, welchen Vorteil bringt denn das vorgehen, eine Datenstruktur die ja schon geliefert wird, zu einer neuen Datenstruktur zu kuratieren, die einfach nur eine Teilmenge der Informationen enthaelt. Nimm doch gleich die Rueckgabe von GetMonitorInfo.

Und was hat GetForegroundWindow (das aktive Fenster) mit get_MONITORACTIVE zu tun? Das ist das Fenster, nicht der Monitor. Warum heisst das so?

Last but not least, und zu deiner eigentlichen Frage: MonitorFromWindow bekommt ein Window-Handle, und liefert den dazugehoerigen Monitor. Das musst du nutzen.
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

Irgendwie habe ich ein déjà vu: viewtopic.php?f=18&t=46440#p352387.
DMD-OS
User
Beiträge: 165
Registriert: Freitag 28. Dezember 2018, 13:52

Ich habe jetzt daran gearbeitet.
Habe jetzt das Problem, daß ich nicht so richtig mit <PyHANDLE:65586> <PyHANDLE:0> (0, 0, 1920, 1080)
umgehen kann. Generell geht die abfrage der 'all_monitors'-information wohl etwas schöner als ich es gemacht habe.
ich versuche jetzt mit dem ausgelesen aktuell monitor die gesamten infos zu dem monitor zu erhalten.

Code: Alles auswählen

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import tkinter as tk
from ctypes import windll
import win32api


class Main(tk.Tk):
    def __init__(self
                 ):
        tk.Tk.__init__(self)
        self.title("Root")
        self.geometry('250x50+250+250')

    def main(self):
        tk.Button(self, text="Set Toplevel-Window", command=self.change_screen).pack(fill=tk.BOTH, expand=True)

    @staticmethod
    def change_screen():
        window_id = windll.user32.GetForegroundWindow()
        # MONITOR_DEFAULTTONULL = 0
        # MONITOR_DEFAULTTOPRIMARY = 1
        # MONITOR_DEFAULTTONEAREST = 2
        id_of_window_monitor = windll.user32.MonitorFromWindow(window_id, 2)
        print(id_of_window_monitor)

	# Ab hier gehts auch besser, glaub i
        all_monitors = win32api.EnumDisplayMonitors()
        for monitor in all_monitors:
            if id_of_window_monitor in monitor:
                monitor_id, monitor_name, monitor_info = monitor
                print(monitor_id, monitor_name, monitor_info)
        print('---')


def main():
    root = Main()
    root.main()
    root.mainloop()


if __name__ == '__main__':
    main()
Kann man das besser abfragen z.b. irgendwie mit dem PyHANDLER?
__deets__
User
Beiträge: 14529
Registriert: Mittwoch 14. Oktober 2015, 14:29

Was heisst du weisst damit nichts anzufangen? Das handle sollte doch auch irgendwo in all_monitors auftauchen. Wie sehen denn die Ausgaben jeweils aus?
DMD-OS
User
Beiträge: 165
Registriert: Freitag 28. Dezember 2018, 13:52

ok, ich habe es hinbekommen.
ich lese aus, auf welchem monitor mein startfenster geöffnet wird und gebe den im dict vorherigen monitor aus.
heißt, wenn das hauptfenster auf dem monitor:
{'Monitor': (-1920, 0, 0, 1080), 'Work': (-1920, 0, 0, 1040), 'Flag': 0, 'Device': '\\\\.\\DISPLAY1'}
liegt, bekomme ich die ausgabe:
{'Monitor': (0, 0, 1920, 1080), 'Work': (0, 0, 1920, 1040), 'Flag': 1, 'Device': '\\\\.\\DISPLAY2'}
SEHR GUT!
Setze ich das hauptfenster auf den anderen monitor, ist die ausgabe entsprechend:
{'Monitor': (-1920, 0, 0, 1080), 'Work': (-1920, 0, 0, 1040), 'Flag': 0, 'Device': '\\\\.\\DISPLAY1'}
Das gesamte dict sieht so aus:

Code: Alles auswählen

{<PyHANDLE:131073>: {'Monitor': (-1920, 0, 0, 1080), 'Work': (-1920, 0, 0, 1040), 'Flag': 0, 'Device': '\\\\.\\DISPLAY1'}, <PyHANDLE:65588>: {'Monitor': (0, 0, 1920, 1080), 'Work': (0, 0, 1920, 1040), 'Flag': 1, 'Device': '\\\\.\\DISPLAY2'}}
jetzt möchte ich eine excel-datei öffnen, die auf dem jeweils ausgegebenen (freien) monitor angezeigt werden soll.
code-versuch:

Code: Alles auswählen

                            # Info zur Anzeige der Excel-Datei
print(excel_monitor_info)   # {'Monitor': (-1920, 0, 0, 1080), 'Work': (-1920, 0, 0, 1040), 'Flag': 0, 'Device': '\\\\.\\DISPLAY1'}
process_file = "file_path_to_excel_file.xlsx"
os.startfile(process_file)
# win32gui.MoveWindow(fenster_id,
#                     excel_monitor_info[0],  # Position x
#                      excel_monitor_info[1],  # Position y
#                      500],  # Fensterbreite
#                      500,  # Fensterhöhe
#                      True  # Fenster-Neuaufbau (Ja/Nein)
#                      )
wie kann man nun die id eines neu geöffnetes excel-file (os.startfile(process_file)) auslesen und an win32gui.MoveWindow übergeben???
Antworten