Python - PyQt5 style checkable QGroupBox (Fusion) like WindowsVista

74 Views Asked by At

Python code:

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file '.\custom_qgroubox.ui'
#
# Created by: PyQt5 UI code generator 5.15.9
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again.  Do not edit this file unless you know what you are doing.


from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(474, 223)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.gridLayout_2 = QtWidgets.QGridLayout(self.centralwidget)
        self.gridLayout_2.setObjectName("gridLayout_2")
        self.groupBox = QtWidgets.QGroupBox(self.centralwidget)
        self.groupBox.setStyleSheet("QGroupBox{\n"
"    border:1px solid #dadada;\n"
"    font-size:50px;\n"
"    margin-top:26px;\n"
"    padding-top:35px;\n"
"}\n"
"\n"
"QGroupBox::title{\n"
"    subcontrol-origin:margin;\n"
"    subcontrol-position: top left;\n"
"    background:green;\n"
"    left:10px;\n"
"    top:0px;\n"
"    padding:0px;\n"
"    spacing:0px;\n"
"}")
        self.groupBox.setCheckable(True)
        self.groupBox.setObjectName("groupBox")
        self.gridLayout = QtWidgets.QGridLayout(self.groupBox)
        self.gridLayout.setObjectName("gridLayout")
        self.pushButton = QtWidgets.QPushButton(self.groupBox)
        self.pushButton.setObjectName("pushButton")
        self.gridLayout.addWidget(self.pushButton, 0, 0, 1, 1)
        self.pushButton_2 = QtWidgets.QPushButton(self.groupBox)
        self.pushButton_2.setObjectName("pushButton_2")
        self.gridLayout.addWidget(self.pushButton_2, 1, 0, 1, 1)
        self.pushButton_3 = QtWidgets.QPushButton(self.groupBox)
        self.pushButton_3.setObjectName("pushButton_3")
        self.gridLayout.addWidget(self.pushButton_3, 2, 0, 1, 1)
        self.gridLayout_2.addWidget(self.groupBox, 0, 0, 1, 1)
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 474, 22))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.groupBox.setTitle(_translate("MainWindow", "GroupBox"))
        self.pushButton.setText(_translate("MainWindow", "PushButton"))
        self.pushButton_2.setText(_translate("MainWindow", "PushButton"))
        self.pushButton_3.setText(_translate("MainWindow", "PushButton"))


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    app.setStyle("Fusion")    
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

Output:

enter image description here

In the green area i want to control (set/get):

  1. The space between the indicator and the groupbox title
  2. The space between the groupbox title and the top of green area
  3. The space between the right side of groupbox title and the end of right side of green area.

For 1. i want it to be 10px, for 2. i want it to be 0px and for 3. i also want it to be 0px.

Is that possible?

Thanks.

1

There are 1 best solutions below

0
Chris P On

File: graphics_custom_groupBox.py

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file '.\graphics_custom_groupBox.ui'
#
# Created by: PyQt5 UI code generator 5.15.9
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again.  Do not edit this file unless you know what you are doing.


from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(800, 600)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
        self.verticalLayout.setObjectName("verticalLayout")
        self.graphicsView = QtWidgets.QGraphicsView(self.centralwidget)
        self.graphicsView.setObjectName("graphicsView")
        self.verticalLayout.addWidget(self.graphicsView)
        self.frame = QtWidgets.QFrame(self.centralwidget)
        self.frame.setStyleSheet("QFrame{border:none;}")
        self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.frame.setFrameShadow(QtWidgets.QFrame.Raised)
        self.frame.setObjectName("frame")
        self.gridLayout = QtWidgets.QGridLayout(self.frame)
        self.gridLayout.setObjectName("gridLayout")
        self.pushButton_3 = QtWidgets.QPushButton(self.frame)
        self.pushButton_3.setObjectName("pushButton_3")
        self.gridLayout.addWidget(self.pushButton_3, 3, 0, 1, 1)
        self.pushButton = QtWidgets.QPushButton(self.frame)
        self.pushButton.setObjectName("pushButton")
        self.gridLayout.addWidget(self.pushButton, 1, 0, 1, 1)
        self.pushButton_2 = QtWidgets.QPushButton(self.frame)
        self.pushButton_2.setObjectName("pushButton_2")
        self.gridLayout.addWidget(self.pushButton_2, 2, 0, 1, 1)
        self.verticalLayout.addWidget(self.frame)
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 22))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.pushButton_3.setText(_translate("MainWindow", "PushButton"))
        self.pushButton.setText(_translate("MainWindow", "PushButton"))
        self.pushButton_2.setText(_translate("MainWindow", "PushButton"))


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

File: run_me.py

from PyQt5 import QtWidgets, QtCore, QtGui
from PyQt5.QtWidgets import QLabel, QApplication
from PyQt5.QtCore import pyqtSignal, QTimer
from graphics_custom_groupBox import Ui_MainWindow
import sys

class Run_me:
    
    def __init__(self):
        self.app = QtWidgets.QApplication(sys.argv)
        self.MainWindow = QtWidgets.QMainWindow()
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self.MainWindow)
        self.MainWindow.show()
        
        self.make_custom_groupBox(self.ui.graphicsView,self.ui.frame,"GroupBOX",font_size=20)
        
        sys.exit(self.app.exec_())
        
    def make_custom_groupBox(self,graphicsView,frame,title,font_size=20):
        self.frame = frame
        frame_width = self.frame.width()
        frame_top_margins = self.frame.contentsMargins().top()
        title_line_height = font_size
        self.frame.setContentsMargins(self.frame.contentsMargins().left(),int(font_size/2+self.frame.contentsMargins().top()),self.frame.contentsMargins().right(),self.frame.contentsMargins().bottom())
        
        self.MainWindow.adjustSize()
        
        frame_height = self.frame.height()
        self.ui.verticalLayout.removeWidget(self.frame)
        self.frame.setParent(None)
        
        
        
        self.frame.setStyleSheet(self.frame.styleSheet()+"QFrame{border:1px solid #dadada;}")
        graphicsView.setStyleSheet("QGraphicsView{border:none;background:transparent;}")

        self.scene = QtWidgets.QGraphicsScene()
        graphicsView.setScene(self.scene)
        self.scene.setSceneRect(0,0,frame_width,frame_height+title_line_height/2)
        graphicsView.setMinimumSize(QtCore.QSize(frame_width, int(frame_height+title_line_height/2)))
        graphicsView.setMaximumSize(QtCore.QSize(frame_width, int(frame_height+title_line_height/2)))
        
        self.frame.setMinimumSize(QtCore.QSize(frame_width, frame_height))
        self.frame.setMaximumSize(QtCore.QSize(frame_width, frame_height))
        
        self.frame.setFixedSize(int(frame_width),int(frame_height))
        proxy = self.scene.addWidget(self.frame)
        proxy.setFlag(QtWidgets.QGraphicsItem.ItemStacksBehindParent)
        proxy.setZValue(-1)
        proxy.setPos(0,title_line_height/2)
        
        self.control_checkBox = QtWidgets.QCheckBox()
        self.control_checkBox.setText("")
        self.control_checkBox.setCheckState(QtCore.Qt.Checked)
        self.control_checkBox.setStyleSheet("QCheckBox::indicator{width:"+str(title_line_height)+"px;height:"+str(title_line_height)+"px;}")
        self.control_checkBox.setFixedSize(int(title_line_height),int(title_line_height))
        self.control_checkBox.toggled.connect(lambda:self.control_checkBox_toggled())
        proxy = self.scene.addWidget(self.control_checkBox)
        proxy.setFlag(QtWidgets.QGraphicsItem.ItemStacksBehindParent)
        proxy.setZValue(10)
        proxy.setPos(10,0)
        
        groupBox_title = QLabelClickable()
        groupBox_title.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
        groupBox_title.setText(title)
        groupBox_title.setStyleSheet("QLabel{font-size:"+str(title_line_height)+"px;spacing:0;padding:0px;}")
        #groupBox_title.setFixedHeight(int(title_line_height))
        proxy = self.scene.addWidget(groupBox_title)
        groupBox_title.clicked.connect(lambda state:self.groupBox_title_clicked())
        proxy.setFlag(QtWidgets.QGraphicsItem.ItemStacksBehindParent)
        proxy.setZValue(10)
        proxy.setPos(10+int(title_line_height)+10,-(groupBox_title.sizeHint().height()-title_line_height))
        
        self.MainWindow.adjustSize()
        
    def control_checkBox_toggled(self):
        if self.control_checkBox.checkState() == QtCore.Qt.Checked:
            self.frame.setEnabled(True)
        else:
            self.frame.setEnabled(False)
    
    def groupBox_title_clicked(self):
        if self.frame.isEnabled():
            self.frame.setEnabled(False)
            self.control_checkBox.setCheckState(QtCore.Qt.Unchecked)
        else:
            self.frame.setEnabled(True)
            self.control_checkBox.setCheckState(QtCore.Qt.Checked)

class QLabelClickable(QLabel):
    clicked = pyqtSignal(str)
    
    def __init__(self, parent=None):
        super(QLabelClickable, self).__init__(parent)

    def mousePressEvent(self, event):
        self.ultimo = "Clic"
    
    def mouseReleaseEvent(self, event):
        if self.ultimo == "Clic":
            QTimer.singleShot(QApplication.instance().doubleClickInterval(),self.performSingleClickAction)
        else:
            # Realizar acción de doble clic.
            self.clicked.emit(self.ultimo)
    
    def mouseDoubleClickEvent(self, event):
        self.ultimo = "Doble Clic"
    
    def performSingleClickAction(self):
        if self.ultimo == "Clic":
            self.clicked.emit(self.ultimo)

if __name__ == "__main__":
    program = Run_me()

Result:

enter image description here

You can test for any font-size you want by editing this line:

self.make_custom_groupBox(self.ui.graphicsView,self.ui.frame,"GroupBox",font_size=100)