午後わてんのブログ

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

WPFとVB.NETでカラーピッカーその4、パレットを作って色を登録できるようにした

前回は3日前
の続き
WPFVB.NETでカラーピッカーその3、元の色の明るさ(輝度)に合わせた別の色(色相)を選びたい ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
http://blogs.yahoo.co.jp/gogowaten/14039932.html
 
 
カラーピッカーに色を登録するパレットをつけた

今回のカラーピッカー
 
ウィンドウ下側にあるたくさんのマスが色を登録するパレット
色が決まったら登録したいマスを右クリックして色を追加(登録)する
削除するときも削除したいマスを右クリックから色の削除
登録した色はファイルとして記録されるので次回起動時に引き継がれる
パレットをクリックで新しい色のところの色が変わる
 
パレット部分はWrapPanelにマスとなるBorderコントロールを流し込んでいる
 
 
必要な処理
  1. パレットの色データをファイルとして保存
  2. パレットの色データのファイルを読み込む
  3. 色の追加
  4. 色の削除
  5. 右クリックメニューの作成
  6. マスをクリックした時に新しい色をマスの色と同じにする
  7. マスを作成する
 
1番のパレットの色データをファイルとして保存
ファイルに保存するにはシリアライズするんだけど
WPFのColorはシリアライズできない!WindowsFormのColorはできたのに!
調べた感じではWPFのColorもできるっぽいけど難しくてわからなかったので
別の方法
色のデータとして必要なのはARGB各値、4つのbyte型だけなので
新たにIntARGBっていうStructureを作った
Integer型にしたけど素直にbyte型のが良かったかも
どっちでもシリアライズできるはず
 
これを追加した場所は
イメージ 2
MainWindowクラスの外側
<serializabla>を頭につけてシリアライズできます宣言しておく
 
このIntARGBはマスの個数分作るのでこれをまとめてリストにして入れておくために
イメージ 3
ObservableCollectionを継承したPaletteARGBっていうクラスを作成
これにもシリアライズできます宣言の<Serializable>を付ける
あとはこれをMainWindowクラスの方で適当な名前の変数に入れて使う
 
イメージ 4
PaletteARGBを入れた変数の名前はPaletteDataARGBにした
これをシリアライズしてファイルに保存することになる
 
グローバル変数っていうのかな、クラスのどこからでも参照できる変数
これを増やすのは良くないみたい、でもどんどん増えるYO
FocusPalette
現在選択中のマス(Border)の目印用
PaletteColors
すべてのマスを入れておくリスト
 
 

マスの色は背景色(Background)でこれにはSolidColorBrushを指定するから
IntARGBとSolidColorBrushをそれぞれに変換する関数が

’IntARGBをSolidColorBrushに変換
    Public Function ARGBtoSolidBrush(argb As IntARGB) As SolidColorBrush
        Return New SolidColorBrush(Color.FromArgb(argb.A, argb.R, argb.G, argb.B))
    End Function
 
’SolidColorBrushをIntARGBに変換する関数
    Public Function SolidBrushtoARGB(b As SolidColorBrush) As IntARGB
        Dim col As Color = b.Color
        Return New IntARGB(col.A, col.R, col.G, col.B)
    End Function
イメージ 8

 
これで色データをシリアライズする準備ができた
 
 
 
1.パレットの色データをファイルとして保存

    'パレットデータをシリアライズしてファイルに保存
    Private Sub SavePaletteData()
        Dim appPath As String = My.Application.Info.DirectoryPath
        Dim fileName As String = "PaletteColorData.bin"
        Dim filePath As String = appPath & "\" & fileName
        Try
            Using fs As New FileStream(filePath, FileMode.Create)
                Dim bf As New System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
                bf.Serialize(fs, PaletteDataARGB)
            End Using
        Catch ex As Exception
            Dim str As String = "ファイルの保存に失敗しました" & vbNewLine
            MsgBox(str & ex.Message)
        End Try
    End Sub

イメージ 5
ファイルの保存場所はアプリの実行ファイルと同じフォルダ
ファイル名はPaletteColorData.binにした
PaletteDataARGBが色情報のリスト
 
My.Application.Info.DirectoryPath
これで実行ファイルの場所取得
 
 
 
2.パレットの色データのファイルを読み込む

    'パレットデータをデシリアライズして読み込む
    Private Sub LoadPaletteData()
        Dim appPath As String = My.Application.Info.DirectoryPath
        Dim fileName As String = "PaletteColorData.bin"
        Dim filePath As String = appPath & "\" & fileName
        'ファイルが存在しなければなにもしないで終了
        If File.Exists(filePath) = False Then Exit Sub
 
        Try
            Using fs As New FileStream(filePath, FileMode.Open)
                Dim bf As New Runtime.Serialization.Formatters.Binary.BinaryFormatter
                PaletteDataARGB = bf.Deserialize(fs)
            End Using
        Catch ex As Exception
            Dim str As String = "ファイルの読み込みに失敗しました" & vbNewLine
            MsgBox(str & ex.Message)
        End Try
    End Sub
イメージ 6
PaletteDataARGBにファイルからデシリアライズしたものを取得している
取得した色情報をマスに反映する処理が
   
        '読み込んだデータをPaletteに反映させる
        For i As Integer = 0 To PaletteDataARGB.Count - 1
            PaletteColors(i).Background = ARGBtoSolidBrush(PaletteDataARGB(i))
        Next
 
イメージ 7
PaletteColorsがマス(Border)のリスト
PaletteDataARGBが色情報のリスト
ARGBtoSolidBrushはIntARGBをSolidColorBrushに変換する関数
 
 
 
 

3.色の追加

    Private Sub PaletteAddColor()
        FocusPalette.Background = rectMihon.Fill
        Dim i As Integer = PaletteColors.IndexOf(FocusPalette)
        PaletteDataARGB(i) = SolidBrushtoARGB(FocusPalette.Background)
        'パレットデータをセーブ
        Call SavePaletteData()
    End Sub

4.色を削除

    Private Sub PaletteColorDelete()
        FocusPalette.Background = New SolidColorBrush(Colors.Transparent)
        Dim i As Integer = PaletteColors.IndexOf(FocusPalette)
        PaletteDataARGB(i) = New IntARGB(Colors.Transparent)
        'パレットデータをセーブ
        Call SavePaletteData()
    End Sub
イメージ 9
新しい色で表示している色を選択中のマスにコピー
マスの色を色情報を書き込み
色情報をファイルに保存
っていう流れ
rectMihonが新しい色を表示しているRectangle
FocusPaletteが選択中のマス、これを使ってマスのリストの何番目のマスなのかを取得しているのが
Dim i As Integer = PaletteColors.IndexOf(FocusPalette)
色情報のリストとマスのリストの順番は一致しているので
同じ番号のところに色情報を書き込みしているのが
PaletteDataARGB(i) = SolidBrushtoARGB(FocusPalette.Background)
 
色の削除は透明色を指定している
 
 
 

5.右クリックメニューの作成

    Private Function AddContextMeruPalette() As ContextMenu
        '右クリックメニュー作成
        Dim cm As New ContextMenu
        Dim mi As New MenuItem
        mi.Header = "色を追加"
        cm.Items.Add(mi)
        AddHandler mi.Click, AddressOf PaletteAddColor
        Dim mi2 As New MenuItem
        mi2.Header = "色を削除"
        cm.Items.Add(mi2)
        AddHandler mi2.Click, AddressOf PaletteColorDelete
        Return cm
    End Function
イメージ 10
 

6.マスをクリックした時に新しい色をマスの色と同じにする

    'Paletteクリックした時、hsvとαの各スライダーを変化させる
    Private Sub Palette_Click(sender As Object, e As RoutedEventArgs)
        Dim b As SolidColorBrush = FocusPalette.Background
        '透明色(アルファ値が0)なら何もしないで終了
        If b.Color.A = 0 Then Return
 
        Dim hsv As HSV = RGBtoHSV(b.Color)
        sldHue.Value = hsv.H
        sldS.Value = hsv.S
        sldV.Value = hsv.V
        sldA.Value = b.Color.A
    End Sub
イメージ 11
クリックしたマスの色をHSVに変換して
αとHSVそれぞれのスライダーの値を変化させているだけ
 
 

7.マスを作成する

    '選択中のPaletteを変更
    Private Sub FocusedPalette(sender As Object, e As RoutedEventArgs)
        FocusPalette = sender
    End Sub
 
    'Palette用のBorder作成して追加
    Private Sub AddPalette()
        '右クリックメニュー作成
        Dim cm As ContextMenu = AddContextMeruPalette()
 
        'Palette作成
        For i As Integer = 0 To 100
            Dim r As New Border
            With r
                .Background = New SolidColorBrush(Colors.Transparent) '最初は透明色を指定
                .Width = 20
                .Height = 20
                .BorderThickness = New Thickness(1)
                .BorderBrush = New SolidColorBrush(Colors.LightGray)
                .Margin = New Thickness(2, 2, 0, 0)
                .ContextMenu = cm '右クリックメニュー指定
 
            End With
 
            'WrapPanelに追加
            wpPalette.Children.Add(r)
            'イベントとメソッドの関連付け
            AddHandler r.PreviewMouseDown, AddressOf FocusedPalette
            AddHandler r.MouseLeftButtonDown, AddressOf Palette_Click
 
            'Borderのリストに追加
            PaletteColors.Add(r)
            'シリアライズ用のリストにARGBを追加
            PaletteDataARGB.Add(SolidBrushtoARGB(r.Background))
        Next
 
        ''デシリアライズでパレットデータを読み込んで反映
        Call UpdatePalette()
 
    End Sub
イメージ 12
マスを101個作成してそれぞれに色々設定
PreviewMouseDownイベントに選択中のマスを切り替える処理の
FocusedPaletteを指定しているのが
AddHandler r.PreviewMouseDown, AddressOf FocusedPalette
 
このAddPaletteメソッドはアプリが起動し終わった時に実行することにしたので
イメージ 13
Me.Loadedのところで呼び出し
 
 
イメージ 14
縦に長過ぎるwレイアウトが⊂ミ⊃^ω^ )⊃ アウアウ!!
色のスライダーと登録するパレットが離れているのはどうにかするとして
プログラムもイマイチなところがあるけど
機能的にはかなり満足できるものができた!
 
 
コード
 
 
WPFVB.NETでカラーピッカーその5、もっと色を登録できるようにした ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
http://blogs.yahoo.co.jp/gogowaten/14058386.html