How can I use PyQt5/PySide or any other Python library to display a desired image on a secondary monitor in full-screen mode? In the past, I used a framebuffer image viewer (Fbi and Fbi improved). However, this approach requires me to use Linux. I prefer to work in Windows and preferably find a solution using Python.
Motivation/Context
I am working on a DLP projection based 3D printing process. When I connect a DLP projector to my Windows PC using HDMI, it shows up as a second monitor. I want to dedicate this secondary monitor (DLP) only to display my desired patterns images (png, bmp, or svg) for the 3D printing process. I would like to programmatically control using Python which image is being displayed. This is a followup question to https://3dprinting.stackexchange.com/questions/1217/how-to-display-images-on-dlp-using-hdmi-for-3d-printing
Partial solution and issues
Below code is one possible solution, however I am unsure if its the correct or the most efficient approach. I found two approaches using PyQt5: 1) using splash screen, and 2) using QLabel. I am facing the following issues with my code:
- Cursor is hidden as expected, however if I accidentally click mouse on secondary screen, the splash screen closes.
- If I use the QLabel approach, I see a white screen appear and then my image gets loaded. There is a distinct delay of ~ 0.5-1s from the time white screen appears to when the actual image is displayed.
- If the images are displayed in high frequency (ex: every 1 sec), this code doesn't work well. For example, in the code change the total_loops=1 to total_loops=25. When using splash screen method, I see the splash screen appear on the main screen then it moves to the secondary screen. When using the QLabel method, all I see is a white screen appear, and only the last iteration the image is displayed. In addition, the window of the QLabel becomes active on the main screen and is visible in the Task bar.
- How do I handle a situation if I want to display a video instead of an image?
For 3D printing application, the solution needs to meet the following requirement:
- Secondary screen is the DLP projector, and it should NOT contain any OS related windows/taskbars/etc...
- No cursor/mouse or other applications should appear on the the secondary screen
- Images/videos need to be displayed in fullscreen mode
- When displaying or updating images on the secondary screen, there should be no disturbance on the primary screen. For example, the image window in secondary screen shouldn't take focus away from currently active window in the primary screen
import time
start_time = time.time()
import sys
from PyQt5.QtWidgets import QApplication, QLabel, QSplashScreen
from PyQt5.QtGui import QPixmap, QCursor
from PyQt5.QtCore import Qt
import os
app = QApplication(sys.argv)
total_loops = 1
for i in range(total_loops):
# https://doc.qt.io/qtforpython/index.html
# https://www.riverbankcomputing.com/static/Docs/PyQt5/module_index.html
s = app.screens()[1] # Get the secondary screen
# Display info about secondary screen
print('Screen Name: {} Size: {}x{} Available geometry {}x{} '.format(s.name(), s.size().width(), s.size().height(), s.availableGeometry().width(), s.availableGeometry().height()))
# Hide cursor from appearing on screen
app.setOverrideCursor(QCursor(Qt.BlankCursor)) # https://forum.qt.io/topic/49877/hide-cursor
# Select desired image to be displayed
pixmap = QPixmap('test.png')
# Splash screen approach
# https://doc.qt.io/qtforpython/PySide2/QtWidgets/QSplashScreen.html?highlight=windowflags
splash = QSplashScreen(pixmap) # Set the splash screen to desired image
splash.show() # Show the splash screen
splash.windowHandle().setScreen(s) # Set splash screen to secondary monitor https://stackoverflow.com/a/30597458/4988010
splash.showFullScreen() # Show in splash screen in full screen mode
# # Qlabel apporach
# l = QLabel()
# l.setPixmap(pixmap)
# l.move(1920,0)
# l.show()
# l.windowHandle().setScreen(s) # https://stackoverflow.com/a/30597458/4988010
# l.showFullScreen()
time.sleep(0.5)
end_time = time.time()
print('Execution time: ', end_time-start_time )
sys.exit(app.exec_())