午後わてんのブログ

ベランダ菜園とWindows用アプリ作成(WPFとC#)

WPF色一覧表示してHSVで並べ替えするアプリできた

WPF色一覧表示と並べ替え
イメージ 1
System.Windows.Media.Colorの中の色一覧を表示
並べ替えは
色の名前順(昇順ソート)
H:色相(昇順ソート)
S:彩度(昇順ソート)
V:明度(降順ソート)
YUVのY:輝度(降順ソート)
 
一覧マスをクリックで色の詳細表示と見本枠の背景色変更
一覧マスにマウスカーソルを乗せると見本枠の文字色変更
Transparentは無色透明で色じゃないけどそのまま入っていて、Whiteと同じような扱いになっている
 
一覧のTomatoをクリックしたところ
イメージ 2
右にTomato色の詳細表示
#FFFF6347は16進数でARGBの順番
 
 
一覧のOliveにマウスカーソルを乗せたところ
イメージ 3
右下の文字色がOliveになる
 
 
並べ替え

f:id:gogowaten:20191213134657p:plain

最初は名前順になっている
 
色相順
名前順→色相順

f:id:gogowaten:20191213134709p:plain

名前順→明度→色相

f:id:gogowaten:20191213134718p:plain

同じ色相順でも明度順にしてからだと少し変わるのは
色相が全く同じ色が複数あるからで
色相0は9色もあって左上のRedからMaroonまでがそう
 
 
彩度順
名前順→彩度順

f:id:gogowaten:20191213134730p:plain

名前から彩度だとバラけた感じだけど
 
名前→色相→明度→彩度

f:id:gogowaten:20191213134824p:plain

色相と明度を挟むとまとまる
 
 
 
明度順
名前順→明度順

f:id:gogowaten:20191213134855p:plain

前半がバラけている
 
名前順→色相→明度

f:id:gogowaten:20191213134909p:plain

このほうが選びやすい
 
 
輝度順

f:id:gogowaten:20191213134921p:plain

輝度順はどの並びからでもほとんど変化なし
 
 
デザイン画面
MainWindow.xaml

f:id:gogowaten:20191213134932p:plain

 
MainWindow.xaml.cs
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;

using MyHSV;
using System.Reflection;

namespace WPF色一覧
{
    class MyItem
    {
        public string Name;//色名
        public Color Color;
        public HSV HSV;
        public double Y;//YUV形式のY、輝度

        public MyItem(string name, Color color, HSV hSV, double y)
        {
            Name = name;
            Color = color;
            HSV = hSV;
            Y = y;
        }
    }

    public partial class MainWindow : Window
    {
        //色表示に使うTextBlockのリスト
        private List<TextBlock> MyListTextBlock = new List<TextBlock>();
        //並べ替えするテーブル
        List<MyItem> MyTable = new List<MyItem>();
        public MainWindow()
        {
            InitializeComponent();
            Title = this.ToString();

            MyInitialize();

            ButtonHue.Click += ButtonHue_Click;
            ButtonSaturation.Click += ButtonSaturation_Click;
            ButtonValue.Click += ButtonValue_Click;
            ButtonBrightness.Click += ButtonBrightness_Click;
            ButtonName.Click += ButtonName_Click;
            CheckBoxVisible.Click += CheckBoxVisible_Click;
        }
        private void CheckBoxVisible_Click(object sender, RoutedEventArgs e)
        {
            if (CheckBoxVisible.IsChecked == true)
            {
                for (int i = 0; i < MyListTextBlock.Count; i++)
                {
                    MyListTextBlock[i].Text = MyTable[i].Name;
                }
            }
            else
            {
                for (int i = 0; i < MyListTextBlock.Count; i++)
                {
                    MyListTextBlock[i].Text = "";
                }
            }
        }
        private void ButtonName_Click(object sender, RoutedEventArgs e)
        {
            MyTable = MyTable.OrderBy(a => a.Name).ToList();
            ChangeTextBlockColor();
        }

        private void ButtonBrightness_Click(object sender, RoutedEventArgs e)
        {
            MyTable = MyTable.OrderByDescending(a => a.Y).ToList();
            ChangeTextBlockColor();
        }

        private void ButtonValue_Click(object sender, RoutedEventArgs e)
        {
            MyTable = MyTable.OrderByDescending(a => a.HSV.Value).ToList();
            ChangeTextBlockColor();
        }

        private void ButtonSaturation_Click(object sender, RoutedEventArgs e)
        {
            MyTable = MyTable.OrderBy(a => a.HSV.Saturation).ToList();
            ChangeTextBlockColor();
        }

        private void ButtonHue_Click(object sender, RoutedEventArgs e)
        {
            MyTable = MyTable.OrderBy(a => a.HSV.Hue).ToList();
            ChangeTextBlockColor();
        }



        private void MyInitialize()
        {
            //TypeクラスのGetPropertyメソッドを使ってColorsクラスの色取得
            PropertyInfo[] infos = typeof(Colors).GetProperties(BindingFlags.Public | BindingFlags.Static);

            for (int i = 0; i < infos.Length; i++)
            {
                PropertyInfo info = infos[i];
                Color color = (Color)info.GetValue(null);
                //HSV hSV = HSV.Color2HSV_ConicalModel(color);//円錐モデル
                HSV hSV = HSV.Color2HSV(color);//円柱モデル
                string name = info.Name;
                double y = GetBrightness(color);
                MyTable.Add(new MyItem(name, color, hSV, y));
                var textBlock = new TextBlock()
                {
                    Margin = new Thickness(1),
                    Text = name,
                    Width = 120,
                    Tag = i
                };
                MyWrapPanel.Children.Add(textBlock);
                MyListTextBlock.Add(textBlock);
                textBlock.MouseLeftButtonDown += TextBlock_MouseLeftButtonDown;
                textBlock.MouseEnter += TextBlock_MouseEnter;
            }
            ChangeTextBlockColor();
        }
        private void TextBlock_MouseEnter(object sender, MouseEventArgs e)
        {
            var tb = (TextBlock)sender;
            var i = (int)tb.Tag;
            TextBlockBackAndForeColor.Foreground = new SolidColorBrush(MyTable[i].Color);
            TextBlockBackAndForeColor.Text = MyTable[i].Name;
        }
        private void TextBlock_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            var textBlock = (TextBlock)sender;
            var b = (SolidColorBrush)textBlock.Background;
            int i = (int)textBlock.Tag;
            MyItem item = MyTable[i];
            TextBlockBackAndForeColor.Background = b;
            TextBlockHexadecimal.Text = b.Color.ToString();
            TextBlockColor.Background = b;
            TextBlockColorName.Text = item.Name;
            TextBlockRGB.Text = $"R:{b.Color.R.ToString()} G:{b.Color.G.ToString()} B:{b.Color.B.ToString()}";
            TextBlockHue.Text = $"色相:{item.HSV.Hue:000.00}°";
            TextBlockSaturation.Text = $"彩度:{item.HSV.Saturation:000.00%}";
            TextBlockValue.Text = $"明度:{item.HSV.Value:000.00%}";
            TextBlockbrightness.Text = $"輝度:{item.Y:000.00}";
        }
        //色一覧textblockの色の変更        
        private void ChangeTextBlockColor()
        {
            for (int i = 0; i < MyTable.Count; i++)
            {
                TextBlock tb = MyListTextBlock[i];
                MyItem item = MyTable[i];
                tb.Background = new SolidColorBrush(item.Color);
                if (CheckBoxVisible.IsChecked == true)
                {
                    tb.Text = item.Name;
                }
                //色の輝度が200未満なら文字色を白にする、以上なら灰色
                if (item.Y < 200)
                {
                    tb.Foreground = new SolidColorBrush(Colors.White);
                }
                else
                {
                    tb.Foreground = new SolidColorBrush(Colors.Gray);
                }

            }
        }
        //輝度
        private double GetBrightness(Color col)
        {
            double y = 0.299 * col.R + 0.587 * col.G + 0.11 * col.B;
            return y;
        }
    }
}
 
 
イメージ 13
RGBからHSVの変換は以前作ったDLLを使うので参照に追加して
using MyHSV(16行目)している
 
17行目のusing System.Reflectionは
System.Windows.Media.Colorにある色全部を取得するのに使っている
 
 
Colorsの名前付きの色全部取得
イメージ 15
これを全部取得したい
 
イメージ 17
イメージ 18
取得できた
 
イメージ 14
Colors.Red;とかの中にカーソルを置いてF12キー押すと
イメージ 16
Colorsクラスの中みたいなのが表示される
色の名前が並んでいて、それはpublic staticってのがわかる
 
Type t = typeof(Colors);
PropertyInfo[] infos = t.GetProperties(BindingFlags.Public | BindingFlags.Static);
 
 
 
色の情報を一覧表(テーブル)にする
HSVそれぞれの要素でソートしたかったので、1色ごとの情報を入れておくクラスを作って
イメージ 19
これだけなら構造体でもいい気もするけど、どうなんだろ
 
MyItemを全部の色分作って、それを入れておくリスト(テーブル)をフィールドで用意して
イメージ 20
MyTable
 
 
MyTableにMyItemを入れていく
イメージ 22
 
 
MyTableの中
イメージ 21
HSVの値も入った
順番は名前順なので先頭はAliceBlue
 
 
 
並べ替え
色相順で並べ替えしたMyTableの中イメージ 23
先頭の色が色相245のAliceBlueから色相0のBrownに変わっている
 
 
並べ替えはOrderByメソッド
 
MyTableを色相順で並べ替え(ソート)
MyTable = MyTable.OrderBy(a => a.HSV.Hue).ToList();
 
OrderByってのが昇順ソートで降順ソートしたいときはOrderByDescending
     MyTable = MyTable.OrderByDescending(a => a.HSV.Hue).ToList();
 
 
     MyTable.OrderBy(a => a.HSV.Hue)
これのaは変数みたいなものでbでもcでもxでもいいしitemとかでもいい
これにMyTableの要素一つ一つが順番に入って処理されていく感じかなあ
 
イメージ 24
MyTable.OrderBy(a => a.
ここまで入れると入力候補が出てくるのでソートの基準にしたいのを選ぶ
今回は色相(Hue)なので
 
MyTable.OrderBy(a => a.HSV.Hue)
 
これでソートされたものが出てくる、ソートされるんじゃなくて出てくるので
 
var sorted = MyTable.OrderBy(a => a.HSV.Hue);
 
ってするとソートされたものが受け取れる
でもこれだと
イメージ 25
OrderedEnumerableっていうよくわかんない型になっているので
最後にToList();を付けて元のリストの形にしている
 
 
 

 
連続ソート
MyTable = MyTable.OrderBy(a => a.HSV.Hue).OrderBy(a => a.Name).ToList();
 
色相でソートされた状態から名前でソートされる
今回は使っていないけど、こういうのもできるんだねえ
 
並べ替えのOrderByとかはLINQ関係なんだろうけど、使えると便利だねえ
これがForとIfの組み合わせで同じことをしようとすると何十行にもなりそうなのを1行でできる
ただ、=>とかのラムダ式と相まって難しい、またすぐ忘れそう
 
色のマスをクリックしたときに詳細を表示するところ
イメージ 26
これもバインディングとか使えばラクできそうなんだけど、その書き方がねえ、まだ理解できない
 
それでも目的のColorsの色一覧をHSVで並べ直して表示ってのは達成できた!
以前に作ったRGBをHSVに変換するDLLを利用できたのも良かった
 

 
参照したところ
色一覧取得
C#でColorの値をリストアップしてみる - takoashiの開発記録
http://d.hatena.ne.jp/takoashi_net/20080818/1219028584
C#】定義済みColorの色名と色一覧 - 中の下の上の真ん中あたり
http://arikalog.hateblo.jp/entry/2013/12/02/215401
 
WPF 色の名前と色の表示 その2: C# プログラミング 再入門
http://dotnetcsharptips.seesaa.net/article/434274231.html
いつかはこんなふうに書けるようになりたいねえ
 
並べ替え
C# リストで複数キーを指定したソート方法 | システム開発・Web制作・システム運用・技術者派遣なら株式会社スリーエスシステム&サービス
http://www.3s-sys.co.jp/blog/2017/03/15/1195/
ここのがすごい参考になった
 
Listの要素を並べ替えるには?[C#VB]:.NET TIPS - @IT
http://www.atmarkit.co.jp/ait/articles/1703/22/news023.html
[LINQ] クエリ式の基本(from, select) | HIRO's.NET Blog
http://blog.hiros-dot.net/?p=5083

 
ダウンロード
アプリ
ここのWPF.zipがそれ
 
 
xamlC#コード
 
 
RGB→HSVのDLL

 
関連記事
2018/2/20
WPF、Color(RGB)とHSVを相互変換するdll作ってみた、オブジェクトブラウザ使ってみた ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
https://blogs.yahoo.co.jp/gogowaten/15380324.html
2018/2/18
dllファイル(クラスライブラリ.NET framework)の作り方と使うまでの手順メモ ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
https://blogs.yahoo.co.jp/gogowaten/15377219.html