[英]Creating a complex custom widget in PyQt5 and adding it to a 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
考慮到所有這些要求,我有以下問題:
LEDs
,然后使用組合QVBoxLayout
和 QHBoxLayout 來排列QLineEdits
、 QLabels
、正方形和圓形(LED 指示燈)QPushButton
或QLineEdit
一樣簡單地將它添加到布局中?PS:custom_widget_sketch 還包含一條線和一個在左上角內有三條線的正方形。 這是描述 LIPO 電池的連接器。 現在實施它可能太復雜了。 因此,即使我能夠實現這兩個元素以外的所有內容,我也會很高興
我經歷了一些 SO 問題,但它們都參考了一個教程,這不是我的最終目標。
我將不勝感激任何代碼片段、要遵循的代碼/步驟的大綱或任何文章/教程的鏈接,這些文章/教程創建類似於我希望創建的自定義小部件。
我最終創建的自定義小部件的 Python 代碼。 小部件如下所示:
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 屏幕如下所示:
沒有必要為藍色方塊使用 QPainter,因為您可以為整個小部件使用樣式表,訣竅是使用選擇器。
我嘗試創建您的小部件並使用此樣式表:
Battery {
background-color: white;
}
QFrame#statusFrame {
background-color: rgb(64, 112, 190);
}
QFrame#statusFrame QLabel {
color: white;
font-weight: bold;
font-size: 24pt;
}
QLineEdit {
border: 1px solid black;
font-size: 24pt;
}
#serialLabel {
font-weight: bold;
font-size: 16pt;
}
我創建了一個“容器”QWidget,狀態矩形實際上是一個帶有自己布局的QFrame,我將其命名為statusFrame
(您可以在設計器中設置它,或者通過setObjectName(str)
)。
通過使用對象名稱和子選擇器,我能夠通過使用QFrame#statusFrame QLabel
選擇器(這意味着“應用於作為 QFrame 子級的每個 QLabel”)為其標簽設置特定字體; 我還將serialLabel
對象名稱設置為 s/n 標簽,允許我設置不同的字體大小。
您可以通過代碼或使用設計器執行此操作,只需記住設置正確的對象名稱和父/子層次結構。
我也能夠繪制“連接器”部分,這需要為主小部件設置固定邊距:
class Battery(QtWidgets.QWidget):
connPath = QtGui.QPainterPath()
connPath.addRect(30, 10, 40, 28)
connPath.moveTo(30, 16)
connPath.lineTo(45, 16)
connPath.moveTo(30, 24)
connPath.lineTo(45, 24)
connPath.moveTo(30, 32)
connPath.lineTo(45, 32)
cablePen = QtGui.QColor(77, 122, 194)
def __init__(self):
QtWidgets.QWidget.__init__(self)
# the following is only if you create the whole widget from code,
# otherwise ensure to set both widget and layout contentsMargins
# accordingly in designer
self.setContentsMargins(25, 50, 10, 10)
layout = QtWidgets.QGridLayout()
self.setLayout(layout)
layout.setContentsMargins(0, 0, 0, 0)
# ...
def paintEvent(self, event):
qp = QtGui.QPainter(self)
qp.setRenderHints(qp.Antialiasing)
qp.translate(.5, .5)
qp.drawPath(self.connPath)
qp.setPen(self.cablePen)
cablePath = QtGui.QPainterPath()
cablePath.moveTo(30, 24)
top = self.statusFrame.geometry().top()
cablePath.quadTo(0, top + 20, 25, top + 40)
qp.drawPath(cablePath)
如您所見,它與您的幾乎相同。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.