首页 > 解决方案 > 在 PyQt5 中创建复杂的自定义小部件并将其添加到 QGridlayout

问题描述

我必须创建一个如下所示的自定义小部件:

custom_widget_sketch

每个自定义小部件代表一个 LIPO 电池,并显示电池电压(V)、状态文本(charging, discharging, etc)、电池序列号(S/N)和三种状态LEDs(黄色、绿色和红色)

创建自定义小部件后,我需要在 6*5 的网格中添加其中的 30 个。我在这里的假设是,一旦我创建了该自定义小部件,它应该就像在 QGridLayout 中添加一个 QPushButton 一样简单,如下所示:

custom_layput = QGridLayout()
custom_layout.addWidget(custom_widget, 0, 0)
custom_layout.addWidget(custom_widget, 0, 1)

.
.
.

custom_layout.addWidget(custom_widget, 6, 5)

最终屏幕如下所示:

main_window_sketch

考虑到所有这些要求,我有以下问题:

  1. 我能否使用 PyQt5 创建如此复杂/丰富的自定义小部件?可行吗?
  2. 这是创建自定义小部件的正确方法吗:首先使用 QPainter 绘制一个正方形(这是 custom_widget_sketch 中的蓝色正方形),然后添加 QLineEdits 以显示电压 (V) 文本、序列号 (S/N) 文本和状态文本,添加一个 QLabel 用于在自定义小部件中显示“V”、“S/N”和“STATUS”标签,然后绘制三个圆圈:黄色、绿色和红色各一个LEDs,然后使用QVBoxLayout和的组合QHBoxLayout 用于排列QLineEditsQLabels、 正方形和圆形(LED 指示灯)
  3. 如何打包这个自定义小部件,以便我可以像添加 aQPushButton或 a一样简单地将其添加到布局中QLineEdit

PS:custom_widget_sketch 在左上角还包含一条线和一个正方形,里面有三条线。这是为了描述 LIPO 电池的连接器。现在实施它可能太复杂了。因此,即使我能够实现这两个元素以外的所有内容,我也会很高兴

我经历了一些 SO 问题,但它们都参考了一个教程,这不是我的最终目标。

我将不胜感激任何代码片段、要遵循的代码/步骤的一般大纲或任何文章/教程的链接,这些文章/教程创建了类似于我希望创建的自定义小部件。

标签: pythonpyqtpyqt5customization

解决方案


我最终创建的自定义小部件的 Python 代码。小部件如下所示:

custom_widget_screenshot

from PyQt5.QtGui import QPainter, QPen,QBrush,QColor
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QHBoxLayout,QPushButton, QLineEdit, QLabel, QVBoxLayout, QHBoxLayout, QSizePolicy, QGroupBox
import sys

class BatteryStatusWidget(QWidget):
    def __init__(self):
        super(BatteryStatusWidget, self).__init__()
        #Voltage widgets
        self.voltage_text = QLineEdit()
        self.voltage_text.setReadOnly(True)
        self.voltage_label = QLabel("V")
        self.voltage_label.setStyleSheet("QLabel {color : white}")

        #Status widgets
        self.status_text = QLineEdit()
        self.status_text.setReadOnly(True)
        self.status_label = QLabel("STATUS")
        self.status_label_font = QtGui.QFont()
        self.status_label_font.setPointSize(12)
        self.status_label.setFont(self.status_label_font)
        self.status_label.setAlignment(QtCore.Qt.AlignCenter)
        self.status_label.setStyleSheet("QLabel {color : white}")

        #Serial number
        self.serial_number_text = QLineEdit()
        self.serial_number_label = QLabel("S/N")

        #LED widgets
        self.yellow_led_label = QLabel()
        self.yellow_led_label.setStyleSheet("QLabel {background-color : yellow; border-color : black; border-width : 1px; border-style : solid; border-radius : 10px; min-height: 20px; min-width: 20px}")
        self.green_led_label = QLabel()
        self.green_led_label.setStyleSheet("QLabel {background-color : green; border-color : black; border-width : 1px; border-style : solid; border-radius : 10px; min-height: 20px; min-width: 20px}")
        self.red_led_label = QLabel()
        self.red_led_label.setStyleSheet("QLabel {background-color : red; border-color : black; border-width : 1px; border-style : solid; border-radius : 10px; min-height: 20px; min-width: 20px}")

        #Number Identifier Label
        #This label is for tagging the widget with the same label as on the PCB
        self.number_label = QLabel("Test")
        self.number_label.setAlignment(QtCore.Qt.AlignCenter)
        self.number_label_font = QtGui.QFont()
        self.number_label_font.setPointSize(12)
        self.number_label_font.setBold(True)
        self.number_label.setFont(self.number_label_font)

        #Layouts
        #voltage layout
        self.voltage_layout = QHBoxLayout()
        self.voltage_layout.addWidget(self.voltage_text)
        self.voltage_layout.addWidget(self.voltage_label)

        #Serial number layout
        self.serial_num_layout = QHBoxLayout()
        self.serial_num_layout.addWidget(self.serial_number_label)
        self.serial_num_layout.addWidget(self.serial_number_text)

        #Voltage and status box layouts
        self.blue_container = QWidget()
        self.blue_container.setStyleSheet("background-color:rgb(77, 122, 194);")
        self.blue_box_layout = QVBoxLayout()
        self.blue_box_layout.addLayout(self.voltage_layout)
        self.blue_box_layout.addWidget(self.status_text)
        self.blue_box_layout.addWidget(self.status_label)
        self.blue_container.setLayout(self.blue_box_layout)


        #Blue box+ serial num layout
        self.non_led_layout = QVBoxLayout()
        #self.non_led_layout.addWidget(self.number_label)
        self.non_led_layout.addWidget(self.blue_container)
        self.non_led_layout.addLayout(self.serial_num_layout)

        #LED layout
        self.led_layout = QVBoxLayout()
        self.led_layout.addWidget(self.yellow_led_label)
        self.led_layout.addWidget(self.green_led_label)
        self.led_layout.addWidget(self.red_led_label)
        self.led_layout.addStretch(1)

        #Main Layout
        self.main_layout = QHBoxLayout()
        self.main_layout.addLayout(self.non_led_layout)
        self.main_layout.addLayout(self.led_layout)

        #Main group box
        self.main_group_box = QGroupBox()
        self.main_group_box.setStyleSheet("QGroupBox{font-size: 10px}")
        self.main_group_box.setTitle("Chan #")
        self.main_group_box.setLayout(self.main_layout)

        #Outer main layout to accomodate the group box
        self.outer_main_layout = QVBoxLayout()
        self.outer_main_layout.addWidget(self.main_group_box)

        #Set the main layout
        self.setLayout(self.outer_main_layout)
        self.setWindowTitle("Battery Widget")


if __name__ == '__main__':
    app = QApplication(sys.argv)
    main_window = BatteryStatusWidget()
    main_window.show()
    app.exec_()

我能够轻松地创建自定义小部件的 30 个实例并将其添加到QGridLayout我在我的问题中发布的。最终的 GUI 屏幕如下所示:

final_GUI_window_screenshot


推荐阅读