Custom Titlebar with frame in PyQt5

后端 未结 1 1114
北恋
北恋 2020-11-30 10:32

I\'m working on an opensource markdown supported minimal note taking application for Windows/Linux. I\'m trying to remove the title bar and add my own buttons. I want someth

相关标签:
1条回答
  • 2020-11-30 11:25

    Here are the steps you just gotta follow:

    1. Have your MainWindow, be it a QMainWindow, or QWidget, or whatever [widget] you want to inherit.
    2. Set its flag, self.setWindowFlags(Qt.FramelessWindowHint)
    3. Implement your own moving around.
    4. Implement your own buttons (close, max, min)
    5. Implement your own resize.

    Here is a small example with move around, and buttons implemented. You should still have to implement the resize using the same logic.

    import sys
    
    from PyQt5.QtCore import QPoint
    from PyQt5.QtCore import Qt
    from PyQt5.QtWidgets import QApplication
    from PyQt5.QtWidgets import QHBoxLayout
    from PyQt5.QtWidgets import QLabel
    from PyQt5.QtWidgets import QPushButton
    from PyQt5.QtWidgets import QVBoxLayout
    from PyQt5.QtWidgets import QWidget
    
    
    
    class MainWindow(QWidget):
    
        def __init__(self):
            super(MainWindow, self).__init__()
            self.layout  = QVBoxLayout()
            self.layout.addWidget(MyBar(self))
            self.setLayout(self.layout)
            self.layout.setContentsMargins(0,0,0,0)
            self.layout.addStretch(-1)
            self.setMinimumSize(800,400)
            self.setWindowFlags(Qt.FramelessWindowHint)
            self.pressing = False
    
    
    class MyBar(QWidget):
    
        def __init__(self, parent):
            super(MyBar, self).__init__()
            self.parent = parent
            print(self.parent.width())
            self.layout = QHBoxLayout()
            self.layout.setContentsMargins(0,0,0,0)
            self.title = QLabel("My Own Bar")
    
            btn_size = 35
    
            self.btn_close = QPushButton("x")
            self.btn_close.clicked.connect(self.btn_close_clicked)
            self.btn_close.setFixedSize(btn_size,btn_size)
            self.btn_close.setStyleSheet("background-color: red;")
    
            self.btn_min = QPushButton("-")
            self.btn_min.clicked.connect(self.btn_min_clicked)
            self.btn_min.setFixedSize(btn_size, btn_size)
            self.btn_min.setStyleSheet("background-color: gray;")
    
            self.btn_max = QPushButton("+")
            self.btn_max.clicked.connect(self.btn_max_clicked)
            self.btn_max.setFixedSize(btn_size, btn_size)
            self.btn_max.setStyleSheet("background-color: gray;")
    
            self.title.setFixedHeight(35)
            self.title.setAlignment(Qt.AlignCenter)
            self.layout.addWidget(self.title)
            self.layout.addWidget(self.btn_min)
            self.layout.addWidget(self.btn_max)
            self.layout.addWidget(self.btn_close)
    
            self.title.setStyleSheet("""
                background-color: black;
                color: white;
            """)
            self.setLayout(self.layout)
    
            self.start = QPoint(0, 0)
            self.pressing = False
    
        def resizeEvent(self, QResizeEvent):
            super(MyBar, self).resizeEvent(QResizeEvent)
            self.title.setFixedWidth(self.parent.width())
    
        def mousePressEvent(self, event):
            self.start = self.mapToGlobal(event.pos())
            self.pressing = True
    
        def mouseMoveEvent(self, event):
            if self.pressing:
                self.end = self.mapToGlobal(event.pos())
                self.movement = self.end-self.start
                self.parent.setGeometry(self.mapToGlobal(self.movement).x(),
                                    self.mapToGlobal(self.movement).y(),
                                    self.parent.width(),
                                    self.parent.height())
                self.start = self.end
    
        def mouseReleaseEvent(self, QMouseEvent):
            self.pressing = False
    
    
        def btn_close_clicked(self):
            self.parent.close()
    
        def btn_max_clicked(self):
            self.parent.showMaximized()
    
        def btn_min_clicked(self):
            self.parent.showMinimized()
    
    
    if __name__ == "__main__":
        app = QApplication(sys.argv)
        mw = MainWindow()
        mw.show()
        sys.exit(app.exec_())
    

    Here are some tips:

    Option 1:

    1. Have a QGridLayout with widget in each corner and side(e.g. left, top-left, menubar, top-right, right, bottom-right, bottom and bottom left)
    2. With the approach (1) you would know when you are clicking in each border, you just got to define each one size and add each one on their place.
    3. When you click on each one treat them in their respective ways, for example, if you click in the left one and drag to the left, you gotta resize it larger and at the same time move it to the left so it will appear to be stopped at the right place and grow width.
    4. Apply this reasoning to each edge, each one behaving in the way it has to.

    Option 2:

    1. Instead of having a QGridLayout you can detect in which place you are clicking by the click pos.

    2. Verify if the x of the click is smaller than the x of the moving pos to know if it's moving left or right and where it's being clicked.

    3. The calculation is made in the same way of the Option1

    Option 3:

    1. Probably there are other ways, but those are the ones I just thought of. For example using the CustomizeWindowHint you said you are able to resize, so you just would have to implement what I gave you as example. BEAUTIFUL!

    Tips:

    1. Be careful with the localPos(inside own widget), globalPos(related to your screen). For example: If you click in the very left of your left widget its 'x' will be zero, if you click in the very left of the middle(content)it will be also zero, although if you mapToGlobal you will having different values according to the pos of the screen.
    2. Pay attention when resizing, or moving, when you have to add width or subtract, or just move, or both, I'd recommend you to draw on a paper and figure out how the logic of resizing works before implementing it out of blue.

    GOOD LUCK :D

    0 讨论(0)
提交回复
热议问题