Issue
I want to create a custom title bar for my PyQt application, and my application uses dockable toolbars. To be dockable, the toolbars should be added to the MainWindow. However, with my custom toolbar being a Widget added to a frameless window, the toolbars dock themselves around the title bar. They can be docked above the title bar, and whenever docked on the sides, they push the title bar, which is not the expected behavior. I understand that this is due to the fact the the toolbar areas are always around the central widget of the window, and my custom title bar is inside the central widget. However, I don't see how I can make this work the way I want. Here is a MWE (I'm using PyQt=5.12.3
) :
import sys
from typing import Optional
from PyQt5.QtCore import Qt, QSize, QPoint
from PyQt5.QtGui import QMouseEvent
from PyQt5.QtWidgets import QMainWindow, QApplication, QVBoxLayout, QPushButton, QWidget, QToolBar, QHBoxLayout, QLabel, \
QToolButton
class CustomTitleBar(QWidget):
def __init__(self, title: str, parent: Optional[QWidget] = None):
super().__init__(parent=parent)
self.window_parent = parent
layout = QHBoxLayout()
self.setObjectName("CustomTitleBar")
self.setLayout(layout)
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(0)
self.setFixedHeight(40)
self.title = title
self.title_label = QLabel(self.title)
self.title_label.setObjectName("TitleBarLabel")
layout.addWidget(self.title_label)
layout.addStretch(1)
but_minimize = QToolButton()
but_minimize.setText("🗕")
but_minimize.setObjectName("MinimizeButton")
layout.addWidget(but_minimize)
but_minimize.clicked.connect(self.window().showMinimized)
self.but_resize = QToolButton()
if self.window().isMaximized():
self.but_resize.setText("🗗")
else:
self.but_resize.setText("🗖")
layout.addWidget(self.but_resize)
self.but_resize.clicked.connect(self.toggle_maximized)
self.but_resize.setObjectName("ResizeButton")
but_close = QToolButton()
but_close.setText("🗙")
layout.addWidget(but_close)
but_close.clicked.connect(self.window().close)
but_close.setObjectName("CloseButton")
self.m_pCursor = QPoint(0, 0)
self.moving = False
def toggle_maximized(self):
if self.window().isMaximized():
self.but_resize.setText("🗖")
self.window().showNormal()
else:
self.but_resize.setText("🗗")
self.window().showMaximized()
def mousePressEvent(self, event: QMouseEvent) -> None:
pass
def mouseDoubleClickEvent(self, event: QMouseEvent) -> None:
pass
def mouseMoveEvent(self, event: QMouseEvent) -> None:
pass
def mouseReleaseEvent(self, event: QMouseEvent) -> None:
pass
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowSystemMenuHint)
self.resize(QSize(800, 600))
main_widget = QWidget(self)
self.setCentralWidget(main_widget)
layout = QVBoxLayout(self)
main_widget.setLayout(layout)
titlebar = CustomTitleBar("Custom TitleBar Test Window", self)
layout.addWidget(titlebar)
layout.addWidget(QPushButton("Hello world"))
layout.addStretch(1)
my_toolbar = QToolBar(self)
self.addToolBar(Qt.RightToolBarArea, my_toolbar)
my_toolbar.addWidget(QPushButton("A"))
my_toolbar.addWidget(QPushButton("B"))
my_toolbar.addWidget(QPushButton("C"))
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MainWindow()
w.show()
app.exec_()
The resulting window is as follow:
How can I get the dockable toolbars to behave around my custom title bar the way they should behave around a standard title bar ?
Solution
Since the title bar should be put outside the standard contents, you cannot put it inside the central widget.
The solution is to setContentsMargins()
using the height of the title bar for the top margin. Then, since the title bar is not managed by any layout, you need to resize it by overriding the resizeEvent()
:
class MainWindow(QMainWindow):
def __init__(self):
# ...
self.titlebar = CustomTitleBar("Custom TitleBar Test Window", self)
self.setContentsMargins(0, self.titlebar.sizeHint().height(), 0, 0)
def resizeEvent(self, event):
super().resizeEvent(event)
self.titlebar.resize(self.width(), self.titlebar.sizeHint().height())
Answered By - musicamante
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.