如何全屏显示在辅助监视器上的图像? [英] How to display image on secondary monitor in full screen?

查看:130
本文介绍了如何全屏显示在辅助监视器上的图像?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何使用PyQt5/PySide或任何其他Python库以全屏模式在辅助监视器上显示所需的图像?过去,我使用帧缓冲图像查看器( Fbi Fbi已改进).但是,这种方法要求我使用Linux.我更喜欢在Windows中工作,最好使用Python查找解决方案.

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.

动机/背景

我正在研究基于DLP投影的3D打印过程.当我使用HDMI将DLP投影仪连接到Windows PC时,它会显示为第二台监视器.我只想将此辅助监视器(DLP)专用于显示3D打印过程中所需的图案图像(png,bmp或svg).我想使用Python以编程方式控制要显示的图像. 这是 https:的后续问题: //3dprinting.stackexchange.com/questions/1217/how-to-display-images-on-dlp-using-hdmi-for-3d-printing

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

部分解决方案和问题

下面的代码是一种可能的解决方案,但是我不确定它是正确还是最有效的方法.我发现使用PyQt5的两种方法:1)使用启动画面,以及2)使用QLabel.我的代码遇到以下问题:

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:

  • 光标被隐藏了,但是,如果我不小心在辅助屏幕上单击鼠标,启动屏幕将关闭.
  • 如果我使用QLabel方法,则会看到白屏,然后加载图像.从白屏显示到实际图像显示,大约有0.5-1s的延迟.
  • 如果图像以高频率显示(例如,每1秒显示一次),则此代码无法正常工作.例如,在代码中将 total_loops = 1 更改为 total_loops = 25 .使用启动屏幕方法时,我看到启动屏幕出现在主屏幕上,然后移至第二屏幕.当使用QLabel方法时,我看到的只是一个白屏,并且只显示图像的最后一次迭代.此外,QLabel的窗口在主屏幕上变为活动状态,并在任务栏中可见.
  • 如果要显示视频而不是图像,该如何处理?
  • 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?

对于3D打印应用程序,该解决方案需要满足以下要求:

For 3D printing application, the solution needs to meet the following requirement:

  • 辅助屏幕是DLP投影仪,它不应包含任何与操作系统相关的窗口/任务栏/等...
  • 辅助屏幕上不应出现光标/鼠标或其他应用程序
  • 图像/视频需要以全屏模式显示
  • 在辅助屏幕上显示或更新图像时,主屏幕上应该没有干扰.例如,辅助屏幕中的图像窗口不应将焦点移离主屏幕中当前处于活动状态的窗口
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_())

推荐答案

您不应在主线程之外运行GUI,因为Qt不能保证其正常工作,如

You should not run the GUI in other than the main thread since Qt does not guarantee that it works correctly as indicated by the docs. Instead of executing the GUI in another thread, you must execute the other heavy tasks in another thread.

您必须更改传统顺序逻辑的方法,但必须使用面向事件的编程,在事件发生之前(在通过信号进行Qt的情况下)采取措施.

You have to change your approach to classical sequential logic but you must use event-oriented programming where actions are taken before an event, in the case of Qt through signals.

考虑到上述情况,解决方案是:

Considering the above, the solution is:

import sys
import time


from PyQt5.QtCore import pyqtSignal, pyqtSlot, QObject, Qt, QThread, QTimer
from PyQt5.QtGui import QColor, QPixmap
from PyQt5.QtWidgets import QApplication, QLabel, QWidget


class TaskManager(QObject):
    task3Finished = pyqtSignal()
    task4Finished = pyqtSignal()

    @pyqtSlot()
    def task3(self):
        print("Step 3")
        print("     Continue some logic while QT running in background")
        time.sleep(2)
        self.task3Finished.emit()

    @pyqtSlot()
    def task4(self):
        print("Step 4")
        print("     Update the displayed image in the QT app running in background")
        time.sleep(2)
        self.task4Finished.emit()


class qtAppWidget(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setupGUI()

    def setupGUI(self):
        self.app = QApplication.instance()

        # Get avaliable screens/monitors
        # https://doc.qt.io/qt-5/qscreen.html
        # Get info on selected screen
        self.selected_screen = 0  # Select the desired monitor/screen

        self.screens_available = self.app.screens()
        self.screen = self.screens_available[self.selected_screen]
        self.screen_width = self.screen.size().width()
        self.screen_height = self.screen.size().height()

        # Create a black image for init
        self.pixmap = QPixmap(self.screen_width, self.screen_height)
        self.pixmap.fill(QColor("black"))

        # Create QLabel object
        self.app_widget = QLabel()

        # Varioius flags that can be applied to make displayed window frameless, fullscreen, etc...
        # https://doc.qt.io/qt-5/qt.html#WindowType-enum
        # https://doc.qt.io/qt-5/qt.html#WidgetAttribute-enum
        self.app_widget.setWindowFlags(
            Qt.FramelessWindowHint
            | Qt.WindowDoesNotAcceptFocus
            | Qt.WindowStaysOnTopHint
        )
        # Hide mouse cursor
        self.app_widget.setCursor(Qt.BlankCursor)

        self.app_widget.setGeometry(
            0, 0, self.screen_width, self.screen_height
        )  # Set the size of Qlabel to size of the screen
        self.app_widget.setWindowTitle("myImageDisplayApp")
        self.app_widget.setAlignment(
            Qt.AlignLeft | Qt.AlignTop
        )  # https://doc.qt.io/qt-5/qt.html#AlignmentFlag-enum
        self.app_widget.setPixmap(self.pixmap)
        self.app_widget.show()

        # Set the screen on which widget is on
        self.app_widget.windowHandle().setScreen(self.screen)
        # Make full screen
        self.app_widget.show()

    @pyqtSlot()
    def on_task3_finished(self):
        pixmap = QPixmap("qt_test_static_1.png")
        self.app_widget.setPixmap(pixmap)

    @pyqtSlot()
    def on_task4_finished(self):
        pixmap = QPixmap("qt_test_static_2.png")
        self.app_widget.setPixmap(pixmap)

        # quit application after to 2 secons
        QTimer.singleShot(2 * 1000, QApplication.quit)


def main(args):
    print("Step 1")
    print("     Some logic here without QT")

    print("Step 2")
    print("     Launch QT app to run")
    app = QApplication(args)
    myapp = qtAppWidget()

    thread = QThread()
    thread.start()

    manager = TaskManager()
    # move the QObject to the other thread
    manager.moveToThread(thread)

    manager.task3Finished.connect(myapp.on_task3_finished)
    manager.task3Finished.connect(manager.task4)
    manager.task4Finished.connect(myapp.on_task4_finished)

    # start task
    QTimer.singleShot(0, manager.task3)

    ret = app.exec_()

    thread.quit()
    thread.wait()

    del thread, app

    return ret


if __name__ == "__main__":

    sys.exit(main(sys.argv))

这篇关于如何全屏显示在辅助监视器上的图像?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆