午後わてんのブログ

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

マウスドラッグでラベルコントロールの移動と直線の描画その2、頂点の追加と削除

続き

頂点の追加と削除
 
移動させたLabelには右クリックした場所の色を表示している

線の色はアクアでARGB(255,0,255,255)
線以外の場所の色は無色ARGB(0,0,0,0)
右クリックした場所の色がアクアなら頂点追加のメニューを表示するようにしている
右クリックした場所が頂点(ラベル)なら削除のメニューを表示
 

f:id:gogowaten:20191016102707p:plain

デザイン画面でツールボックスから右クリックメニューの追加
頂点を右クリックした時用と線を右クリックした時用の二つ追加
 

f:id:gogowaten:20191016102736p:plain

追加した右クリックメニューは
プロパティのItemsのコレクションの右のボタンを押すと
項目を追加したり設定の画面↓

f:id:gogowaten:20191016102818p:plain

一個追加して
右クリックメニュー自体の名前はめんどくさくてそのままの
ContextMenuStrip1
項目の名前はToolStripMenuItemPointDeleteにしてみた(長い)
項目の表示は「点の削除」にしてみた
 

f:id:gogowaten:20191016102830p:plain

もう一つは線を右クリックした時用
こっちもメニュー自体の名前はそのまま
項目の名前は「ToolStripMenuItem頂点の追加」にした
やっぱり日本語入れたほうがいいな
項目の表示名は「頂点の追加」
線は画像なので画像を表示するexPictureBoxの上にあることになる
なのでこの右クリックメニューはexPictureBoxに関連付ける
 

f:id:gogowaten:20191016102842p:plain

exPictureBoxのプロパティのContextMenuStripのドロップダウンリストから選ぶ
これでexPictureBoxのどこを右クリックしてもメニューが表示されるようになる
でも今回はexPictureBoxのどこでもではなく線の上だけで表示したいので
ここは「なし」のままにしておく
 
 
exPictureBoxを右クリックした時にその場所が線の上か
線の上ではないのかを判定して
線の上なら右クリックメニューを設定して
線の上ではないなら右クリックメニューを「なし」にする
処理をMouseDownイベントように書いた
MouseDownはクリックボタンを押し下げた時でボタンを上げる前の状態
 
    Private Sub クリックした位置で右クリックメニューの有無(sender As Object, e As MouseEventArgs)
        If e.Button = Windows.Forms.MouseButtons.Right Then
            Dim bmp As New Bitmap(Me.ExPictureBox1.Image)
            Dim col As Color = bmp.GetPixel(e.X, e.Y)
            Me.Label1.Text = col.ToString
            If col <> Color.FromArgb(0, 0, 0, 0) Then 'ライン上なら右クリックメニュー表示
                Me.ExPictureBox1.ContextMenuStrip = Me.ContextMenuStrip2
                mousePoint = e.Location 'クリックした位置を記憶(expicturebox上の座標)
                focusPic = Me.ExPictureBox1 'sender
            Else
                Me.ExPictureBox1.ContextMenuStrip = Nothing 'ライン外なら何も表示しない
            End If
            bmp.Dispose()
        End If
    End Sub
exPictureBoxの画像をBitmapで読み込んでGetPixelで色の判定をする
クリックした位置の取得はマウスイベントの引数?のeからできる
色がARGB(0,0,0,0)なら色が付いていないってことだから線の上ではないことになる
のでexPictureBoxに右クリックメニューを「なし」にする
Me.ExPictureBox1.ContextMenuStrip = Nothing
「なし」にする場合はNothingでいいみたい
 
逆に色がARGB(0,0,0,0)以外なら線の上なのでメニューを指定する
                Me.ExPictureBox1.ContextMenuStrip = Me.ContextMenuStrip2
↑はexPictureBox1って決め打ちしてるけどsenderとかにすればいいのかも
mousePointとfocusPicの変数はそれぞれクリックした座標と
クリックしたexPictureBoxを入れておくもので後で使う
 
exPictureBoxのMouseDownイベント用なので設定
この処理はアプリの起動時の
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
に↓を追加
AddHandler ExPictureBox1.MouseDown, AddressOf クリックした位置で右クリックメニューの有無

f:id:gogowaten:20191016102857p:plain

exPictureBox1のMouseDownイベントに直接設定する場合
exPictureBoxを動的作成しないならこっちのほうがわかりやすい
頂点の追加をクリックした時に実行する処理

f:id:gogowaten:20191016102911p:plain

イベントのクリックをダブルクリック
 
頂点の追加
新しい頂点の座標はさっきの右クリックメニューのところで取得した
mousePointに入っているのでこれでわかる
問題はどの頂点とどの頂点の間に入れればいいのか
頂点の順番で線は引かれる、4つ頂点があれば1から2、2から3、3から4
今のところはこれがうまくできなくて、変なところに入ってしまうことがある
すべての頂点の座標がわかっているんだから
たぶん中学生(小学生?)レベルの算数だと思うんだけどコレガワカラナイ
1次関数ってやつだと思う、直線のグラフを書くやつ
イメージ 8
恥ずかしいけど載せていくスタイル、エクセルでなんかやってるところ
新しい頂点の座標が二つの頂点のx,yそれぞれの値の間にあれば
そこでいいんじゃないかってひねり出した方法で処理している
これはあとでググってみる
Private Sub ToolStripMenuItem頂点の追加_Click(sender As Object, e As EventArgs) Handles ToolStripMenuItem頂点の追加.Click
    '右クリックしたところに頂点を追加
    Dim newP As New Point(mousePoint) '新しい頂点の座標
    Dim ps As Generic.List(Of Point) = focusPic.PointN
    Dim xMin As Long
    Dim xMax As Long
    Dim yMin As Long
    Dim yMax As Long
    For i As Long = 0 To ps.Count - 2
        xMin = Math.Min(ps.Item(i).X, ps.Item(i + 1).X)
        xMax = Math.Max(ps.Item(i).X, ps.Item(i + 1).X)
        yMin = Math.Min(ps(i).Y, ps(i + 1).Y)
        yMax = Math.Max(ps(i).Y, ps(i + 1).Y)
        If (xMin <= newP.X) AndAlso (newP.X <= xMax) AndAlso (yMin <= newP.Y) AndAlso (newP.Y <= yMax) Then
            focusPic.PointN.Insert(i + 1, newP)
            Exit For

        End If
    Next

    Call 頂点の初期化(focusPic)

End Sub
↑は間違っている
 
 
頂点の右クリックメニュー
頂点につかうラベルコントロールはプログラムの実行中に追加や削除されるので
追加するときに右クリックメニューを設定することになる
Private Sub 頂点の初期化(iPic As exPictureBox)
   'すべての頂点を削除
    iPic.Controls.Clear()

   '頂点すべてを作成
    Dim ps() As Point
    ps = DirectCast(iPic.PointN.ToArray, Point())
    For i As Long = 0 To UBound(ps)
        iLabel = New Label
        With iLabel
            .Width = 5
            .Height = 5
            .BackColor = Color.Black
            .Tag = i
            .Name = iPic.Name
            .Location = ps(i)
            .ContextMenuStrip = Me.ContextMenuStrip1 '右クリックメニューの追加
        End With

        iPic.Controls.Add(iLabel)’頂点の追加
  ’マウスイベントに登録
        AddHandler iLabel.MouseDown, AddressOf マウスダウンドラッグ開始
        AddHandler iLabel.MouseMove, AddressOf マウスムーブドラッグ中
        AddHandler iLabel.MouseUp, AddressOf マウスアップ
    Next
End Sub
 
頂点の削除の処理
Private Sub ToolStripMenuItemPointDelete_Click(sender As Object, e As EventArgs) Handles ToolStripMenuItemPointDelete.Click
   '右クリックした頂点の削除
    Dim iPic As exPictureBox = Me.Controls(iLabel.Name)’親コントロールexPictureBoxの名前をラベルの名前につけてある
    If iPic.Controls.Count > 2 Then '頂点が2個以上なら

        Dim i As Integer = iLabel.Tag
        Me.ExPictureBox1.PointN.RemoveAt(i) '指定した頂点の情報削除
        Me.ExPictureBox1.Controls.Remove(iLabel) '指定した頂点の削除
        Call 頂点の初期化(iPic)
        Call 線の描画(iPic)
    End If
End Sub

Private Sub 線の描画(iPic As exPictureBox)
    Dim ps() As Point = DirectCast(iPic.PointN.ToArray, Point())
    Dim canvas As New Bitmap(iPic.Width, iPic.Height)
    Dim g As Graphics = Graphics.FromImage(canvas)
    g.DrawLines(Pen2, ps)
    iPic.Image = canvas
    g.Dispose()
End Sub
 
後半は飽きてきたw
文字ばかりだと飽きる
イメージ 10
 
 
関連記事
次回 2014/12/21は1日後
 
前回 2014/12/19は1日前

gogowaten.hatenablog.com