Create a color picker for the color wheel with Python + Qt (PySide)

It was unlikely and unexpected, so I created a widget for the color picker of the color wheel. Initially, when I described low-level processing with C language glue, it became slow motion when enlarged and displayed in the operation check for high resolution monitor, and it works without problems if I optimize the Qt library and Python style It came to be. If you use Python, you should learn the Python style.

The gradation of the color box of saturation and lightness in the center is realized by synthesizing the two gradations of saturation and transparency. This method was introduced on overseas bulletin boards.

I registered with PyPI. You can install it with pip etc. I registered the source on GitHub. https://github.com/tokyo-noctambulist/colorpicker.git

(Updated on 2017/03/07) Fixed a bug that was destroying the α value. Changed to tile BG to reflect α value on color sample and color chart Change value passed by reference to copy when specifying color

sample

image

In sample.py, the two hue circles are linked and displayed.


Brief explanation

I registered with PyPI. You can install it with pip etc.

function


pip install colorpicker #install

from colorpicker import *

colorCircle = QHueCircleWidget(self)
color = colorCircle.getColor() #Get color
colorCircle.setColor(QColor(255,100,10,200)) #Set color

colorCircle.colorChanged.connect(onUpdateColor) #signal-slot

You can resize it with resize (). However, it will not work properly unless the aspect ratio is set to 1: 1. (Not compatible with elliptical state orz)


QHueCircleWidget.py


# coding:utf-8
from __future__ import division, print_function, unicode_literals, absolute_import
# noinspection PyUnresolvedReferences
from future_builtins import *

from PySide.QtGui import *
from PySide.QtCore import *

import math

class QHueCircleWidget(QGraphicsView):
    PRESS_NONE = 0
    PRESS_BOX = 1
    PRESS_CIRCLE = 2

    colorChanged = Signal(str)

    def __init__(self, parent):
        super(QHueCircleWidget, self).__init__(parent)
        self.scene = QGraphicsScene(self)
        self.setScene(self.scene)
        self.rectF = None
        self.press_mode = self.PRESS_NONE
        self.color = QColor()
        self.color.setHsv(0, 255, 255, 255)
        self.setColor(self.color)
        self.bg_brush = QBrush(self.create_bg_pixmap())

        # self.setFixedSize(200,200)
        self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        self.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
        self.setMinimumSize(200, 200)


    def drawBackground(self, painter, rect):
        """
        :type rect: QRectF
        :type painter: QPainter
        """
        painter.save()

        painter.translate(rect.center())
        painter.setRenderHint(QPainter.Antialiasing, True)
        self.rectF = rect
        self.rectToParam()
        painter.setPen(QPen(Qt.black, 1))
        # draw select color
        painter.setBrush(self.bg_brush)
        painter.drawEllipse(-self.half_width, -self.half_height, self.width / 8, self.height / 8)
        painter.setBrush(self.color)
        painter.drawEllipse(-self.half_width, -self.half_height, self.width / 8, self.height / 8)
        # hue color circle
        painter.setBrush(self.bg_brush)
        painter.drawEllipse(0 - self.half_width, 0 - self.half_height, self.width, self.height)
        color = QColor()
        gradient = QConicalGradient(0, 0, 0)
        for _ in range(11):
            color.setHsv((10 - _) * 36, 255, 255, self.color.alpha())
            gradient.setColorAt(0.1 * _, color)
        painter.setBrush(gradient)
        painter.drawEllipse(0 - self.half_width, 0 - self.half_height, self.width, self.height)
        # center delete circle
        mini_circle_width = self.width * 3 / 4
        mini_circle_height = self.height * 3 / 4
        painter.setBrush(QPalette().brush(QPalette.Midlight))
        painter.drawEllipse(0 - mini_circle_width / 2, 0 - mini_circle_height / 2 , mini_circle_width, mini_circle_height)
        # center box saturation
        gradient = QLinearGradient(-self.quarter_width, 0, self.quarter_width, 0)
        color.setHsv(self.color.hue(), 0, 255, 255)
        gradient.setColorAt(0.0, color)
        color.setHsv(self.color.hue(), 255, 255, 255)
        gradient.setColorAt(1.0, color)
        painter.setBrush(gradient)
        painter.drawRect(-self.quarter_width, -self.quarter_height, self.half_width, self.half_height)

        painter.restore()

    def drawForeground(self, painter, rect):
        """
        :type rect: QRectF
        :type painter: QPainter
        """
        painter.save()

        painter.translate(rect.center())
        painter.setRenderHint(QPainter.Antialiasing, True)
        # center box value
        gradient = QLinearGradient(0, -self.quarter_height, 0, self.quarter_height)
        color = QColor()
        color.setHsv(0, 0, 0, 0)
        gradient.setColorAt(0.0, color)
        color.setHsv(0, 0, 0, 255)
        gradient.setColorAt(1.0, color)
        painter.setBrush(gradient)
        painter.drawRect(-self.quarter_width, -self.quarter_height, self.half_width, self.half_height)
        # lupe for Saturation / Value
        painter.setPen(QPen(QColor(255, 255, 255, 255), 1))
        painter.drawEllipse(self.sv_x - 3, self.sv_y - 3, 7, 7)
        painter.setPen(QPen(QColor(0, 0, 0, 255), 1))
        painter.drawEllipse(self.sv_x - 2, self.sv_y - 2, 5, 5)
        # lupe for Hue
        painter.setPen(QPen(QColor(0, 0, 0, 255), 1))
        painter.setBrush(QColor(255, 255, 255, 0))
        painter.rotate(self.color.hue())
        painter.drawRect(self.width * 3 / 8, -4, self.width / 8, 8)

        painter.restore()

    def mouseMoveEvent(self, event):
        self.clickToColor(event)

    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.rectToParam()
            if self.hitBox(event.x(), event.y()):
                self.press_mode = self.PRESS_BOX
                self.clickToColor(event)
            elif self.hitCircle(event.x(), event.y()):
                self.press_mode = self.PRESS_CIRCLE
                self.clickToColor(event)
            else:
                self.press_mode = self.PRESS_NONE

    def clickToColor(self, event):
        if self.press_mode == self.PRESS_BOX:
            self.clickToBox(event)
        elif self.press_mode == self.PRESS_CIRCLE:
            self.clickCircle(event)

        self.colorChanged.emit('colorChanged')
        self.scene.update()

    def hitBox(self, x, y):
        rect = QRect(self.quarter_width, self.quarter_height, self.width * 2 / 4, self.height * 2 / 4)
        return rect.contains(x, y)

    def hitCircle(self, x, y):
        path = QPainterPath()
        path.addEllipse(0, 0, self.width, self.height)

        path2 = QPainterPath()
        path2.addEllipse(self.quarter_width / 2., self.quarter_height / 2., self.width / 4. * 3., self.height / 4. * 3.)

        pos = QPointF(x, y)
        return path.contains(pos) and not path2.contains(pos)

    def clickToBox(self, event):
        if not self.hitBox(event.x(), event.y()):
            return

        x = event.x()
        y = event.y()

        col_sat = 255 * (x - self.quarter_width) / self.half_width
        col_sat = 0 if col_sat < 0 else col_sat
        col_sat = 255 if col_sat > 255 else col_sat

        col_val = 255 * (self.half_height - (y - self.quarter_height)) / self.half_height
        col_val = 0 if col_val < 0 else col_val
        col_val = 255 if col_val > 255 else col_val

        self.color.setHsv(
            self.color.hue(),
            col_sat,
            col_val,
            self.color.alpha()
        )
        self.sv_x = x - self.half_width
        self.sv_y = y - self.half_height

    def clickCircle(self, event):
        x = event.x()
        y = event.y()

        k = int(math.degrees(math.atan2(x - self.half_width, self.half_height - y)))
        self.color.setHsv(
            (k - 90) % 360,
            self.color.saturation(),
            self.color.value(),
            self.color.alpha()
        )
        self.hue_x = x - self.half_width
        self.hue_y = y - self.half_height

    def getColor(self):
        return(self.color)

    def setColor(self, color):
        self.color = QColor(color)
        if self.rectF == None:
            self.sv_x = 0
            self.sv_y = 0
            self.hue_x = 0
            self.hue_y = 0
            self.scene.update()
        else:
            self.rectToParam()
            # SV
            self.sv_x = color.saturation() * self.half_width / 255 - self.quarter_width
            self.sv_y = (255 - color.value()) * self.half_height / 255 - self.quarter_height
            # Hue
            radian = ((color.hue()) % 360) * math.pi / 180
            self.hue_x = math.cos(radian) * self.half_width
            self.hue_y = math.sin(radian) * self.half_height
        self.scene.update()

    def rectToParam(self):
        if self.rectF == None:
            rect = QRectF(0, 0, 200, 200)
        else:
            rect = self.rectF

        self.width = rect.toRect().width()
        self.half_width = self.width / 2
        self.quarter_width = self.width / 4

        self.height = rect.toRect().height()
        self.half_height = self.height / 2
        self.quarter_height = self.height / 4

    @staticmethod
    def create_bg_pixmap(color1=None, color2=None):
        """
        :rtype: QPixmap
        """
        pixmap = QPixmap(QSize(16, 16))
        color1 = color1 or QColor(128, 128, 128)
        color2 = color2 or QColor(168, 168, 168)

        painter = QPainter(pixmap)
        painter.save()
        brush1 = QBrush(color1)
        brush2 = QBrush(color2)
        painter.fillRect(0, 0, 8, 8, brush1)
        painter.fillRect(8, 8, 8, 8, brush1)
        painter.fillRect(8, 0, 8, 8, brush2)
        painter.fillRect(0, 8, 8, 8, brush2)
        painter.restore()
        painter.end()

        return pixmap

sample.py


from __future__ import division, print_function, unicode_literals, absolute_import

from PySide.QtGui import *
from PySide.QtCore import *
import sys

class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.resize(700, 500)

        self.colorCircle1 = QHueCircleWidget(self)

        self.colorCircle2 = QHueCircleWidget(self)
        self.colorCircle2.resize(400, 400)
        self.colorCircle2.move(260, 50)

        # alpha color sample
        color = QColor(255, 0, 0, 100)
        self.colorCircle1.setColor(color)
        self.colorCircle2.setColor(color)

        self.colorCircle1.colorChanged.connect(self.onUpdateColor1)
        self.colorCircle2.colorChanged.connect(self.onUpdateColor2)

    @Slot()
    def onUpdateColor1(self):
        color = self.colorCircle1.getColor()
        self.colorCircle2.setColor(color)

    @Slot()
    def onUpdateColor2(self):
        color = self.colorCircle2.getColor()
        self.colorCircle1.setColor(color)

def main():
    app = QApplication(sys.argv)
    main_window = MainWindow()
    main_window.show()
    sys.exit(app.exec_())

if __name__ == "__main__":
    main()

Recommended Posts

Create a color picker for the color wheel with Python + Qt (PySide)
Create a color bar with Python + Qt (PySide)
Create a color-specified widget with Python + Qt (PySide)
Create a Twitter BOT with the GoogleAppEngine SDK for Python
Create a LINE BOT with Minette for Python
Fill the background with a single color with OpenCV2 + Python
Create a Layer for AWS Lambda Python with Docker
Create a directory with python
Create a child account for connect with Stripe in Python
[Python] Create a screen for HTTP status code 403/404/500 with Django
Create a virtual environment with Python!
Create a striped illusion with gamma correction for Python3 and openCV3
The story of making a standard driver for db with python.
Create a USB boot Ubuntu with a Python environment for data analysis
Create a compatibility judgment program with the random module of python.
Create a Python function decorator with Class
Build a blockchain with Python ① Create a class
Create a dummy image with Python + PIL.
Let's create a virtual environment for Python
[Python] Create a virtual environment with Anaconda
Let's create a free group with Python
Search the maze with the python A * algorithm
Make Qt for Python app a desktop app
Create a word frequency counter with Python 3.4
Create a Python development environment locally at the fastest speed (for beginners)
[Introduction to Udemy Python3 + Application] 47. Process the dictionary with a for statement
Create a record with attachments in KINTONE using the Python requests module
[Python] Get the files in a folder with Python
Created a Python wrapper for the Qiita API
Get a ticket for a theme park with python
Use logger with Python for the time being
Procedure for creating a LineBot made with Python
Create a page that loads infinitely with python
[Note] Create a one-line timezone class with python
You can easily create a GUI with Python
Create a python3 build environment with Sublime Text3
Create a dashboard for Network devices with Django!
Python: Prepare a serializer for the class instance:
Steps to create a Twitter bot with python
Commands for creating a python3 environment with virtualenv
Create a decision tree from 0 with Python (1. Overview)
Create a new page in confluence with Python
Create a Photoshop format file (.psd) with python
Create a Python console application easily with Click
Create a translation tool with the Translate Toolkit
Create a simple reception system with the Python serverless framework Chalice and Twilio
Turn multiple lists with a for statement at the same time in Python
[Introduction to Python] How to get the index of data with a for statement
Create a clean DB for testing with FastAPI and unittest the API with pytest
Automate background removal for the latest portraits in a directory with Python and API
Create a Python module
Run with CentOS7 + Apache2.4 + Python3.6 for the time being
How to create a submenu with the [Blender] plugin
[CRUD] [Django] Create a CRUD site using the Python framework Django ~ 1 ~
[Python] 2 Create a risk-return map for your asset portfolio
Build a python environment for each directory with pyenv-virtualenv
[Python] Create a ValueObject with a complete constructor using dataclasses
Create a Todo app with the Django REST framework
Why not create a stylish table easily with Python?
Create a python development environment with vagrant + ansible + fabric
Make a breakpoint on the c layer with python