QML(Qt)でカラーピッカーを作ってみた

お絵かきツールとかで色を選ぶアレです。
こんな感じ

/// スクリーンショット ///
 


/// 今回のポイント ///
・グラデーションは縦方向にしかできない。
・クリップは真四角しかできない。


グラデーションは縦方向にしかできない
パフォーマンスの関係で現状縦方向のみのサポートだそうです。
横向きにしたい場合はグラデーションをかけるエレメントを「rotation」プロパティで90度回転させる必要があります。(ヘルプに書いてありますけどね。)
ただし、この回転にはクセがあるので注意です。
レイアウト的な縦横サイズはそのままで見た目だけ回転するので縦横のサイズが違う場合におかしなことになります。
なので、目的のサイズのItemの中に回転したRectangleを置くなど工夫が必要です。


クリップは真四角しかできない
これもパフォーマンスの関係とヘルプに書いてあるのですが。
例えば、Rectangleの中にImageを全体的に貼りつけて、Rectangleを「radius」プロパティで角丸にすると画像の角がはみ出ます。
なので、「clip」プロパティをtrueにすればOKかと思いきやはみ出ます。
サポートされてないので当たり前ですがそおいうことなので注意です。


機能的な話では以下の3点でしょうか。
・色を作成するバーのみを作って見本は別で自由にできる。
・バーはどのあたりを選ぶとどんな色になるかわかる表現をする。
・アルファのバーはプロパティで消せる
・ColorPikcker全体の横幅にあわせて自動で配置されます。
・バーの1つずつの幅を調整したい場合は、rowSpacingを調整する。


サンプルについて
今回のサンプルはあくまでバーの部分だけです。
色見本は別で作ってます。

余談ですが、プロパティバインディングほんとイイヨネ!って内容です。
今までの「作ってみたシリーズ」でも使いまくってますけど。
QMLの強みですね。


GooleCodeにコード置いてあります。
Componentsサンプル


使い方
01.import QtQuick 1.0
02.import "Components"
03. 
04.Rectangle {
05.    width: 360
06.    height: 360
07. 
08.    Column{
09.        anchors.fill: parent
10.        anchors.margins: 5
11.        spacing: 5
12. 
13.        Row{
14.            Text{
15.                anchors.verticalCenter: parent.verticalCenter
16.                text: "色見本"
17.            }
18.            Rectangle{
19.                width: 50
20.                height: 50
21.                color: _colorPicker.value
22.            }
23.        }
24. 
25. 
26.        ColorPicker{
27.            id: _colorPicker
28.            useAlpha: true
29.        }
30.    }
31. 
32.}


バーをまとめた全体
001.// ColorPicker.qml
002. 
003.import QtQuick 1.0
004. 
005.Rectangle {
006.    id: _root
007.    width: 200
008.    height: 150
009. 
010.    // トータルの色
011.    property color value: Qt.rgba(_barRed.value
012.                                  , _barGreen.value
013.                                  , _barBlue.value
014.                                  , _barAlpha.value)
015.    // 個別の色
016.    property alias red: _barRed.value
017.    property alias green: _barGreen.value
018.    property alias blue: _barBlue.value
019.    property alias alpha: _barAlpha.value
020. 
021.    // バーの横幅(これは外から操作すべきじゃない)
022.    property real barWidth: width / _bar.children.length
023.                            - _bar.spacing * (_bar.children.length - 1) / _bar.children.length
024. 
025.    // バーの隙間
026.    property alias rowSpacing: _bar.spacing
027.    // バーの枠関係の情報
028.    property int borderWidth: 2
029.    property color borderColor: "#444444"
030.    property int borderRadius: 2
031. 
032.    // アルファ使うか
033.    property alias useAlpha: _barAlpha.visible
034. 
035.    Column{
036.        anchors.fill: parent
037.        spacing: 5
038. 
039.        // 色選択バー
040.        Row{
041.            id: _bar
042.            height: parent.height * 0.9
043.            spacing: 5
044. 
045.            // 赤のバー
046.            ColorPickerBar{
047.                id: _barRed
048.                width: barWidth
049.                border.width: borderWidth
050.                border.color: borderColor
051.                radius: borderRadius
052.                viewRedMin: 0.0
053.                viewRedMax: 1.0
054.                viewGreenMin: _barGreen.value
055.                viewGreenMax: _barGreen.value
056.                viewBlueMin: _barBlue.value
057.                viewBlueMax: _barBlue.value
058.                viewAlphaMin: _barAlpha.value
059.                viewAlphaMax: _barAlpha.value
060.            }
061. 
062.            // 緑のバー
063.            ColorPickerBar{
064.                id: _barGreen
065.                width: barWidth
066.                border.width: borderWidth
067.                border.color: borderColor
068.                radius: borderRadius
069.                viewRedMin: _barRed.value
070.                viewRedMax: _barRed.value
071.                viewGreenMin: 0.0
072.                viewGreenMax: 1.0
073.                viewBlueMin: _barBlue.value
074.                viewBlueMax: _barBlue.value
075.                viewAlphaMin: _barAlpha.value
076.                viewAlphaMax: _barAlpha.value
077.            }
078.            // 青のバー
079.            ColorPickerBar{
080.                id: _barBlue
081.                width: barWidth
082.                border.width: borderWidth
083.                border.color: borderColor
084.                radius: borderRadius
085.                viewRedMin: _barRed.value
086.                viewRedMax: _barRed.value
087.                viewGreenMin: _barGreen.value
088.                viewGreenMax: _barGreen.value
089.                viewBlueMin: 0.0
090.                viewBlueMax: 1.0
091.                viewAlphaMin: _barAlpha.value
092.                viewAlphaMax: _barAlpha.value
093.            }
094.            // アルファのバー
095.            ColorPickerBar{
096.                id: _barAlpha
097.                width: barWidth
098.                border.width: borderWidth
099.                border.color: borderColor
100.                radius: borderRadius
101.                viewRedMin: _barRed.value
102.                viewRedMax: _barRed.value
103.                viewGreenMin: _barGreen.value
104.                viewGreenMax: _barGreen.value
105.                viewBlueMin: _barBlue.value
106.                viewBlueMax: _barBlue.value
107.                viewAlphaMin: 0.0
108.                viewAlphaMax: 1.0
109. 
110.                value: 1.0
111.            }
112.        }
113. 
114.        // 色説明的なの
115.        Row{
116.            height: parent.height - _bar.height - parent.spacing
117.            spacing: _bar.spacing
118.            // red
119.            Rectangle{
120.                width: _barRed.width
121.                height: parent.height
122.                color: "#ff0000"
123.                border.width: _barRed.border.width
124.                border.color: _barRed.border.color
125.                radius: _barRed.radius
126.            }
127.            // green
128.            Rectangle{
129.                width: _barGreen.width
130.                height: parent.height
131.                color: "#00ff00"
132.                border.width: _barGreen.border.width
133.                border.color: _barGreen.border.color
134.                radius: _barGreen.radius
135.            }
136.            // blue
137.            Rectangle{
138.                width: _barBlue.width
139.                height: parent.height
140.                color: "#0000ff"
141.                border.width: _barBlue.border.width
142.                border.color: _barBlue.border.color
143.                radius: _barBlue.radius
144.            }
145.            // alpha
146.            Rectangle{
147.                width: _barAlpha.width
148.                height: parent.height
149.                color: "#ffffffff"
150.                border.width: _barAlpha.border.width
151.                border.color: _barAlpha.border.color
152.                radius: _barAlpha.radius
153.                visible: _barAlpha.visible
154.            }
155.        }
156.    }
157.}


バー1つずつ
01.// ColorPickerBar.qml
02. 
03.import QtQuick 1.0
04. 
05.Rectangle{
06.    id: _root
07.    width: parent.width
08.    height: parent.height
09.    clip: true
10. 
11.    // 自分自身の色の強さ
12.    property real value: 0
13.    // 表示色用のパラメータ
14.    property real viewRedMin: 0.0
15.    property real viewRedMax: 1.0
16.    property real viewGreenMin: 0.0
17.    property real viewGreenMax: 1.0
18.    property real viewBlueMin: 0.0
19.    property real viewBlueMax: 1.0
20.    property real viewAlphaMin: 0.0
21.    property real viewAlphaMax: 1.0
22. 
23.    // 透けたときに見える背景
24.    Image{
25.        anchors.fill: parent
26.        fillMode: Image.Tile
27.        source: "./images/alpha_background.png"
28.    }
29.    // 色見本のグラデーション
30.    Rectangle{
31.        anchors.fill: parent
32.        radius: parent.radius
33.        border.color: parent.border.color
34.        border.width: parent.border.width
35.        gradient: Gradient {
36.            GradientStop {position: 0.0;  color: Qt.rgba(viewRedMin, viewGreenMin, viewBlueMin, viewAlphaMin)}
37.            GradientStop {position: 1.0;  color: Qt.rgba(viewRedMax, viewGreenMax, viewBlueMax, viewAlphaMax)}
38.        }
39.    }
40.    // ポインタ
41.    Rectangle{
42.        x: parent.border.width
43.        y: parent.height * value
44.        width: parent.width - parent.border.width * 2
45.        height: 2
46.        color: "#bbbbbb"
47.        Rectangle{
48.            anchors.bottom: parent.bottom
49.            x: 0
50.            width: parent.width
51.            height: 1
52.            color: "#333333"
53.        }
54.    }
55. 
56.    // 色変更用のクリックイベント
57.    MouseArea{
58.        anchors.fill: parent
59.        onMousePositionChanged: {
60.            // 自分の色を変更する
61.            _root.value = mouse.y / height;
62.            if(_root.value > 1.0){
63.                _root.value = 1.0;
64.            }else if(_root.value < 0.0){
65.                _root.value = 0.0;
66.            }
67.        }
68.    }
69.}