pythonuser-interfacepyqt5resolutionpythoninterpreter

How to determine an active screen (monitor) of my Application (window) using python PyQt5?


I am working on an application which is using many widgets (QGroupBox, QVBoxLayout, QHBoxLayout). Initially it was developed on normal HD monitors. But, recently many of us upgraded to 4K resolution monitors. Now some of the buttons and sliders are compressed so small that they are unusable.

Now I tried to make some changes so that the application can be used with both HD and 4K monitors.

I started reading the link below:

https://leomoon.com/journal/python/high-dpi-scaling-in-pyqt5/enter link description here

I thought whenever my window is opened in a particular monitor I can call the following code:

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)

Then I tried to get the monitor resolution (pixel_x and pixel_y) using below code from using related post 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)]

screen_width = 0, screen_height = 1 gives me the resolution of my primary monitor(mostly laptops in our case which are HD). screen_width = 78, screen_height = 79 gives me the combined resolution of virtual machines. But I do not understand how I can dynamically get these values depending upon where my application opened.

My application window is developed in such a way that it will open in the same monitor where it was closed last time. The problem is now I want to get the active monitor resolution whenever my GUI is called and adapt to that resolution. I would be glad if someone can help me out.

I am interested to know if I can call the screen resolution calculation every time that I drag my window from an HD monitor to a 4K monitor and Vice versa.

Edit: I have found something similar in this post here But I could not get much from this.

Edit2: Based on @Joe solution, Primary Screen Detection, Why is my primary screen always my laptop resolution even though I run the application on a 4K screen? enter image description here

I just tried to get the dpi of all the screens using the code below:

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

Solution

  • Well, after creating the MainWindow, you can just call QMainWindow.screen(). This returns the current screen the MainWindow is on. This would at least allow you to check the screen resolution at the start of your application. Right now there is no such thing as a screenChangeEvent. However i am sure you can create one by subclassing the MainWindow and overloading the QMainWindow.moveEvent

    For example:

        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)
    

    This checks if the screen has changed. If it has it emits a signal. Now you only need to connect this signal to a function that sets your dpi attributes. The event gives you access to the old and to the new screen.

    Warning:

    One of the screen can be None at the start of your application because there is no oldScreen when you first start your application. So please check this.