1. 程式人生 > >pyqt4 自定義圓形指示燈控制元件

pyqt4 自定義圓形指示燈控制元件

# -*- 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()

在這裡插入圖片描述