pyqt4 自定義圓形指示燈控制元件
阿新 • • 發佈:2018-12-12
# -*- coding: utf-8 -*-# #------------------------------------------------------------------------------- # Name: 自定義圓形指示燈控制元件 #------------------------------------------------------------------------------- import sys from PyQt4.QtGui import * from PyQt4.QtCore import * allAttributes = [ 'colorOnBegin', 'colorOnEnd', 'colorOffBegin', 'colorOffEnd', 'colorBorderIn', 'colorBorderOut', 'radiusBorderOut', 'radiusBorderIn', 'radiusCircle'] 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), 500, 450, 400] allLabelNames = [ u'燈亮圓心顏色:', u'燈亮邊緣顏色:', u'燈滅圓心顏色:', u'燈滅邊緣顏色:', u'邊框內測顏色:', u'邊框外側顏色:', u'邊框外側半徑:', u'邊框內側半徑:', u'中間圓燈半徑:'] class MyLed(QAbstractButton): def __init__(self, parent=None): super(MyLed, self).__init__(parent) self.initUI() def initUI(self): self.setMinimumSize(24, 24) self.setCheckable(True) self.scaledSize = 1000.0 #為方便計算,將視窗短邊值對映為1000 self.setLedDefaultOption() def setLedDefaultOption(self): for attr, val in zip(allAttributes, allDefaultVal): setattr(self, attr, val) self.update() def setLedOption(self, opt='colorOnBegin', val=QColor(0,240,0)): if hasattr(self, opt): setattr(self, opt, val) self.update() def resizeEvent(self, evt): self.update() def paintEvent(self, evt): painter = QPainter(self) painter.setRenderHint(QPainter.Antialiasing, True) painter.setPen(QPen(Qt.black, 1)) realSize = min(self.width(), self.height()) #視窗的短邊 painter.translate(self.width()/2.0, self.height()/2.0) #原點平移到視窗中心 painter.scale(realSize/self.scaledSize, realSize/self.scaledSize) #縮放,視窗的短邊值對映為self.scaledSize gradient = QRadialGradient(QPointF(0, 0), self.scaledSize/2.0, QPointF(0, 0)) #輻射漸變 #畫邊框外圈和內圈 for color, radius in [(self.colorBorderOut, self.radiusBorderOut), #邊框外圈 (self.colorBorderIn, self.radiusBorderIn)]: #邊框內圈 gradient.setColorAt(1, color) painter.setBrush(QBrush(gradient)) painter.drawEllipse(QPointF(0, 0), radius, radius) # 畫內圓 gradient.setColorAt(0, self.colorOnBegin if self.isChecked() else self.colorOffBegin) gradient.setColorAt(1, self.colorOnEnd if self.isChecked() else self.colorOffEnd) painter.setBrush(QBrush(gradient)) painter.drawEllipse(QPointF(0, 0), self.radiusCircle, self.radiusCircle) class MyColorBox(QFrame): sigColorChanged = pyqtSignal(QColor) def __init__(self, parent=None, height=20, color=QColor(0,240,0)): super(MyColorBox, self).__init__(parent) self.setFixedHeight(height) self.setAutoFillBackground(True) self.setPalette(QPalette(color)) self.setFrameStyle(QFrame.Panel | QFrame.Sunken) def mousePressEvent(self, *args, **kwargs): color = QColorDialog.getColor(initial=self.palette().color(QPalette.Window)) if color.isValid(): self.setPalette(QPalette(color)) self.sigColorChanged.emit(color) def setColor(self, color): self.setPalette(QPalette(color)) class MyRadiusCtrl(QSpinBox): def __init__(self, parent=None, initVal=500): super(MyRadiusCtrl, self).__init__(parent) self.setRange(1, 500) self.setValue(initVal) class ConfigWnd(QFrame): def __init__(self, parent=None): super(ConfigWnd, self).__init__(parent) self.initUI() def initUI(self): self.setFrameStyle(QFrame.Box|QFrame.Sunken) mainLayout = QVBoxLayout(self) mainLayout.addWidget(self.createColorParaGroupBox(), 0) mainLayout.addSpacing(20) mainLayout.addWidget(self.createRadiusParaGroupBox(), 0) mainLayout.addStretch() mainLayout.addSpacing(20) self.restoreDefaultBtn = QPushButton(u'恢復預設設定') mainLayout.addWidget(self.restoreDefaultBtn, 0) mainLayout.addSpacing(10) self.animateBtn = QPushButton(u'開始動畫') self.animateBtn.setCheckable(True) mainLayout.addWidget(self.animateBtn, 0) def createColorParaGroupBox(self): colorParaGroupBox = QGroupBox(u"顏色引數設定", self) layout = QGridLayout(colorParaGroupBox) layout.setSpacing(10) self.allColorBoxCtrls = [] for name, color, row in zip(allLabelNames[:6], allDefaultVal[:6], range(6)): layout.addWidget(QLabel(name), row, 0) colorBox = MyColorBox(color=color) layout.addWidget(colorBox, row, 1) self.allColorBoxCtrls.append(colorBox) layout.setColumnStretch(0, 0) layout.setColumnStretch(1, 1) return colorParaGroupBox def createRadiusParaGroupBox(self): radiusParaGroupBox = QGroupBox(u"半徑設定(1~500)", self) layout = QGridLayout(radiusParaGroupBox) layout.setSpacing(10) self.allRadiusCtrls = [] for name, radius, row in zip(allLabelNames[6:], allDefaultVal[6:], range(3)): layout.addWidget(QLabel(name), row, 0) radiusCtrl = MyRadiusCtrl(initVal=radius) layout.addWidget(radiusCtrl, row, 1) self.allRadiusCtrls.append(radiusCtrl) layout.setColumnStretch(0, 0) layout.setColumnStretch(1, 1) return radiusParaGroupBox class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() self.initUI() self.initSlotFunc() self.cnt = 0 self.show() def initUI(self): self.resize(580, 350) self.setWindowTitle(u'自定義圓形指示燈控制元件') mainSplitter = self.createSplitter(style=Qt.Horizontal, parent=self, width=4) self.configWnd = ConfigWnd(mainSplitter) rightSplitter = self.createSplitter(style=Qt.Vertical, parent=mainSplitter, width=4) rightTopWnd = self.createSubWnd(rightSplitter) rightTopLayout = QVBoxLayout(rightTopWnd) rightTopLayout.setContentsMargins(60, 60, 60, 60) self.ledSingle = MyLed() self.ledSingle.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) rightTopLayout.addWidget(self.ledSingle) rightBottomWnd = self.createSubWnd(rightSplitter) rightBottomLayout = QHBoxLayout(rightBottomWnd) rightBottomLayout.setContentsMargins(10, 10, 10, 10) self.ledGroup = [] for i in range(8): led = MyLed() led.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.ledGroup.append(led) rightBottomLayout.addWidget(led) self.setSplitterStrechFactor(rightSplitter, 1, 0) self.setSplitterStrechFactor(mainSplitter, 0, 1) self.setCentralWidget(mainSplitter) def createSplitter(self, style=Qt.Horizontal, parent=None, width=3): splitter = QSplitter(style, parent) splitter.setHandleWidth(width) return splitter def setSplitterStrechFactor(self, splitter=None, factor1=1, factor2=1): #設定分割條兩部分的比例 splitter.setStretchFactor(0, factor1) splitter.setStretchFactor(1, factor2) def createSubWnd(self, parent=None): wnd = QFrame(parent) wnd.setFrameStyle(QFrame.Box | QFrame.Sunken) return wnd def initSlotFunc(self): self.configWnd.restoreDefaultBtn.clicked.connect(self.slotRestoreDefault) map(lambda x: x.sigColorChanged.connect(self.slotattributeChanged), self.configWnd.allColorBoxCtrls) #設定每個顏色控制元件的槽函式 map(lambda x: x.valueChanged.connect(self.slotattributeChanged), self.configWnd.allRadiusCtrls) #設定每個半徑控制元件的槽函式 self.configWnd.animateBtn.clicked.connect(self.slotAnimation) self.timer = QTimer() self.timer.timeout.connect(self.slotTimeout) #動畫定時器 def slotattributeChanged(self, val): allCtrls = self.configWnd.allColorBoxCtrls + self.configWnd.allRadiusCtrls idx = allCtrls.index(self.sender()) self.ledSingle.setLedOption(allAttributes[idx], val) def slotRestoreDefault(self): for colorBox, val in zip(self.configWnd.allColorBoxCtrls, allDefaultVal[:6]): colorBox.setColor(val) for radiusCtrl, val in zip(self.configWnd.allRadiusCtrls, allDefaultVal[6:]): radiusCtrl.setValue(val) self.ledSingle.setLedDefaultOption() def slotAnimation(self): if self.configWnd.animateBtn.isChecked(): self.cnt = 0 self.configWnd.animateBtn.setText(u'停止動畫') self.timer.start(300) else: self.configWnd.animateBtn.setText(u'開始動畫') self.timer.stop() def slotTimeout(self): self.cnt = self.cnt % 256 ledBits = QString('%1').arg(self.cnt, 8, 2, fillChar=QChar('0')) #將數值轉換為二進位制字串 for ledBit, led in zip(ledBits, self.ledGroup): led.setChecked(ledBit=='1') self.cnt += 1 def main(): app = QApplication(sys.argv) mainWnd = MainWindow() sys.exit(app.exec_()) if __name__ == '__main__': main()