Seite 1 von 1

Multiple monitoring

Verfasst: Donnerstag 28. November 2019, 11:15
von DMD-OS
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?

Re: Multiple monitoring

Verfasst: Donnerstag 28. November 2019, 11:43
von __deets__
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.

Re: Multiple monitoring

Verfasst: Donnerstag 28. November 2019, 14:54
von Sirius3
Irgendwie habe ich ein déjà vu: viewtopic.php?f=18&t=46440#p352387.

Re: Multiple monitoring

Verfasst: Donnerstag 28. November 2019, 15:37
von DMD-OS
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?

Re: Multiple monitoring

Verfasst: Donnerstag 28. November 2019, 16:11
von __deets__
Was heisst du weisst damit nichts anzufangen? Das handle sollte doch auch irgendwo in all_monitors auftauchen. Wie sehen denn die Ausgaben jeweils aus?

Re: Multiple monitoring

Verfasst: Freitag 29. November 2019, 11:47
von DMD-OS
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???