HOME/Articles/

color_chooser

Article Outline

Example Python program color_chooser.py This program creates a PyQt GUI Python version 3.x or newer. To check the Python version use:

python --version

Modules

  • import sys, re
  • from PyQt5.QtCore import *
  • from PyQt5.QtGui import *
  • from PyQt5.QtWidgets import *

Classes

  • class SliderColorChooser(QWidget):

Methods

  • def init(self, parent=None):
  • def setupWidgetProperties(self):
  • def connectWidgets(self):
  • def setupLayout(self):
  • def updateHexColorBox(self):
  • def updateSlidersAndSpinners(self, hexCode):
  • def updateColorBox(self):
  • def main():

Code

Example Python PyQt program :

import sys, re
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *


class SliderColorChooser(QWidget):
    # Choose colors using a slider interface
    # TODO this currently uses standard Qt Widgets, maybe write some of our own?
    #      i.e. custom sliders that give a better color representation
    # TODO interface for alpha values?

    # Color modes
    EightBit = 1
    SixteenBit = 2
    TwentyFourBit = 3     # NOTE Only supported one now, no real option to change it anyways
    ThirtyTwoBit = 4

    # For formatting and printing
    HexCodeColorFormat = 'XXX'
    BGColorCSS = 'background-color:%s;'


    def __init__(self, parent=None):
        super(SliderColorChooser, self).__init__(parent)

        # the sliders, in a horizontal fashion
        self.rSlider = QSlider(Qt.Horizontal, self)
        self.gSlider = QSlider(Qt.Horizontal, self)
        self.bSlider = QSlider(Qt.Horizontal, self)

        # The spin boxex
        self.rSpinner = QSpinBox(self)
        self.gSpinner = QSpinBox(self)
        self.bSpinner = QSpinBox(self)

        # The color box and hex code
        self.colorBox = QFrame(self)
        self.colorBox.setFrameStyle(QFrame.Box)
        self.colorBox.setStyleSheet(self.BGColorCSS%'#000000')

        self.hexCodeBox = QLineEdit(self)
        self.hexCodeBox.setText('000000')

        self.badHexCode = QLabel('X')       # TODO replace with a better thing, like a caution sign
        self.badHexCode.hide()              # It should only show on a bad hex color

        # Setup the layout
        self.setupWidgetProperties()
        self.connectWidgets()
        self.setupLayout()

        print(self.rSpinner.minimumSizeHint())
        print(self.rSpinner.sizeHint())

        print(self.rSpinner.minimumSize())
        print(self.rSpinner.size())
        print(self.rSpinner.maximumSize())


    def setupWidgetProperties(self):
        # Organization function to set properties for the widgets

        # Mins & Maxes
        self.rSlider.setMinimum(0x00)
        self.gSlider.setMinimum(0x00)
        self.bSlider.setMinimum(0x00)

        self.rSpinner.setMinimum(0x00)
        self.gSpinner.setMinimum(0x00)
        self.bSpinner.setMinimum(0x00)

        self.rSlider.setMaximum(0xFF)
        self.gSlider.setMaximum(0xFF)
        self.bSlider.setMaximum(0xFF)

        self.rSpinner.setMaximum(0xFF)
        self.gSpinner.setMaximum(0xFF)
        self.bSpinner.setMaximum(0xFF)

        # Steps
        self.rSlider.setSingleStep(1)
        self.gSlider.setSingleStep(1)
        self.bSlider.setSingleStep(1)

        self.rSpinner.setSingleStep(1)
        self.gSpinner.setSingleStep(1)
        self.bSpinner.setSingleStep(1)

        self.rSlider.setPageStep(8)
        self.gSlider.setPageStep(8)
        self.bSlider.setPageStep(8)


    def connectWidgets(self):
        # Organizational function to connect up all of the widget's signals and slots

        # Make the sliders change the spinners
        self.rSlider.valueChanged[int].connect(self.rSpinner.setValue)
        self.gSlider.valueChanged[int].connect(self.gSpinner.setValue)
        self.bSlider.valueChanged[int].connect(self.bSpinner.setValue)

        # Make the spinners change the sliders
        self.rSpinner.valueChanged[int].connect(self.rSlider.setValue)
        self.gSpinner.valueChanged[int].connect(self.gSlider.setValue)
        self.bSpinner.valueChanged[int].connect(self.bSlider.setValue)

        # Make the sliders & spinners change the contents in the box
        self.rSlider.valueChanged.connect(self.updateHexColorBox)
        self.gSlider.valueChanged.connect(self.updateHexColorBox)
        self.bSlider.valueChanged.connect(self.updateHexColorBox)
        self.rSpinner.valueChanged.connect(self.updateHexColorBox)
        self.gSpinner.valueChanged.connect(self.updateHexColorBox)
        self.bSpinner.valueChanged.connect(self.updateHexColorBox)

        # Make the box change the spinners and the box
        self.hexCodeBox.textEdited[str].connect(self.updateSlidersAndSpinners)

        # Make all of the widgets update the color in the box
        self.rSlider.valueChanged.connect(self.updateColorBox)
        self.gSlider.valueChanged.connect(self.updateColorBox)
        self.bSlider.valueChanged.connect(self.updateColorBox)
        self.rSpinner.valueChanged.connect(self.updateColorBox)
        self.gSpinner.valueChanged.connect(self.updateColorBox)
        self.bSpinner.valueChanged.connect(self.updateColorBox)
        self.hexCodeBox.textEdited.connect(self.updateColorBox)


    def setupLayout(self):
        # Organizational function to setup the layout of the widget
        layout = QGridLayout(self)

        # Labels
        layout.addWidget(QLabel('R', self), 0, 0)
        layout.addWidget(QLabel('G', self), 1, 0)
        layout.addWidget(QLabel('B', self), 2, 0)

        # Sliders
        layout.addWidget(self.rSlider, 0, 1)
        layout.addWidget(self.gSlider, 1, 1)
        layout.addWidget(self.bSlider, 2, 1)

        # Spinners
        layout.addWidget(self.rSpinner, 0, 2)
        layout.addWidget(self.gSpinner, 1, 2)
        layout.addWidget(self.bSpinner, 2, 2)

        # colors representations
        layout.addWidget(self.colorBox, 0, 3, 2, 2)
        layout.addWidget(self.hexCodeBox, 2, 3)
        layout.addWidget(self.badHexCode, 2, 4)

        self.setLayout(layout)

        # TODO set fixed width on all widgets


    @pyqtSlot()
    def updateHexColorBox(self):
        # When a slider or spinner changes, this will update the hex value in the box
        # Doesn't really matter where we get the colors from, they shoould all be the same
        rVal = self.rSlider.value()
        gVal = self.gSlider.value()
        bVal = self.bSlider.value()

        # Change text and hide error
        self.hexCodeBox.setText(self.HexCodeColorFormat%(rVal, gVal, bVal))
        self.badHexCode.hide()


    @pyqtSlot(str)
    def updateSlidersAndSpinners(self, hexCode):
        # Change the values of the slider and the spinners based upon the hex code
        hexCode = hexCode.strip().upper()       # Use upper case and strip

        # Do nothing if we don't have anything
        if len(hexCode) == 0:
            return

        # For our pound signers
        if hexCode[0] == '#':
            hexCode = hexCode[1:]

        # Make sure that we only have six chars
        if len(hexCode) != 6:
            self.badHexCode.show()
            return

        # Make sure that it's only hex
        x = re.compile('[0-9A-F]+')
        if x.fullmatch(hexCode) == None:
            self.badHexCode.show()
            return

        # Peel out each color
        rVal = int(hexCode[:2], 16)
        gVal = int(hexCode[2:4], 16)
        bVal = int(hexCode[4:], 16)

        # Set the spinners and the sliders
        self.rSlider.setValue(rVal)
        self.gSlider.setValue(gVal)
        self.bSlider.setValue(bVal)
        self.rSpinner.setValue(rVal)
        self.gSpinner.setValue(gVal)
        self.bSpinner.setValue(bVal)


    @pyqtSlot()
    def updateColorBox(self):
        # Get colors from sliders, not that it matters
        rVal = self.rSlider.value()
        gVal = self.gSlider.value()
        bVal = self.bSlider.value()

        # Build the hex code color and set the stylesheet
        hexCodeColor = '#' + self.HexCodeColorFormat%(rVal, gVal, bVal)
        self.colorBox.setStyleSheet(self.BGColorCSS%hexCodeColor)




def main():
    app = QApplication(sys.argv)
    scc = SliderColorChooser()
    scc.show()

    sys.exit(app.exec_())


main()