Wie bestimme ich mit Python PyQt5 einen aktiven Bildschirm (Monitor) meiner Anwendung (Fenster)?

8

Ich arbeite an einer Anwendung, die viele Widgets verwendet (QGroupBox, QVBoxLayout, QHBoxLayout). Ursprünglich wurde es auf normalen HD-Monitoren entwickelt. Vor kurzem haben viele von uns ein Upgrade auf Monitore mit 4K-Auflösung durchgeführt. Jetzt sind einige der Schaltflächen und Schieberegler so klein komprimiert, dass sie unbrauchbar werden.

Jetzt habe ich versucht, einige Änderungen vorzunehmen, damit die Anwendung sowohl mit HD- als auch mit 4K-Monitoren verwendet werden kann.

Ich fing an, den folgenden Link zu lesen:

https://leomoon.com/journal/python/high-dpi-scaling-in-pyqt5/ Geben Sie hier die Linkbeschreibung ein

Ich dachte, wann immer mein Fenster in einem bestimmten Monitor geöffnet wird, kann ich den folgenden Code aufrufen:

if pixel_x > 1920 and pixel_y > 1080:
  Qapp.setAttribute(Qt.AA_EnableHighDpiScaling, True)
  Qapp.setAttribute(Qt.AA_UseHighDpiPixmaps, True)
else:
  Qapp.setAttribute(Qt.AA_EnableHighDpiScaling, False)
  Qapp.setAttribute(Qt.AA_UseHighDpiPixmaps, False)

Dann habe ich versucht, die Monitorauflösung (pixel_x und pixel_y) mithilfe des folgenden Codes zu ermitteln, indem ich hier einen verwandten Beitrag verwendet habe .

import sys, ctypes

user32 = ctypes.windll.user32
user32.SetProcessDPIAware()
screen_width  = 0 #78
screen_height = 1 #79
[pixel_x , pixel_y ] = [user32.GetSystemMetrics(screen_width), user32.GetSystemMetrics(screen_height)]

screen_width = 0, screen_height = 1 gibt mir die Auflösung meines primären Monitors (meistens Laptops in unserem Fall, die HD sind). screen_width = 78, screen_height = 79gibt mir die kombinierte Auflösung von virtuellen Maschinen. Ich verstehe jedoch nicht, wie ich diese Werte dynamisch abrufen kann, je nachdem, wo meine Anwendung geöffnet wurde.

Mein Anwendungsfenster ist so entwickelt, dass es auf demselben Monitor geöffnet wird, auf dem es zuletzt geschlossen wurde. Das Problem ist jetzt, dass ich die aktive Monitorauflösung erhalten möchte, wenn meine GUI aufgerufen wird, und mich an diese Auflösung anpassen möchte. Ich würde mich freuen, wenn mir jemand helfen kann.

Ich bin interessiert zu wissen, ob ich die Berechnung der Bildschirmauflösung jedes Mal aufrufen kann, wenn ich mein Fenster von einem HD-Monitor auf einen 4K-Monitor ziehe und umgekehrt.

Edit: Ich habe in diesem Beitrag hier etwas Ähnliches gefunden aber ich konnte nicht viel davon bekommen.

Edit2: Basierend auf der @ Joe-Lösung, Primary Screen Detection, Warum ist mein primärer Bildschirm immer meine Laptop-Auflösung, obwohl ich die Anwendung auf einem 4K-Bildschirm ausführe? Geben Sie hier die Bildbeschreibung ein

Ich habe gerade versucht, die dpi aller Bildschirme mit dem folgenden Code zu erhalten:

def screen_selection():
  app = QApplication(sys.argv)
  valid_screens = []
  for index, screen_no in enumerate(app.screens()):
    screen = app.screens()[index]
    dpi = screen.physicalDotsPerInch()
    valid_screens.append(dpi)
  return valid_screens
Rohithsai Sai
quelle

Antworten:

3

Nun, nachdem Sie das MainWindow erstellt haben, können Sie einfach QMainWindow.screen () aufrufen . Dies gibt den aktuellen Bildschirm zurück, auf dem sich das MainWindow befindet. Auf diese Weise können Sie zumindest die Bildschirmauflösung zu Beginn Ihrer Anwendung überprüfen. Derzeit gibt es kein screenChangeEvent. Ich bin jedoch sicher, dass Sie eine erstellen können, indem Sie das MainWindow unterordnen und das überladenQMainWindow.moveEvent

Zum Beispiel:

    class MainWindow(QtWidgets.QMainWindow):
        screenChanged = QtCore.pyqtSignal(QtGui.QScreen, QtGui.QScreen)

        def moveEvent(self, event):
            oldScreen = QtWidgets.QApplication.screenAt(event.oldPos())
            newScreen = QtWidgets.QApplication.screenAt(event.pos())

            if not oldScreen == newScreen:
                self.screenChanged.emit(oldScreen, newScreen)

            return super().moveEvent(event)

Dies prüft, ob sich der Bildschirm geändert hat. Wenn es hat, gibt es ein Signal aus. Jetzt müssen Sie dieses Signal nur noch mit einer Funktion verbinden, die Ihre dpi-Attribute festlegt. Das Ereignis gibt Ihnen Zugriff auf den alten und den neuen Bildschirm.

Warnung:

Einer der Bildschirme kann sich Noneam Anfang Ihrer Anwendung befinden, da oldScreenbeim ersten Start Ihrer Anwendung keine angezeigt wird . Bitte überprüfen Sie dies.

Tim Körner
quelle
Körnet bedankt sich für die Lösung. Es gibt jedoch keine Methode namens QMainWindow.screen () in PyQt5, zumindest nicht das, was ich verstanden habe. Wenn ich falsch liege, zeige mir bitte einen Link für Python (PyQt5)
Rohithsai Sai
Ich konnte es auch nicht in der Dokumentation finden. Wie QWidgetSie hier sehen können, unterstützt jedoch jeder diese Methode . QMainWindowUnterklassen QWidget.Ich habe auch meinen Code getestet und es hat funktioniert. Bitte überprüfen Sie nur, ob es auch für Sie funktioniert.
Tim Körner
Ich würde auch empfehlen, die Lösung mit Unterklassen QMainWindowund Überladen der zu verwenden moveEvent. Dies funktioniert zu 100% und bietet Ihnen mehr Funktionalität. Sie können einfach den von mir bereitgestellten Code nehmen und verwenden. Der Code funktioniert einwandfrei und ich erhalte das richtige screenChangedSignal, wenn ich das `` MainWindow` auf einem anderen Bildschirm bewege.
Tim Körner
Ich bin interessiert zu wissen, wie Sie gesagt haben, getestet und gearbeitet. Erstens, wenn ich QMainWindow.screen () verwende, wird ein Fehler ausgegeben, der besagt, dass es kein Attribut hat. Zweitens hat 'moveAppvent' für moveEvent, das einen Fehler erhält, kein Attribut 'screenAt'. Ich möchte verstehen, ob Sie in Python implementiert haben.
Rohithsai Sai
Ja natürlich benutze ich Python. Meine PyQt5Version ist 5.13.2. Sie können hier sehen, dass die offizielle PyQt5-Referenz auch die QApplication.screenAtMethode auflistet .
Tim Körner
6

Eine Lösung kam ich über ist eine vorübergehende zu verwenden QApplication():

import sys
from PyQt5 import QtWidgets, QtCore, QtGui

# fire up a temporary QApplication
def get_resolution():

    app = QtWidgets.QApplication(sys.argv)

    print(app.primaryScreen())

    d = app.desktop()

    print(d.screenGeometry())
    print(d.availableGeometry())
    print(d.screenCount())    

    g = d.screenGeometry()
    return (g.width(), g.height())

x, y = get_resolution()

if x > 1920 and y > 1080:
  QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling, True)
  QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_UseHighDpiPixmaps, True)
else:
  QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling, False)
  QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_UseHighDpiPixmaps, False)

# Now your code ...

Diese Funktion erkennt alle angehängten Bildschirme:

# fire up a temporary QApplication
def get_resolution_multiple_screens():

    app = QtGui.QGuiApplication(sys.argv)
    #QtWidgets.QtGui
    all_screens = app.screens()

    for s in all_screens:

        print()
        print(s.name())
        print(s.availableGeometry())
        print(s.availableGeometry().width())
        print(s.availableGeometry().height())
        print(s.size())
        print(s.size().width())
        print(s.size().height())

    print()
    print('primary:', app.primaryScreen())
    print('primary:', app.primaryScreen().availableGeometry().width())
    print('primary:', app.primaryScreen().availableGeometry().height())

    # now choose one

Sie können die Hinweise hier und hier verwenden , um den Bildschirm zu erhalten, auf dem die Anwendung ausgeführt wird.

Aber ich denke, primaryScreensollte auch dies zurückgeben:

primaryScreen: QScreen * const

Diese Eigenschaft enthält den primären (oder Standard-) Bildschirm der Anwendung.

Dies ist der Bildschirm, auf dem QWindows zunächst angezeigt werden, sofern nicht anders angegeben.

( https://doc.qt.io/qt-5/qguiapplication.html#primaryScreen-prop )

Joe
quelle
Danke für die Antwort. Leider funktioniert das nicht. Ich habe versucht, die obige Funktion in Spyder IDE zu implementieren. Ich führe die Anwendung auf einem 4K-Monitor aus, aber sie gibt trotzdem meine Laptop-Auflösungen zurück.
Rohithsai Sai
Wurde der 4K als zweiter Bildschirm an den Laptop angeschlossen?
Joe
Ja, und meine aktive Anwendung wird im 4K-Monitor geöffnet
Rohithsai Sai
Bitte versuchen Sie die andere Funktion, die ich angehängt habe. Überprüfen Sie auch app.primaryScreen(), welcher Bildschirm verwendet wird.
Joe
1
Links zu meiner Antwort hinzugefügt
Joe
3

Obwohl ich nicht die direkte Lösung finden konnte, kann ich eine Methode entwickeln, um das zu bekommen, wonach ich gesucht habe. Mit Hilfe von wenigen Links und vorherigem Beitrag kann ich erreichen. Mit diesem Beitrag kam mir die Idee, das Mausereignis zu verfolgen.

Ich habe eine Methode entwickelt, um alle Monitore und die jeweiligen Blickpositionen zu verfolgen. Wenn meine Variablennamen nicht angemessen sind, akzeptiere ich die Änderungen gerne

def get_screen_resolution():
  app = QApplication(sys.argv)
  screen_count = QGuiApplication.screens()
  resolutions_in_x = []

  for index, screen_names in enumerate(screen_count):
    resolution = screen_count[index].size()
    height = resolution.height()
    width = resolution.width()
    resolutions_in_x.append(width)

  low_resolution_monitors = {}
  high_resolution_monitors = {}

  for i, wid_res in enumerate(resolutions_in_x):
    if wid_res > 1920:
      high_resolution_monitors.update({i: wid_res})
    else:
      low_resolution_monitors.update({'L': wid_res})    
  temp_value = 0
  high_res_monitors_x_position = []
  low_res_monitors_x_position = []
  for i in range(len(screen_count)):
    temp_value = temp_value+resolutions_in_x[i]
      if resolutions_in_x[i] in high_resolution_monitors.values():
        high_res_monitors_x_position.append(temp_value-resolutions_in_x[i])
      else:
        low_res_monitors_x_position.append(temp_value-resolutions_in_x[i])

  total_width_res = []
  pixel_value = 0
  first_pixel = 0
  for i, wid_value in enumerate(resolutions_in_x):
    pixel_value = pixel_value + wid_value
    total_width_res.append(tuple((first_pixel, pixel_value-1)))
    first_pixel = pixel_value

  return high_res_monitors_x_position, low_res_monitors_x_position, total_width_res


def moveEvent(self, event):

screen_pos = self.pos()
screen_dimensions = [screen_pos.x(),screen_pos.y()]
super(MainWindow, self).moveEvent(event)

Window_starting_pt = screen_pos.x()
for i, value in enumerate(self.total_width_res):
  if value[0]<=Window_starting_pt+30 <=value[1] or value[0]<=Window_starting_pt-30 <=value[1]: #taking 30pixels as tolerance since widgets are staring at some negative pixel values
    if value[0] in self.high_res_monitors_x_position:
      QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling, True)
      QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_UseHighDpiPixmaps, True)
    else:
      QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling, False)
      QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_UseHighDpiPixmaps, False)

Mit aboe können zwei Funktionen die Position meiner Anwendung (Fenster) verfolgen und auch, wann immer sie zwischen Fenstern gezogen wird

Rohithsai Sai
quelle