Python＋Qt（PySide）でカラーバーを作成

　PySideのQColorDialogの外観が普通なので、自分でカラーピッカーのWidgetを作成しました。ここではカラーバーについて紹介します。
　Python歴３ヶ月の私でもそれっぽいものが作れるのが、Python＆Qtのいいところです。

　ソースをGitHubに登録しました。
https://github.com/tokyo-noctambulist/colorpicker.git


(2017/03/07 更新) 
　　色指定時に、値を参照渡していたのをcopyに変更


###サンプル
![image](https://qiita-image-store.s3.amazonaws.com/0/164171/99ac4a95-907d-d5da-8653-70a4cc76bf4e.png)


　sample.pyでは、２つの色相のカラーバーを連動させて、別に透明度のカラーバーを表示しています。


***
###カラーバーの種類
　カラーバーの種類を、色相、彩度、明度、透明度から選択できます。
　PyPIに登録しました。pip等でinstallできます。


| 種類 | 値 |
|:-:|:-:|
|色相   | BAR_TYPE_HUE = 0  |
|彩度   | BAR_TYPE_SATURATION = 1  |
|明度   | BAR_TYPE_VALUE = 2  |
|透明度 | BAR_TYPE_ALPHA = 3  |

```python:function
pip install colorpicker #install

from colorpicker import *

QColorBarWidget(親, BARの種類(=未指定の時は色相))

widget = QColorBarWidget(self, BAR_TYPE_VALUE)
widget.setColor(QColor(0,0,0,0)) #色をセット
color = widget.getColor() #色を収得
colorBar.colorChanged.connect(onUpdateColor) # signal-slot
```

　PhotoshopやPainterのように複数のカラーピッカーを表示して、色を連動させる場合は、colorChangedのsignal()で色の変更を受け取って、他のWidgetと連動させてください。


***

```python:QColorBarWidget.py
from __future__ import division, print_function, unicode_literals, absolute_import

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

# TYPE
BAR_TYPE_HUE = 0
BAR_TYPE_SATURATION = 1
BAR_TYPE_VALUE = 2
BAR_TYPE_ALPHA = 3
BAR_TYPE_MAX = 4

Lupe_Color = [
    QColor(0, 0, 0, 255),
    QColor(0, 0, 0, 255),
    QColor(255, 255, 255, 255),
    QColor(255, 0, 0, 255)
]


class QColorBarWidget(QGraphicsView):
    colorChanged = Signal(str)

    def __init__(self, parent, type=BAR_TYPE_HUE):
        super(QColorBarWidget, self).__init__(parent)
        self.scene = QGraphicsScene(self)
        self.setScene(self.scene)
        self.width = 0

        self.type = type if type < BAR_TYPE_MAX else BAR_TYPE_HUE
        self.lupe_color = Lupe_Color[type]

        self.color = QColor()
        self.color.setHsv(0, 255, 255, 255)
        self.setColor(self.color)

        # BG
        pixmap = QPixmap(QSize(16, 16))
        tile = QPainter(pixmap)
        tile.save()
        brush1 = QBrush(QColor(128, 128, 128))
        brush2 = QBrush(QColor(168, 168, 168))
        tile.fillRect(0, 0, 8, 8, brush1)
        tile.fillRect(8, 8, 8, 8, brush1)
        tile.fillRect(8, 0, 8, 8, brush2)
        tile.fillRect(0, 8, 8, 8, brush2)
        tile.restore()
        tile.end()
        self.bg_brush = QBrush(pixmap)

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

    def drawForeground(self, painter, rect):
        """
        :type rect: QRectF
        :type painter: QPainter
        """
        painter.save()
        painter.translate(rect.center())
        painter.setRenderHint(QPainter.Antialiasing, True)
        self.width = rect.toRect().width()
        half_width = self.width / 2
        height = rect.toRect().height()
        half_height = height / 2
        # bar
        gradient = QLinearGradient(-half_width, 0, half_width, 0)
        self.makeGradient(gradient)
        painter.setBrush(gradient)
        painter.drawRect(-half_width, -half_height, self.width, height)
        # lupe
        painter.setPen(QPen(self.lupe_color, 1))
        painter.setBrush(QColor(0, 0, 0, 0))
        half_width = self.px - half_width
        painter.drawEllipse(half_width - 2, 2 - half_height, 5, 5)
        painter.fillRect(half_width, 6 - half_height, 1, height, QBrush(self.lupe_color))

        painter.restore()

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

    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.clickToColor(event)

    def clickToColor(self, event):
        self.px = event.pos().x()
        param = self.px / self.width
        param = 0 if param < 0 else param
        if self.type == BAR_TYPE_HUE:
            self.color.setHsv(360 * param, self.color.saturation(), self.color.value(), self.color.alpha())
        elif self.type == BAR_TYPE_SATURATION:
            self.color.setHsv(self.color.hue(), 255 * param, self.color.value(), self.color.alpha())
        elif self.type == BAR_TYPE_VALUE:
            self.color.setHsv(self.color.hue(), self.color.saturation(), 255 * param, self.color.alpha())
        else:  # alpha
            self.color.setAlphaF(param)

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

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

    def setColor(self, color):
        self.color = QColor(color)
        if self.type == BAR_TYPE_HUE:
            self.px = color.hue() * self.width / 360
        elif self.type == BAR_TYPE_SATURATION:
            self.px = color.saturation() * self.width / 255
        elif self.type == BAR_TYPE_VALUE:
            self.px = color.value() * self.width / 255
        else:  # alpha
            self.px = color.alpha() * self.width / 255
        self.scene.update()

    def makeGradient(self, gradient):
        color = QColor()
        if self.type == BAR_TYPE_HUE:
            for _ in range(11):
                color.setHsv(_ * 36, 255, 255, 255)
                gradient.setColorAt(0.1 * _, color)
        elif self.type == BAR_TYPE_SATURATION:
            color.setHsv(360, 0, 255, 255)
            gradient.setColorAt(0.0, color)
            color.setHsv(360, 255, 255, 255)
            gradient.setColorAt(1.0, color)
        elif self.type == BAR_TYPE_VALUE:
            color.setHsv(360, 255, 0, 255)
            gradient.setColorAt(0.0, color)
            color.setHsv(360, 255, 255, 255)
            gradient.setColorAt(1.0, color)
        else:  # alpha
            color.setRgb(255, 255, 255, 0)
            gradient.setColorAt(0.0, color)
            color.setRgb(255, 255, 255, 255)
            gradient.setColorAt(1.0, color)
        return
```

```python: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(300, 100)

        self.colorBar1 = QColorBarWidget(self)
        self.colorBar1.resize(150, 20)

        self.colorBar2 = QColorBarWidget(self, BAR_TYPE_HUE)
        self.colorBar2.resize(250, 30)
        self.colorBar2.move(0, 30)

        self.colorBar3 = QColorBarWidget(self, BAR_TYPE_ALPHA)
        self.colorBar3.resize(200, 20)
        self.colorBar3.move(50, 70)

        self.colorBar1.colorChanged.connect(self.onUpdateColor1)
        self.colorBar2.colorChanged.connect(self.onUpdateColor2)

    @Slot()
    def onUpdateColor1(self):
        color = self.colorBar1.getColor()
        self.colorBar2.setColor(color)

    @Slot()
    def onUpdateColor2(self):
        color = self.colorBar2.getColor()
        self.colorBar1.setColor(color)

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

if __name__ == "__main__":
    main()

```