我正在尝试重建一个屏幕记录PyQt应用程序,而ScreenToGIF对我来说是一个很好的演示,它创建了一个只在“中央小部件”中具有边框和记录内容的接口,如下所示:

具有以下主要职能:
然而,它是在C# (链接:https://github.com/NickeManarin/ScreenToGif)中实现的,我想知道是否有可能在没有学习C#专业知识的情况下制作类似的PyQt应用程序?
将QMainWidgets的背景图像更改为桌面区域没有意义,因为应该记录桌面上的鼠标操作(例如双击打开文件)。鼠标事件可以穿透应用程序(就像Qt.WindowTransparentForInput应用于内部内容?)
发布于 2019-08-31 23:04:51
您想要实现的目标是设置一个https://doc.qt.io/qt-5/qwidget.html#setMask-1,允许您拥有一个具有特定“形状”的小部件,该小部件不一定是矩形。
主要的困难是理解窗口几何图形是如何工作的,这可能很棘手。
您必须确保窗口“框架”(包括其边距和标题栏-如果有的话)已经计算,然后找出内部矩形,并创建相应的掩码。请注意,在Linux上,这发生在调用了“某一段时间”之后;我认为您在show()上,但是我已经以一种对Linux、MacOS和show()都很好的方式实现了它。如果您确信您的程序将只在Windows上运行,则有关于此的评论。
最后,我只能在Linux、葡萄酒和一个虚拟化的WinXP环境上运行这个程序。它应该在任何系统上都能正常工作,但是,根据我的经验,有一个特定的“化妆品”错误:标题栏不是按照当前的Windows主题绘制的。我认为这是因为无论何时应用掩码,底层的windows系统都不会像通常那样绘制“样式”窗口框架。如果在较新的系统中也出现这种情况,可能会有一个解决办法,但这并不容易,我不能保证它能解决这个问题。
NB:请记住,这种方法永远不会允许您在“抓取矩形”内绘制任何东西(没有阴影,也没有半透明的彩色掩码);原因是您显然需要实现鼠标与“下方”小部件的交互,并对其进行绘制将需要更改覆盖掩码。
from PyQt5 import QtCore, QtGui, QtWidgets
class VLine(QtWidgets.QFrame):
# a simple VLine, like the one you get from designer
def __init__(self):
super(VLine, self).__init__()
self.setFrameShape(self.VLine|self.Sunken)
class Grabber(QtWidgets.QWidget):
dirty = True
def __init__(self):
super(Grabber, self).__init__()
self.setWindowTitle('Screen grabber')
# ensure that the widget always stays on top, no matter what
self.setWindowFlags(self.windowFlags() | QtCore.Qt.WindowStaysOnTopHint)
layout = QtWidgets.QVBoxLayout()
self.setLayout(layout)
# limit widget AND layout margins
layout.setContentsMargins(0, 0, 0, 0)
self.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(0)
# create a "placeholder" widget for the screen grab geometry
self.grabWidget = QtWidgets.QWidget()
self.grabWidget.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
layout.addWidget(self.grabWidget)
# let's add a configuration panel
self.panel = QtWidgets.QWidget()
layout.addWidget(self.panel)
panelLayout = QtWidgets.QHBoxLayout()
self.panel.setLayout(panelLayout)
panelLayout.setContentsMargins(0, 0, 0, 0)
self.setContentsMargins(1, 1, 1, 1)
self.configButton = QtWidgets.QPushButton(self.style().standardIcon(QtWidgets.QStyle.SP_ComputerIcon), '')
self.configButton.setFlat(True)
panelLayout.addWidget(self.configButton)
panelLayout.addWidget(VLine())
self.fpsSpinBox = QtWidgets.QSpinBox()
panelLayout.addWidget(self.fpsSpinBox)
self.fpsSpinBox.setRange(1, 50)
self.fpsSpinBox.setValue(15)
panelLayout.addWidget(QtWidgets.QLabel('fps'))
panelLayout.addWidget(VLine())
self.widthLabel = QtWidgets.QLabel()
panelLayout.addWidget(self.widthLabel)
self.widthLabel.setFrameShape(QtWidgets.QLabel.StyledPanel|QtWidgets.QLabel.Sunken)
panelLayout.addWidget(QtWidgets.QLabel('x'))
self.heightLabel = QtWidgets.QLabel()
panelLayout.addWidget(self.heightLabel)
self.heightLabel.setFrameShape(QtWidgets.QLabel.StyledPanel|QtWidgets.QLabel.Sunken)
panelLayout.addWidget(QtWidgets.QLabel('px'))
panelLayout.addWidget(VLine())
self.recButton = QtWidgets.QPushButton('rec')
panelLayout.addWidget(self.recButton)
self.playButton = QtWidgets.QPushButton('play')
panelLayout.addWidget(self.playButton)
panelLayout.addStretch(1000)
def updateMask(self):
# get the *whole* window geometry, including its titlebar and borders
frameRect = self.frameGeometry()
# get the grabWidget geometry and remap it to global coordinates
grabGeometry = self.grabWidget.geometry()
grabGeometry.moveTopLeft(self.grabWidget.mapToGlobal(QtCore.QPoint(0, 0)))
# get the actual margins between the grabWidget and the window margins
left = frameRect.left() - grabGeometry.left()
top = frameRect.top() - grabGeometry.top()
right = frameRect.right() - grabGeometry.right()
bottom = frameRect.bottom() - grabGeometry.bottom()
# reset the geometries to get "0-point" rectangles for the mask
frameRect.moveTopLeft(QtCore.QPoint(0, 0))
grabGeometry.moveTopLeft(QtCore.QPoint(0, 0))
# create the base mask region, adjusted to the margins between the
# grabWidget and the window as computed above
region = QtGui.QRegion(frameRect.adjusted(left, top, right, bottom))
# "subtract" the grabWidget rectangle to get a mask that only contains
# the window titlebar, margins and panel
region -= QtGui.QRegion(grabGeometry)
self.setMask(region)
# update the grab size according to grabWidget geometry
self.widthLabel.setText(str(self.grabWidget.width()))
self.heightLabel.setText(str(self.grabWidget.height()))
def resizeEvent(self, event):
super(Grabber, self).resizeEvent(event)
# the first resizeEvent is called *before* any first-time showEvent and
# paintEvent, there's no need to update the mask until then; see below
if not self.dirty:
self.updateMask()
def paintEvent(self, event):
super(Grabber, self).paintEvent(event)
# on Linux the frameGeometry is actually updated "sometime" after show()
# is called; on Windows and MacOS it *should* happen as soon as the first
# non-spontaneous showEvent is called (programmatically called: showEvent
# is also called whenever a window is restored after it has been
# minimized); we can assume that all that has already happened as soon as
# the first paintEvent is called; before then the window is flagged as
# "dirty", meaning that there's no need to update its mask yet.
# Once paintEvent has been called the first time, the geometries should
# have been already updated, we can mark the geometries "clean" and then
# actually apply the mask.
if self.dirty:
self.updateMask()
self.dirty = False
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
grabber = Grabber()
grabber.show()
sys.exit(app.exec_())发布于 2019-08-29 21:46:44
请尝尝这个
from PyQt5.QtWidgets import QMainWindow, QApplication
from PyQt5.QtCore import Qt
import sys
class MainWindowExample(QMainWindow):
def __init__(self, parent=None):
try:
QMainWindow.__init__(self, parent)
self.setWindowFlags(Qt.CustomizeWindowHint | Qt.FramelessWindowHint)
self.setStyleSheet("border: 1px solid rgba(0, 0, 0, 0.15);")
except Exception as e:
print(e)
if __name__ == '__main__':
app = QApplication(sys.argv)
main_widow = MainWindowExample()
main_widow.show()
sys.exit(app.exec_())https://stackoverflow.com/questions/57717331
复制相似问题