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

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

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

猜你喜欢

转载自www.cnblogs.com/luke0011/p/9271371.html