PyQt5:如何在每个连接的屏幕中打开一个 window?
PyQt5: how to open one window in each connected screen?
我正在尝试使用 python 为 linux 创建屏幕截图实用程序。现在我一直在尝试实现一个功能,让用户 select 从实时屏幕中选择一个区域并对其进行截图。想来想去,我得出的结论是在每个屏幕上创建一个全屏window来获取鼠标的点击和拖动坐标
如何让我的程序为连接到系统的每个屏幕创建一个全屏 window(没有工具栏图标)?
import sys
from PyQt5 import QtWidgets as qtw
from PyQt5 import QtGui as qtg
from PyQt5 import QtCore as qtc
class InvisWindow(qtw.QWidget):
def __init__(self, screens):
super().__init__()
self.setWindowFlags(qtc.Qt.Tool | qtc.Qt.FramelessWindowHint)
self.show()
self.showFullScreen()
self.windowHandle().setScreen(screens[0])
if __name__ == '__main__':
app = qtw.QApplication(sys.argv)
mw = InvisWindow(app.screens())
sys.exit(app.exec_())
我发现这段代码正在寻找一种方法,但无论我将哪个 screen
传递给 setScreen()
,它总是出现在一个屏幕上,即改变参数不会改变它出现在哪个屏幕上。
有两个问题:
If the screen is part of a virtual desktop of multiple screens, the window will not move automatically to newScreen.
- 在 Linux 上,在调用
show
和 window 实际上 映射 之间有一些时间和系统事件第一次出现在屏幕上(参见 Initial Geometry),如果未明确设置几何图形,则可以由 window 管理器覆盖;
也就是说,不需要为此使用 QWindow,因为通常使用 move
就足够了,您只需要在 before 任何调用到 show()
或相关函数:
class InvisWindow(qtw.QWidget):
def __init__(self, screens):
super().__init__()
self.setWindowFlags(qtc.Qt.Tool | qtc.Qt.FramelessWindowHint)
self.move(screens[0].geometry().topLeft())
self.showFullScreen()
请注意,在 showFullScreen()
之前调用 show()
是没有用的,因为它隐式调用了 setVisible(True)
.
如果您想要在所有内容之上显示一个单个 window,那么您可以尝试以下操作:
class InvisWindow(qtw.QWidget):
mapped = False
def __init__(self, screens):
super().__init__()
self.setWindowFlags(
qtc.Qt.WindowStaysOnTopHint |
qtc.Qt.Tool |
qtc.Qt.FramelessWindowHint
)
self.show()
def moveEvent(self, event):
if not self.mapped:
geometry = qtc.QRect()
for screen in qtw.QApplication.screens():
geometry |= screen.geometry()
if self.pos() != geometry.topLeft():
self.setGeometry(geometry)
self.mapped = True
请考虑最后几行,因为它们非常重要,因为尝试在几何更改事件(moveEvent
和 resizeEvent
)中进行几何更改会导致递归。
我正在尝试使用 python 为 linux 创建屏幕截图实用程序。现在我一直在尝试实现一个功能,让用户 select 从实时屏幕中选择一个区域并对其进行截图。想来想去,我得出的结论是在每个屏幕上创建一个全屏window来获取鼠标的点击和拖动坐标
如何让我的程序为连接到系统的每个屏幕创建一个全屏 window(没有工具栏图标)?
import sys
from PyQt5 import QtWidgets as qtw
from PyQt5 import QtGui as qtg
from PyQt5 import QtCore as qtc
class InvisWindow(qtw.QWidget):
def __init__(self, screens):
super().__init__()
self.setWindowFlags(qtc.Qt.Tool | qtc.Qt.FramelessWindowHint)
self.show()
self.showFullScreen()
self.windowHandle().setScreen(screens[0])
if __name__ == '__main__':
app = qtw.QApplication(sys.argv)
mw = InvisWindow(app.screens())
sys.exit(app.exec_())
我发现这段代码正在寻找一种方法,但无论我将哪个 screen
传递给 setScreen()
,它总是出现在一个屏幕上,即改变参数不会改变它出现在哪个屏幕上。
有两个问题:
If the screen is part of a virtual desktop of multiple screens, the window will not move automatically to newScreen.
- 在 Linux 上,在调用
show
和 window 实际上 映射 之间有一些时间和系统事件第一次出现在屏幕上(参见 Initial Geometry),如果未明确设置几何图形,则可以由 window 管理器覆盖;
也就是说,不需要为此使用 QWindow,因为通常使用 move
就足够了,您只需要在 before 任何调用到 show()
或相关函数:
class InvisWindow(qtw.QWidget):
def __init__(self, screens):
super().__init__()
self.setWindowFlags(qtc.Qt.Tool | qtc.Qt.FramelessWindowHint)
self.move(screens[0].geometry().topLeft())
self.showFullScreen()
请注意,在 showFullScreen()
之前调用 show()
是没有用的,因为它隐式调用了 setVisible(True)
.
如果您想要在所有内容之上显示一个单个 window,那么您可以尝试以下操作:
class InvisWindow(qtw.QWidget):
mapped = False
def __init__(self, screens):
super().__init__()
self.setWindowFlags(
qtc.Qt.WindowStaysOnTopHint |
qtc.Qt.Tool |
qtc.Qt.FramelessWindowHint
)
self.show()
def moveEvent(self, event):
if not self.mapped:
geometry = qtc.QRect()
for screen in qtw.QApplication.screens():
geometry |= screen.geometry()
if self.pos() != geometry.topLeft():
self.setGeometry(geometry)
self.mapped = True
请考虑最后几行,因为它们非常重要,因为尝试在几何更改事件(moveEvent
和 resizeEvent
)中进行几何更改会导致递归。