web-dev-qa-db-ja.com

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

多くのウィジェット(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)

次に、関連する投稿 here を使用して、以下のコードを使用してモニターの解像度(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モニターにドラッグしたり、その逆を行ったりするたびに、画面解像度の計算を呼び出すことができるかどうか知りたいです。

編集:この投稿で似たようなものを見つけました here しかし、これから多くを得ることができませんでした。

Edit2:@Joeソリューションのプライマリ画面検出に基づいて、4K画面でアプリケーションを実行しているのに、なぜプライマリ画面が常に私のラップトップの解像度であるのですか? enter image description here

以下のコードを使用して、すべての画面の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
8
Rohithsai Sai

まあ、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になることがあります。ぜひチェックしてみてください。

3
Tim Körner

私が来た1つの解決策 across は、一時的な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

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

しかし、primaryScreenもこれを返すはずだと思います。

primaryScreen:QScreen * const

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

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

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

6
Joe

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

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

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つの関数でアプリケーション(ウィンドウ)の位置を追跡でき、ウィンドウ間でドラッグされたときにも追跡できます。

3
Rohithsai Sai