如何使用 python PyQt5 确定我的应用程序(窗口)的活动屏幕(监视器)?

Roh*_*Sai 9 python user-interface resolution pyqt5 pythoninterpreter

我正在开发一个使用许多小部件(QGroupBox、QVBoxLayout、QHBoxLayout)的应用程序。最初它是在普通的高清显示器上开发的。但是,最近我们中的许多人升级到了 4K 分辨率的显示器。现在一些按钮和滑块被压缩得非常小以至于无法使用。

现在我尝试进行一些更改,以便该应用程序可以与 HD 和 4K 显示器一起使用。

我开始阅读以下链接:

https://leomoon.com/journal/python/high-dpi-scaling-in-pyqt5/在此处输入链接描述

我想每当我的窗口在特定监视器中打开时,我都可以调用以下代码:

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)
Run Code Online (Sandbox Code Playgroud)

然后我尝试使用以下代码获取显示器分辨率(pixel_x 和 pixel_y),使用相关帖子here

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)]
Run Code Online (Sandbox Code Playgroud)

screen_width = 0, screen_height = 1给了我主显示器的分辨率(在我们的案例中主要是笔记本电脑,它们是高清的)。screen_width = 78, screen_height = 79给了我虚拟机的组合分辨率。但我不明白如何根据我的应用程序打开的位置动态获取这些值。

我的应用程序窗口的开发方式是,它将在上次关闭的同一监视器中打开。现在的问题是,每当我的 GUI 被调用并适应该分辨率时,我都想获得活动监视器分辨率。如果有人可以帮助我,我会很高兴。

我很想知道每次将窗口从高清显示器拖动到 4K 显示器时是否可以调用屏幕分辨率计算,反之亦然。

编辑:我在这里的这篇文章中发现了类似的东西,但我无法从中得到太多。

Edit2:基于@Joe 解决方案,主屏幕检测,为什么我的主屏幕始终是我的笔记本电脑分辨率,即使我在 4K 屏幕上运行应用程序? 在此处输入图片说明

我只是尝试使用以下代码获取所有屏幕的 dpi:

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
Run Code Online (Sandbox Code Playgroud)

Joe*_*Joe 6

我来到了一个解决方案跨越是使用一个临时的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 ...
Run Code Online (Sandbox Code Playgroud)

此功能将检测所有附加的屏幕:

# 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
Run Code Online (Sandbox Code Playgroud)

您可以使用此处此处的提示来获取运行应用程序的屏幕。

但我认为primaryScreen也应该返回这个:

主屏幕:QScreen* const

此属性保存应用程序的主(或默认)屏幕。

除非另有说明,这将是最初显示 QWindows 的屏幕。

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


Tim*_*ner 4

好吧,创建 MainWindow 之后,您可以调用QMainWindow.screen()。这将返回主窗口所在的当前屏幕。这至少允许您在应用程序启动时检查屏幕分辨率。现在还没有 screenChangeEvent 这样的东西。不过,我确信您可以通过子类化 MainWindow 并重载来创建一个QMainWindow.moveEvent

例如:

    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)
Run Code Online (Sandbox Code Playgroud)

这会检查屏幕是否已更改。如果有,它会发出信号。现在您只需将此信号连接到设置 dpi 属性的函数即可。该活动使您可以访问旧屏幕和新屏幕。

警告:

其中一个屏幕可以位于应用程序的开始处,因为当您第一次启动应用程序时None没有屏幕。oldScreen所以请检查一下。