Is It Possible To Create Qmainwindow With Only Outer Border?
Solution 1:
What you want to achieve requires setting a mask, allowing you to have a widget that has a specific "shape" that doesn't have to be a rectangle.
The main difficulty is to understand how window geometries work, which can be tricky.
You have to ensure that the window "frame" (which includes its margins and titlebar - if any) has been computed, then find out the inner rectangle and create a mask accordingly. Note that on Linux this happens "some time" after show()
has been called; I think you're on Windows, but I've implemented it in a way that should work fine for both Linux, MacOS and Windows. There's a comment about that, if you're sure that your program will run on Windows only.
Finally, I've only been able to run this on Linux, Wine and a virtualized WinXP environment. It should work fine on any system, but, from my experience, there's a specific "cosmetic" bug: the title bar is not painted according to the current Windows theme. I think that this is due to the fact that whenever a mask is applied, the underlying windows system doesn't draw its "styled" window frame as it usually would. If this happens in newer systems also, there could be a workaround, but it's not easy, and I cannot guarantee that it would solve this issue.
NB: remember that this approach will never allow you to draw anything inside the "grab rectangle" (no shade, nor semi-transparent color mask); the reason for this is that you obviously need to achieve mouse interaction with what is "beneath" the widget, and painting over it would require altering the overlaying mask.
from PyQt5 import QtCore, QtGui, QtWidgets
classVLine(QtWidgets.QFrame):
# a simple VLine, like the one you get from designerdef__init__(self):
super(VLine, self).__init__()
self.setFrameShape(self.VLine|self.Sunken)
classGrabber(QtWidgets.QWidget):
dirty = Truedef__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)
defupdateMask(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()))
defresizeEvent(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 belowifnot self.dirty:
self.updateMask()
defpaintEvent(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 = Falseif __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
grabber = Grabber()
grabber.show()
sys.exit(app.exec_())
Solution 2:
please try this
from PyQt5.QtWidgets import QMainWindow, QApplication
from PyQt5.QtCore import Qt
import sys
classMainWindowExample(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_())
Post a Comment for "Is It Possible To Create Qmainwindow With Only Outer Border?"