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?
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
One solution I came across is to use a temporary 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 ...
This function will detect all attached screens:
# 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
You can use the hints here and here to get the screen where the application is running.
But I think primaryScreen
should also return this:
primaryScreen : QScreen* const
This property holds the primary (or default) screen of the application.
This will be the screen where QWindows are initially shown, unless otherwise specified.
(https://doc.qt.io/qt-5/qguiapplication.html#primaryScreen-prop)
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With