Làm cách nào để xác định màn hình hoạt động (màn hình) của Ứng dụng (cửa sổ) bằng python PyQt5?


8

Tôi đang làm việc trên một ứng dụng đang sử dụng nhiều widget (QgroupBox, QVBoxLayout, QHBoxLayout). Ban đầu nó được phát triển trên màn hình HD bình thường. Nhưng, gần đây nhiều người trong chúng ta đã nâng cấp lên màn hình độ phân giải 4K. Bây giờ một số nút và thanh trượt được nén nhỏ đến mức không thể sử dụng được.

Bây giờ tôi đã cố gắng thực hiện một số thay đổi để ứng dụng có thể được sử dụng với cả màn hình HD và 4K.

Tôi bắt đầu đọc liên kết dưới đây:

https://leomoon.com/journal/python/high-dpi-scaling-in-pyqt5/ nhập mô tả liên kết tại đây

Tôi nghĩ bất cứ khi nào cửa sổ của tôi được mở trong một màn hình cụ thể, tôi có thể gọi mã sau đây:

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)

Sau đó, tôi đã cố gắng để có được độ phân giải màn hình (pixel_x và pixel_y) bằng cách sử dụng mã dưới đây từ việc sử dụng bài đăng liên quan ở đâ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 = 1cung cấp cho tôi độ phân giải của màn hình chính của tôi (chủ yếu là máy tính xách tay trong trường hợp của chúng tôi là HD). screen_width = 78, screen_height = 79cho tôi độ phân giải kết hợp của máy ảo. Nhưng tôi không hiểu làm thế nào tôi có thể tự động nhận được các giá trị này tùy thuộc vào nơi ứng dụng của tôi mở.

Cửa sổ ứng dụng của tôi được phát triển theo cách nó sẽ mở trong cùng một màn hình nơi nó được đóng lần trước. Vấn đề là bây giờ tôi muốn có được độ phân giải màn hình hoạt động bất cứ khi nào GUI của tôi được gọi và thích ứng với độ phân giải đó. Tôi sẽ rất vui nếu ai đó có thể giúp tôi.

Tôi muốn biết liệu tôi có thể gọi phép tính độ phân giải màn hình mỗi lần tôi kéo cửa sổ của mình từ màn hình HD sang màn hình 4K và ngược lại.

Chỉnh sửa: Tôi đã tìm thấy một cái gì đó tương tự trong bài viết này ở đây Nhưng tôi không thể nhận được nhiều từ này.

Edit2: Dựa trên giải pháp @Joe, Phát hiện màn hình chính, Tại sao màn hình chính của tôi luôn là độ phân giải máy tính xách tay của tôi mặc dù tôi chạy ứng dụng trên màn hình 4K? nhập mô tả hình ảnh ở đây

Tôi chỉ cố gắng để có được dpi của tất cả các màn hình bằng cách sử dụng mã dưới đây:

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

Câu trả lời:


3

Chà, sau khi tạo MainWindow, bạn có thể gọi QMainWindow.screen () . Điều này trả về màn hình hiện tại MainWindow đang bật. Điều này ít nhất sẽ cho phép bạn kiểm tra độ phân giải màn hình khi bắt đầu ứng dụng. Ngay bây giờ không có thứ gọi là screenChangeEvent. Tuy nhiên tôi chắc chắn rằng bạn có thể tạo một cái bằng cách phân lớp MainWindow và nạp chồngQMainWindow.moveEvent

Ví dụ:

    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)

Điều này kiểm tra nếu màn hình đã thay đổi. Nếu nó có nó phát ra một tín hiệu. Bây giờ bạn chỉ cần kết nối tín hiệu này với một hàm đặt các thuộc tính dpi của bạn. Sự kiện này cho phép bạn truy cập vào màn hình cũ và màn hình mới.

Cảnh báo:

Một trong những màn hình có thể Noneở đầu ứng dụng của bạn vì không có oldScreenkhi bạn khởi động ứng dụng lần đầu tiên. Vì vậy, vui lòng kiểm tra điều này.


Körnet cảm ơn bạn cho giải pháp. Nhưng, không có phương pháp nào gọi là QMainWindow.screen () trong PyQt5 ít nhất là những gì tôi đã hiểu. Nếu sai xin vui lòng cho tôi xem một số liên kết cho python (PyQt5)
Rohithsai Sai

Tôi cũng không thể tìm thấy nó trong tài liệu. Tuy nhiên mọi QWidgethỗ trợ phương pháp này như bạn có thể thấy ở đây . QMainWindowcác lớp con QWidget.Tôi cũng đã kiểm tra mã của mình và nó đã hoạt động. Xin vui lòng chỉ kiểm tra nếu nó làm việc cho bạn là tốt.
Tim Korner

Tôi cũng sẽ khuyên bạn nên sử dụng giải pháp với phân lớp QMainWindowvà quá tải moveEvent. Điều này hoạt động 100% và cung cấp nhiều chức năng hơn cho bạn. Bạn chỉ có thể lấy mã tôi cung cấp và sử dụng nó. Đoạn mã hoạt động tốt và tôi nhận được screenChangedtín hiệu chính xác mỗi khi tôi di chuyển `` MainWindow` trên một màn hình khác.
Tim Korner

Tôi can thiệp để biết bạn nói đã thử nghiệm và làm việc như thế nào. Đầu tiên khi tôi sử dụng QMainWindow.screen () nó sẽ báo lỗi rằng nó không có thuộc tính. Thứ hai, đối với moveEvent nhận được lỗi 'QApplication' không có thuộc tính 'screenAt'. Tôi muốn hiểu nếu bạn đã bắt chước trong Python.
Rohithsai Sai

Vâng tất nhiên tôi đang sử dụng python. PyQt5Phiên bản của tôi là 5.13.2 Bạn có thể thấy ngay tại đây rằng tham chiếu PyQt5 chính thức cũng liệt kê QApplication.screenAtphương thức.
Tim Korner

6

Một giải pháp tôi đã gặp là sử dụng tạm thời 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 ...

Chức năng này sẽ phát hiện tất cả các màn hình đính kèm:

# 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

Bạn có thể sử dụng các gợi ý ở đâyđây để có được màn hình nơi ứng dụng đang chạy.

Nhưng tôi nghĩ primaryScreencũng nên trả lại cái này:

sơ cấp: QScreen * const

Thuộc tính này giữ màn hình chính (hoặc mặc định) của ứng dụng.

Đây sẽ là màn hình nơi QWindows ban đầu được hiển thị, trừ khi có quy định khác.

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


Cảm ơn câu trả lời. Thật không may, điều này không làm việc. Tôi đã cố gắng thực hiện chức năng trên trong Spyder IDE. Tôi chạy ứng dụng trong màn hình 4K nhưng nó vẫn trả về độ phân giải máy tính xách tay của tôi.
Rohithsai Sai

4K có được gắn vào máy tính xách tay như màn hình thứ hai không?
Joe

có và ứng dụng đang hoạt động của tôi được mở trong màn hình 4K
Rohithsai Sai

Vui lòng thử chức năng khác tôi đính kèm. Ngoài ra kiểm tra app.primaryScreen()để xem màn hình nào được sử dụng.
Joe

1
thêm liên kết vào câu trả lời của tôi
Joe

3

Mặc dù tôi không thể có được giải pháp trực tiếp nhưng tôi có thể phát triển một phương pháp để có được những gì tôi đang tìm kiếm. Với sự giúp đỡ của một vài liên kết và bài viết trước tôi có thể đạt được. với bài đăng này, tôi có một ý tưởng theo dõi sự kiện chuột.

Tôi đã phát triển một phương pháp để theo dõi tất cả các màn hình và vị trí nhìn chằm chằm tương ứng. nếu việc đặt tên biến của tôi không phù hợp, tôi rất vui lòng chấp nhận các thay đổi

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)

Với aboe, hai chức năng có thể theo dõi vị trí ứng dụng (cửa sổ) của tôi và cũng có thể theo dõi khi nào nó được kéo giữa các cửa sổ

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.