Python PyQt5を使用してアプリケーション(ウィンドウ)のアクティブな画面(モニター)を確認する方法


8

多くのウィジェット(QGroupBox、QVBoxLayout、QHBoxLayout)を使用しているアプリケーションで作業しています。当初は通常のHDモニターで開発されました。しかし、最近私たちの多くは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)

次に、以下のコードを使用して、ここの関連する投稿を使用して、モニターの解像度(pixel_xおよびpixel_y)を取得しようとしました

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プライマリモニター(ほとんどの場合、ラップトップはHDです)の解像度を取得します。screen_width = 78, screen_height = 79仮想マシンを組み合わせた解像度を取得します。しかし、アプリケーションを開いた場所に応じて、これらの値を動的に取得する方法がわかりません。

私のアプリケーションウィンドウは、前回閉じたときと同じモニターで開くように開発されています。問題は、GUIが呼び出されるたびにアクティブなモニターの解像度を取得し、その解像度に適応させたいことです。誰かが私を助けてくれるとうれしいです。

ウィンドウをHDモニターから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

回答:


3

まあ、MainWindowを作成した後は、QMainWindow.screen()を呼び出すだけです。これにより、MainWindowが表示されている現在の画面が返されます。これにより、少なくともアプリケーションの開始時に画面解像度を確認できます。現在、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)

画面が変更されたかどうかを確認します。持っている場合は、シグナルを発信します。これで、この信号をdpi属性を設定する関数に接続するだけで済みます。このイベントでは、古い画面と新しい画面にアクセスできます。

警告:

最初にアプリケーションを開始するときNoneはないため、画面の1つをoldScreenアプリケーションの開始時に配置できます。ぜひチェックしてみてください。


ケルネットは解決策をありがとう。しかし、PyQt5には少なくとも私が理解したQMainWindow.screen()というメソッドはありません。午前間違っては親切に私のpythonのためのいくつかのリンク(PyQt5)を示している場合
Rohithsaiサイ

また、ドキュメントでそれを見つけることができませんでした。ただし、ここでQWidgetわかるように、すべてがこのメソッドをサポートしています。サブクラス私のコードもテストし、うまくいきました。それもあなたのために動作するかどうかを確認してください。QMainWindowQWidget.
TimKörner19年

また、をサブクラス化してQMainWindowをオーバーロードするソリューションを使用することをお勧めしmoveEventます。これは100%機能し、より多くの機能を提供します。私が提供したコードをそのまま使用できます。コードは正常に機能screenChangedし、「MainWindow」を別の画面に移動するたびに正しい信号が表示されます。
TimKörner19年

私はあなたがどのようにテストされ、働いたと言ったかを知るのに興味があります。まず、QMainWindow.screen()を使用すると、属性がないことを示すエラーがスローされます。次に、moveEventでエラーが発生した場合、「QApplication」には「screenAt」属性がありません。Pythonに習熟しているかどうかを知りたい。
Rohithsai Sai

はい、もちろんPythonを使用しています。私のPyQt5バージョンは、あなたが右に見ることができ5.13.2あり、ここで公式PyQt5の参照も示していますというQApplication.screenAt方法を。
TimKörner19年

6

私が遭遇した 1つの解決策は一時的なものを使用すること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 ...

この関数は、接続されているすべての画面を検出します。

# 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

ここここのヒントを使用して、アプリケーションが実行されている画面を取得できます。

しかし、私はprimaryScreenこれも返す必要があると思います:

primaryScreen:QScreen * const

このプロパティは、アプリケーションのプライマリ(またはデフォルト)画面を保持します。

特に指定がない限り、これはQWindowsが最初に表示される画面になります。

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


答えてくれてありがとう。残念ながら、これは機能していません。上記の機能をSpyder IDEに実装してみました。4Kモニターでアプリケーションを実行していますが、それでもラップトップの解像度が返されます。
Rohithsai Sai

4Kはラップトップにセカンドスクリーンとして接続されていましたか?
Joe

はい、私のアクティブなアプリケーションは4Kモニターで開かれています
Rohithsai Sai

付属している他の機能をお試しください。また、app.primaryScreen()使用されている画面を確認してください。
Joe

1
私の回答へのリンクを追加
Joe

3

直接的な解決策を得ることはできませんでしたが、私が探していたものを得る方法を開発することができました。いくつかのリンクと以前の投稿の助けを借りて、私は達成することができます。このポスト私はマウスイベントを追跡するのアイデアを得ました。

すべてのモニターとそれぞれの凝視位置を追跡する方法を開発しました。変数の名前が適切でない場合、変更を受け入れて喜んでいます

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)

aboeを使用すると、2つの関数でアプリケーション(ウィンドウ)の位置を追跡でき、ウィンドウ間でドラッグされたときにも追跡できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.