在 PyQt5 中创建复杂的自定义小部件并将其添加到 QGridlayout

2022-01-12 00:00:00 python pyqt pyqt5 customization

问题描述

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

I have to create a custom widget that looks like the following:

custom_widget_sketch

custom_widget_sketch

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

Each custom widget is a representation of one LIPO battery, and displays the battery volatge (V), status text (charging, discharging, etc), serial number of the battery (S/N) and three status LEDs (yellow, green and red)

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

After I have created the custom widget I need to add 30 of these in a grid of 6*5. My assumption here is that once I have created that custom widget it should be as simple as adding say a QPushButton in a QGridLayout like so:

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

main_window_sketch

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

Considering all of these requirements I have the following questions:

  1. 我能否使用 PyQt5 创建如此复杂/丰富的自定义小部件?可行吗?
  2. 这是创建自定义小部件的正确方法吗:首先使用 QPainter 绘制一个正方形(这是 custom_widget_sketch 中的蓝色正方形),然后添加 QLineEdits 以显示电压 (V) 文本、序列号 (S/N)文本和状态文本,添加一个 QLabel 用于在自定义小部件中显示V"、S/N"和STATUS"标签,然后绘制三个圆圈:黄色、绿色和红色 LED 各一个,然后使用 QVBoxLayout 和 QHBoxLayout 的组合来排列 QLineEditsQLabels、正方形和圆形(LED 指示灯)
  3. 如何打包这个自定义小部件,以便我可以像添加 QPushButtonQLineEdit 一样简单地将其添加到布局中?
  1. Will I able able to create such a complex/rich custom widget using PyQt5? Is it doable?
  2. Is this the correct approach to create the custom widget: first draw a square using QPainter (this is the blue square in the custom_widget_sketch), then add QLineEdits to dispaly the voltage (V) text, serial number (S/N) text and the Status text, add a QLabel for displaying the "V", "S/N" and "STATUS" labels in the custom widget, then draw the three circles: one each for the yellow, green and red LEDs, then use a combination of QVBoxLayout and QHBoxLayout to arrange the QLineEdits, QLabels, the square and the circles (LED indicators)
  3. How do I package this custom widget such that I can simply add it to a layout like I would add a QPushButton or a QLineEdit?

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

PS: The custom_widget_sketch also contains a line and a square with three lines inside it in the top left corner. This is to depict the connector for the LIPO battery. It may be too complex to implement that right now. So I would be happy even if I am able to implement everything other than these two elements

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

I have been through a few SO questions but they all refer to one tutorial, which is not my end goal.

我希望能提供任何代码片段、代码概要/要遵循的步骤或任何文章/教程的链接,这些文章/教程创建了类似于我希望创建的自定义小部件.

I would appreciate any code snippets, general outline of code/steps to follow or links to any articles/tutorials that create custom widgets similar to the one I wish to create.


解决方案

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

Python code for the custom widget I ended up creating. The widget looks as follows:

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 屏幕如下所示:

I was able to easily create 30 instances of the custom widget and add it to a QGridLayout as I posted in my question. The final GUI screen looks as follows:

相关文章