PyQt5 Resize app for different displays - python

I am using PyQt5 and Python 3.6.4 to design a ui for a program. It was made on a 720p monitor however now using the same code on a 4k monitor, everything is tiny apart from the text. How would I go about resizing the whole app to look the same on all monitors: (720p, 1080p, 4k, etc.)
The program is to be run on windows through an executable created through compiling the python code.
Cheers

Simple 1 line fix for any who need
os.environ["QT_AUTO_SCREEN_SCALE_FACTOR"] = "1"

This is somewhat system dependent, so it would help if you mentioned your target platform(s).
Because PyQt5 is just a wrapper around Qt5, I think High DPI Displays from the Qt manual applies. Citing the relevant bit (but you should read the whole thing):
In order to get an application designed for low DPI values running on a high resolution monitors quickly, consider one of the scaling options (let the application run as DPI Unaware on Windows or set the environment variable QT_AUTO_SCREEN_SCALE_FACTOR to "1". These options may incur some scaling or painting artifacts, though.
In the longer term, the application should be adapted to run unmodified:
Always use the qreal versions of the QPainter drawing API.
Size windows and dialogs in relation to the screen size.
Replace hard-coded sizes in layouts and drawing code by values calculated from font metrics or screen size.
In a shell, you would do something like:
$ export QT_AUTO_SCREEN_SCALE_FACTOR=1
$ python my_application.py

Related

HIGH DPI Tkinter re scaling when I run it in Spyder and when I run it direct in terminal

this is probably not much of a coding question.
I developed an application in Tkinter which consists pretty much in a canvas where I load images on (matplots).
When I run it from Spyder or Jupyter notebook I obtain 143 DPI and when I run it directly in terminal I obtain 95 DPI instead.
The most weird thing is that once I run it from terminal it shows as if it was a 143 DPI application but when I load the image the app decides to resize completely and then change the DPI of my screen. So the whole thing resizes, buttons, pop up boxes and etc...
It is very important to me that I can run it from terminal, because afterwards I will transform it into a .exe application.
My first approach was to use the tkinter method .winfo_fpixel() and try to ratio the DPIs and multiply it to every dimension in the application.
Later I tried to find python.exe and pythonw.exe in order to change the compatibility with HIGH DPI Scale.
Do you thing there is a way to solve this without resizing everything?
I would like to insist that I'm 100% sure this has nothing to do with the code, therefore I might not post any coding samples.
Thanks.
obs: I use Windows 10
ps: I tried to run the app with two screens, what happened was really funny, when I use it on an adequate screen it runs normally, but when I slide it to the other screen and make any action/event it will resize it automatically.
selbie's answer is correct.
Also,You could use winapi to set DPI aware in python directly(this could work in tkinter):
import ctypes, tkinter
try: # >= win 8.1
ctypes.windll.shcore.SetProcessDpiAwareness(2)
except: # win 8.0 or less
ctypes.windll.user32.SetProcessDPIAware()
root = tkinter.Tk()
....
MSDN doc: SetProcessDpiAwareness, MSDN doc: SetProcessDPIAware
And this is another answer which mentioned about DPI awareness.
DPI is largely influenced by your PC's resolution settings - specifically the setting on "Scale and layout". 100% is 96 DPI and 150% is 144 DPI. I'm guessing it's just a rounding error from your app that's showing 95 and 143. Laptops tend to have higher resolution screens, so OEM's default to >100% setting so that you don't have to squint to see your apps. Whereas, your typical 1080p display defaults to 100% DPI. But when you "remote desktop" into a PC, Windows may re-adapt and re-stretch the DPI settings to match the local display if its DPI and resolution are different.
Windows will auto-scale most applications that haven't explicitly set their "DPI awareness" with the OS. That's typically fine for most application (although they can appear "blurry"). Applications can be compiled to be dpi aware are not stretched except in certain multi-monitor situations. This is especially likely for graphics applications. And that's where bugs like the one you are seeing tend to show up. You can often change this behavior by right clicking on the EXE, clicking Properties, and finding the setting the compatibility tab:
The most weird thing is that once I run it from terminal it shows as if it was a 143 DPI application but when I load the image the app decides to resize completely and then change the DPI of my screen. So the whole thing resizes, buttons, pop up boxes and etc...
When you remoted into your PC, the system DPI changed. Applications can get confused - especially if they aren't adapting to a changing DPI setting. Or worse, the application registers with Windows that it is DPI aware, but doesn't handle the corner case of when the monitor is swapped out - which is effectively what happens when you remoted into it. You can however, override this behavior with some combination of the Properties dialog above and the available APIs to control dpi-awareness.
I don't much about TKinter (Does it use the Python process or is it its own exe?). If you can compile it yourself, you can use the various Windows APIs and manifest settings to get the DPI behavior you want. My shot in the dark guess is that TKinter( is declaring itself per-monitor dpi-aware, but has a bug that doesn't account for the DPI changing on the fly. Typical fix for this situation is to just restart the application.
Everything you need to know at the links below:
https://learn.microsoft.com/en-us/windows/desktop/hidpi/high-dpi-desktop-application-development-on-windows
https://learn.microsoft.com/en-us/windows/desktop/api/shellscalingapi/nf-shellscalingapi-setprocessdpiawareness
https://msdn.microsoft.com/en-us/C9488338-D863-45DF-B5CB-7ED9B869A5E2
You can also read my previous answers regarding DPI awareness in Windows apps:
https://stackoverflow.com/search?q=user%3A104458+dpi

appearance of my GUI in several OS

I would like to check the appearance of my GUI while coding, for several OS where it should be distributed.
How can I do ?
The problem is that the ‘previsualisation’ proposed by QT Designer is very different from the appearance of the distributed release. I even have spots in tabs that appear with same font and size in ‘previsualisation’ but have different sizes on Windows... I work with: python 3.5, a GUI designed with QT Designer, developed on mac OS 10.11 and shared with Windows 7 and Windows 10 systems (installed with a recent pyinstaller)
The preview uses some approximation of the final style drawn completely by Qt, but the style used "for real" in most platform plug-ins either employs real, native widgets, or emulates them asking for theme parts straight from the machine where it's running. So, it's not possible to have a completely faithful preview unless you use a style that is always drawn completely by Qt (such as Fusion).
Long story short: to see how your application will really look on different platforms you'll have to test it "for real".
ok. For the moment, I developed a ui file for each OS and test the appearance "for real". That's awkward and, moreover, in a given ui file, some strings that have exactly the same apparent properties in Qt Designer may appear differently in the final release

Writing To The Framebuffer on macOS

I would like to recreate the programs shown in this article on a Mac. Is this possible? My research so far has pointed to "no" but I don't want to give up just yet. Python is preferred but my purpose for this is simple enough that most any language is fine.
Edit: To elaborate on my goal, it is to write individual pixels to the screen with no background. I don't care if they're removed by mouse movements, and if there is a better way to do this than framebuffers I will use that.
Unfortunately, the MacOS kernel doesn't expose a file to access the framebuffer (such as /dev/fb0 on Linux).
There could be a way to do this using the MacOS APIs. In 2004 the DirectFB project had this working (here's the commit that added it: https://github.com/DirectFB/directfb/commit/cbe9cfd0446bfa8c6fcd18b7cbc805566eec9b5d#diff-250fcad7219dfcf74cf05db93c9070445945c9e39cd6529f67d1a00ea93961da ). However, in the last decade it's likely that these APIs have been deprecated and you'd have to look into whatever replaced them.
It's easy enough to use Metal or OpenGL though. Just make a fullscreen window, make two large triangles the size of the screen, and update their texture.

Optimising Python QT apps on retina displays

Qt interfaces currently look horrible on a retina display as they scale up.Its possible to use an Info.Plist for a complied application but does anyone have a solution for dynamic python such as interfaces created in PySide?
You didn't say what Qt version you're working with. Retina support is best in the latest release, Qt v5.1. but v5.0's is also pretty good. If you're still on Qt v4.8, you'll have to manually apply patches to enable high DPI.
High DPI mode is controlled by the following keys in the Info.Plist file:
<key>NSPrincipalClass</key>
<string>NSApplication</string>
<key>NSHighResolutionCapable</key>
<string>True</string>
Qt 5 uses the raster paint engine and implements high-dpi vector graphics by scaling the painter transform. If NSHighResolutionCapable is not set, the application will be rendered at the “normal” resolution which will simply be scaled up. This looks horrible on high resolution displays. On the other hand the high resolution mode is fully backwards compatible and is rendered nicely on lower resolution displays. I would leave it enabled all the time.
Once high DPI is enabled you still have to make sure that all your raster content (image resources) has a high-enough resolution to be displayed nicely. See the QT Blog post Retina display support for Mac OS, iOS and X11 for the full details.
I basically found out the solution: be sure you have QT >= 5 installed, since it has been introduced in that version, secondly I am now running python3.3.
Enjoy your retina

Python Tkinter interface appearance changes depending on OS

My application looks beautiful on Windows
But on MacOS and Linux it does not look nice at all!
Is there something I can do to help make this widget appearance consistent across operating systems?
My application source code : http://pae.st/BILs/
Using Tkinter's place manager for widget layout causes the poor layout of your application on different operating systems. You should be using either pack or grid managers, both of which will adjust to the differing widget sizes you encounter.

Categories