Barra de título personalizada con marco en PyQt5

Estoy trabajando en una aplicación de toma de notas mínima compatible con Opendown Markdown para Windows / Linux. Estoy tratando de eliminar la barra de título y agregar mis propios botones. Quiero algo como, una barra de título con solo dos botones personalizados como se muestra en la figura introduzca la descripción de la imagen aquí

Actualmente tengo esto:

introduzca la descripción de la imagen aquí

He intentado modificar las banderas de la ventana:

  • Sin banderas de ventana, la ventana es redimensionable y movible. Pero no hay botones personalizados.
  • Al usar self.setWindowFlags(QtCore.Qt.FramelessWindowHint) , la ventana no tiene bordes, pero no puede mover o cambiar el tamaño de la ventana
  • Al usar self.setWindowFlags(QtCore.Qt.CustomizeWindowHint) , la ventana puede cambiar de tamaño pero no se puede mover y tampoco puede deshacerse de la parte blanca en la parte superior de la ventana.

Cualquier ayuda apreciada. Puedes encontrar el proyecto en GitHub aquí .

Gracias..

Este es mi código python:

 from PyQt5 import QtCore, QtWidgets, QtWebEngineWidgets, uic import sys import os import markdown2 # https://github.com/trentm/python-markdown2 from PyQt5.QtCore import QRect from PyQt5.QtGui import QFont simpleUiForm = uic.loadUiType("Simple.ui")[0] class SimpleWindow(QtWidgets.QMainWindow, simpleUiForm): def __init__(self, parent=None): QtWidgets.QMainWindow.__init__(self, parent) self.setupUi(self) self.markdown = markdown2.Markdown() self.css = open(os.path.join("css", "default.css")).read() self.editNote.setPlainText("") #self.noteView = QtWebEngineWidgets.QWebEngineView(self) self.installEventFilter(self) self.displayNote.setContextMenuPolicy(QtCore.Qt.NoContextMenu) #self.setWindowFlags(QtCore.Qt.FramelessWindowHint) def eventFilter(self, object, event): if event.type() == QtCore.QEvent.WindowActivate: print("widget window has gained focus") self.editNote.show() self.displayNote.hide() elif event.type() == QtCore.QEvent.WindowDeactivate: print("widget window has lost focus") note = self.editNote.toPlainText() htmlNote = self.getStyledPage(note) # print(note) self.editNote.hide() self.displayNote.show() # print(htmlNote) self.displayNote.setHtml(htmlNote) elif event.type() == QtCore.QEvent.FocusIn: print("widget has gained keyboard focus") elif event.type() == QtCore.QEvent.FocusOut: print("widget has lost keyboard focus") return False 

El archivo UI se crea en la siguiente jerarquía

introduzca la descripción de la imagen aquí

Aquí están los pasos que debes seguir:

  1. Tenga su MainWindow, ya sea un QMainWindow o QWidget, o cualquier otro [widget] que desee heredar.
  2. Establecer su bandera, self.setWindowFlags (Qt.FramelessWindowHint)
  3. Implementa tu propio movimiento.
  4. Implementa tus propios botones (close, max, min)
  5. Implementar su propio tamaño.

Aquí hay un pequeño ejemplo con movimientos y botones implementados. Aún debería tener que implementar el cambio de tamaño usando la misma lógica.

 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_()) 

Aquí hay algunos consejos:

Opción 1:

  1. Tenga un QGridLayout con widget en cada esquina y lado (por ejemplo, izquierda, arriba a la izquierda, barra de menú, arriba a la derecha, derecha, abajo a la derecha, abajo y abajo a la izquierda)
  2. Con el enfoque (1) sabría que al hacer clic en cada borde, solo tiene que definir cada tamaño y agregar cada uno en su lugar.
  3. Al hacer clic en cada uno, trátelos en sus respectivas formas, por ejemplo, si hace clic en el botón izquierdo y arrastra hacia la izquierda, tiene que cambiar su tamaño más grande y al mismo tiempo moverlo hacia la izquierda para que parezca que está Se detiene en el lugar correcto y crece ancho.
  4. Aplique este razonamiento a cada borde, cada uno se comporta de la manera que debe.

Opcion 2:

  1. En lugar de tener un QGridLayout, puede detectar en qué lugar está haciendo clic con el clic pos.

  2. Verifique si la x del clic es más pequeña que la x de la posición en movimiento para saber si se está moviendo hacia la izquierda o hacia la derecha y dónde se está haciendo clic.

  3. El cálculo se realiza de la misma manera que la Opción1.

Opción 3:

  1. Probablemente hay otras formas, pero esas son las que acabo de pensar. Por ejemplo, utilizando el CustomizeWindowHint que dijo que puede cambiar el tamaño, así que solo tendría que implementar lo que le di como ejemplo. ¡HERMOSO!

Consejos:

  1. Tenga cuidado con el localPos (dentro del propio widget), globalPos (relacionado con su pantalla). Por ejemplo: si hace clic en el lado izquierdo del widget de la izquierda, su ‘x’ será cero, si hace clic en el extremo izquierdo del medio (contenido) también será cero, aunque si mapToGlobal tendrá diferentes valores Según la posición de la pantalla.
  2. Preste atención cuando cambie el tamaño, o cuando se mueva, cuando tenga que agregar ancho o restar, o simplemente mover, o ambos, le recomendaría dibujar en un papel y averiguar cómo funciona la lógica de cambiar el tamaño antes de implementarlo de azul.

Buena suerte: D