PyQt4自定义控件----指示灯控件

程序中演示了PyQt中编程实现自定义圆形指示灯控件的方法,通过程序界面可改变其属性值并能实时看到指示灯的外观变化情况,同时,在定时器中也实现了一个类似跑马灯效果的功能。

例子虽小,但涉及的编程点挺多,包括:自定义控件(圆形指示灯、颜色选择框等)、分割条、布局、辐射渐变画刷、定时器、自定义信号(pyqtSignal)、列表、setattr、hasattr、for...in、zip、map、十进制转二进制等等。

代码如下:

  1 # -*- coding: utf-8 -*-#
  2 
  3 #-------------------------------------------------------------------------------
  4 # Name:         自定义圆形指示灯控件
  5 # Description:  
  6 # Author:       lgk
  7 # Date:         2018/7/05
  8 #-------------------------------------------------------------------------------
  9 
 10 import sys
 11 from PyQt4.QtGui import *
 12 from PyQt4.QtCore import *
 13 
 14 allAttributes =   [  'colorOnBegin', 'colorOnEnd', 'colorOffBegin', 'colorOffEnd', 'colorBorderIn', 'colorBorderOut',
 15                      'radiusBorderOut', 'radiusBorderIn', 'radiusCircle']
 16 allDefaultVal =   [ QColor(0, 240, 0), QColor(0, 160, 0), QColor(0, 68, 0), QColor(0, 28, 0), QColor(140, 140, 140), QColor(100, 100, 100),
 17                     500, 450, 400]
 18 allLabelNames =   [ u'灯亮圆心颜色:', u'灯亮边缘颜色:', u'灯灭圆心颜色:', u'灯灭边缘颜色:', u'边框内测颜色:', u'边框外侧颜色:',
 19                     u'边框外侧半径:', u'边框内侧半径:', u'中间圆灯半径:']
 20 
 21 class MyLed(QAbstractButton):
 22     def __init__(self, parent=None):
 23         super(MyLed, self).__init__(parent)
 24         self.initUI()
 25 
 26     def initUI(self):
 27         self.setMinimumSize(24, 24)
 28         self.setCheckable(True)
 29         self.scaledSize = 1000.0    #为方便计算,将窗口短边值映射为1000
 30         self.setLedDefaultOption()
 31 
 32     def setLedDefaultOption(self):
 33         for attr, val in zip(allAttributes, allDefaultVal):
 34             setattr(self, attr, val)
 35         self.update()
 36 
 37     def setLedOption(self, opt='colorOnBegin', val=QColor(0,240,0)):
 38         if hasattr(self, opt):
 39             setattr(self, opt, val)
 40             self.update()
 41 
 42     def resizeEvent(self, evt):
 43         self.update()
 44 
 45     def paintEvent(self, evt):
 46         painter = QPainter(self)
 47         painter.setRenderHint(QPainter.Antialiasing, True)
 48         painter.setPen(QPen(Qt.black, 1))
 49 
 50         realSize = min(self.width(), self.height())                         #窗口的短边
 51         painter.translate(self.width()/2.0, self.height()/2.0)              #原点平移到窗口中心
 52         painter.scale(realSize/self.scaledSize, realSize/self.scaledSize)   #缩放,窗口的短边值映射为self.scaledSize
 53         gradient = QRadialGradient(QPointF(0, 0), self.scaledSize/2.0, QPointF(0, 0))   #辐射渐变
 54 
 55         #画边框外圈和内圈
 56         for color, radius in [(self.colorBorderOut, self.radiusBorderOut),  #边框外圈
 57                                (self.colorBorderIn, self.radiusBorderIn)]:   #边框内圈
 58             gradient.setColorAt(1, color)
 59             painter.setBrush(QBrush(gradient))
 60             painter.drawEllipse(QPointF(0, 0), radius, radius)
 61 
 62         # 画内圆
 63         gradient.setColorAt(0, self.colorOnBegin if self.isChecked() else self.colorOffBegin)
 64         gradient.setColorAt(1, self.colorOnEnd if self.isChecked() else self.colorOffEnd)
 65         painter.setBrush(QBrush(gradient))
 66         painter.drawEllipse(QPointF(0, 0), self.radiusCircle, self.radiusCircle)
 67 
 68 class MyColorBox(QFrame):
 69     sigColorChanged = pyqtSignal(QColor)
 70     def __init__(self, parent=None, height=20, color=QColor(0,240,0)):
 71         super(MyColorBox, self).__init__(parent)
 72         self.setFixedHeight(height)
 73         self.setAutoFillBackground(True)
 74         self.setPalette(QPalette(color))
 75         self.setFrameStyle(QFrame.Panel | QFrame.Sunken)
 76 
 77     def mousePressEvent(self, *args, **kwargs):
 78         color = QColorDialog.getColor(initial=self.palette().color(QPalette.Window))
 79         if color.isValid():
 80             self.setPalette(QPalette(color))
 81             self.sigColorChanged.emit(color)
 82 
 83     def setColor(self, color):
 84         self.setPalette(QPalette(color))
 85 
 86 class MyRadiusCtrl(QSpinBox):
 87     def __init__(self, parent=None, initVal=500):
 88         super(MyRadiusCtrl, self).__init__(parent)
 89         self.setRange(1, 500)
 90         self.setValue(initVal)
 91 
 92 class ConfigWnd(QFrame):
 93     def __init__(self, parent=None):
 94         super(ConfigWnd, self).__init__(parent)
 95         self.initUI()
 96 
 97     def initUI(self):
 98         self.setFrameStyle(QFrame.Box|QFrame.Sunken)
 99 
100         mainLayout = QVBoxLayout(self)
101         mainLayout.addWidget(self.createColorParaGroupBox(), 0)
102         mainLayout.addSpacing(20)
103         mainLayout.addWidget(self.createRadiusParaGroupBox(), 0)
104         mainLayout.addStretch()
105         mainLayout.addSpacing(20)
106         self.restoreDefaultBtn = QPushButton(u'恢复默认设置')
107         mainLayout.addWidget(self.restoreDefaultBtn, 0)
108         mainLayout.addSpacing(10)
109         self.animateBtn = QPushButton(u'开始动画')
110         self.animateBtn.setCheckable(True)
111         mainLayout.addWidget(self.animateBtn, 0)
112 
113     def createColorParaGroupBox(self):
114         colorParaGroupBox = QGroupBox(u"颜色参数设置", self)
115         layout = QGridLayout(colorParaGroupBox)
116         layout.setSpacing(10)
117 
118         self.allColorBoxCtrls = []
119         for name, color, row in zip(allLabelNames[:6], allDefaultVal[:6], range(6)):
120             layout.addWidget(QLabel(name), row, 0)
121             colorBox = MyColorBox(color=color)
122             layout.addWidget(colorBox, row, 1)
123             self.allColorBoxCtrls.append(colorBox)
124 
125         layout.setColumnStretch(0, 0)
126         layout.setColumnStretch(1, 1)
127         return colorParaGroupBox
128 
129     def createRadiusParaGroupBox(self):
130         radiusParaGroupBox = QGroupBox(u"半径设置(1~500)", self)
131         layout = QGridLayout(radiusParaGroupBox)
132         layout.setSpacing(10)
133 
134         self.allRadiusCtrls = []
135         for name, radius, row in zip(allLabelNames[6:], allDefaultVal[6:], range(3)):
136             layout.addWidget(QLabel(name), row, 0)
137             radiusCtrl = MyRadiusCtrl(initVal=radius)
138             layout.addWidget(radiusCtrl, row, 1)
139             self.allRadiusCtrls.append(radiusCtrl)
140 
141         layout.setColumnStretch(0, 0)
142         layout.setColumnStretch(1, 1)
143         return radiusParaGroupBox
144 
145 class MainWindow(QMainWindow):
146     def __init__(self):
147         super(MainWindow, self).__init__()
148         self.initUI()
149         self.initSlotFunc()
150         self.cnt = 0
151         self.show()
152 
153     def initUI(self):
154         self.resize(580, 350)
155         self.setWindowTitle(u'自定义圆形指示灯控件')
156 
157         mainSplitter = self.createSplitter(style=Qt.Horizontal, parent=self, width=4)
158 
159         self.configWnd = ConfigWnd(mainSplitter)
160 
161         rightSplitter = self.createSplitter(style=Qt.Vertical, parent=mainSplitter, width=4)
162 
163         rightTopWnd = self.createSubWnd(rightSplitter)
164         rightTopLayout = QVBoxLayout(rightTopWnd)
165         rightTopLayout.setContentsMargins(60, 60, 60, 60)
166         self.ledSingle = MyLed()
167         self.ledSingle.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
168         rightTopLayout.addWidget(self.ledSingle)
169 
170         rightBottomWnd = self.createSubWnd(rightSplitter)
171         rightBottomLayout = QHBoxLayout(rightBottomWnd)
172         rightBottomLayout.setContentsMargins(10, 10, 10, 10)
173         self.ledGroup = []
174         for i in range(8):
175             led = MyLed()
176             led.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
177             self.ledGroup.append(led)
178             rightBottomLayout.addWidget(led)
179 
180         self.setSplitterStrechFactor(rightSplitter, 1, 0)
181         self.setSplitterStrechFactor(mainSplitter, 0, 1)
182         self.setCentralWidget(mainSplitter)
183 
184     def createSplitter(self, style=Qt.Horizontal, parent=None, width=3):
185         splitter = QSplitter(style, parent)
186         splitter.setHandleWidth(width)
187         return splitter
188 
189     def setSplitterStrechFactor(self, splitter=None, factor1=1, factor2=1): #设置分割条两部分的比例
190         splitter.setStretchFactor(0, factor1)
191         splitter.setStretchFactor(1, factor2)
192 
193     def createSubWnd(self, parent=None):
194         wnd = QFrame(parent)
195         wnd.setFrameStyle(QFrame.Box | QFrame.Sunken)
196         return wnd
197 
198     def initSlotFunc(self):
199         self.configWnd.restoreDefaultBtn.clicked.connect(self.slotRestoreDefault)
200         map(lambda x: x.sigColorChanged.connect(self.slotattributeChanged), self.configWnd.allColorBoxCtrls)   #设定每个颜色控件的槽函数
201         map(lambda x: x.valueChanged.connect(self.slotattributeChanged), self.configWnd.allRadiusCtrls)        #设定每个半径控件的槽函数
202         self.configWnd.animateBtn.clicked.connect(self.slotAnimation)
203         self.timer = QTimer()
204         self.timer.timeout.connect(self.slotTimeout) #动画定时器
205 
206     def slotattributeChanged(self, val):
207         allCtrls = self.configWnd.allColorBoxCtrls + self.configWnd.allRadiusCtrls
208         idx = allCtrls.index(self.sender())
209         self.ledSingle.setLedOption(allAttributes[idx], val)
210 
211     def slotRestoreDefault(self):
212         for colorBox, val in zip(self.configWnd.allColorBoxCtrls, allDefaultVal[:6]):
213             colorBox.setColor(val)
214 
215         for radiusCtrl, val in zip(self.configWnd.allRadiusCtrls, allDefaultVal[6:]):
216             radiusCtrl.setValue(val)
217 
218         self.ledSingle.setLedDefaultOption()
219 
220     def slotAnimation(self):
221         if self.configWnd.animateBtn.isChecked():
222             self.cnt = 0
223             self.configWnd.animateBtn.setText(u'停止动画')
224             self.timer.start(300)
225         else:
226             self.configWnd.animateBtn.setText(u'开始动画')
227             self.timer.stop()
228 
229     def slotTimeout(self):
230         self.cnt = self.cnt % 256
231         ledBits = QString('%1').arg(self.cnt, 8, 2, fillChar=QChar('0'))    #将数值转换为二进制字符串
232         for ledBit, led in zip(ledBits, self.ledGroup):
233             led.setChecked(ledBit=='1')
234         self.cnt += 1
235 
236 def main():
237     app = QApplication(sys.argv)
238     mainWnd = MainWindow()
239     sys.exit(app.exec_())
240 
241 if __name__ == '__main__':
242     main()
 
原文地址:https://www.cnblogs.com/luke0011/p/9271371.html