午後わてんのブログ

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

WPFとVB.NET、エクセルのグループ化を真似したいからまずはグループ化のRectを取得

 
グループ化するときに必要なRectを取得する
グループ化ってのはエクセルの図形とかをグループ化っての、あれをどうしても真似したい
 
イメージ 1
赤枠が必要なRectで対象になるコントロールがぴったり収まる四角形
2016年6月2日追記
これはちょっと違うかもと別の方法
追記ここまで
 
 
デザイン画面とXAML

f:id:gogowaten:20191030112343p:plain

DockPanelに
bt1って名前をつけたButtonと
canvas1って名前をつけたCanvasを配置しただけ
StatusBarはあんまり関係ないしDockPanelもあんまり意味ないな
 
VBコード

f:id:gogowaten:20191030112354p:plain

Imports System.Windows.Controls.Primitives


Class MainWindow
    Private thumbList As New List(Of Thumb)
    Private waku As Path '枠


    'Thumbをcanvas1に追加表示
    Private Sub AddThumb(p As Point, s As Size, angle As Double)
        Dim t As New Thumb
        With t
            .Width = s.Width
            .Height = s.Height
            .RenderTransform = New RotateTransform(angle)
        End With
        Call SetLocate(t, p)
        thumbList.Add(t)
        canvas1.Children.Add(t)
        AddHandler t.DragDelta, AddressOf ThumbDragDelta

    End Sub

    'Thumbの座標セット
    Private Sub SetLocate(t As Thumb, p As Point)
        Canvas.SetLeft(t, p.X)
        Canvas.SetTop(t, p.Y)
    End Sub

    'Thumbの座標ゲット
    Private Function GetLocate(t As Thumb) As Point
        Return New Point(Canvas.GetLeft(t), Canvas.GetTop(t))
    End Function

    'Thumbのマウスドラッグイベント用
    Private Sub ThumbDragDelta(sender As Object, e As DragDeltaEventArgs)
        Dim t As Thumb = DirectCast(sender, Thumb)
        Dim np As New Point(e.HorizontalChange, e.VerticalChange)
        np = np + GetLocate(t)
        Call SetLocate(t, np)
    End Sub


    '渡されたThumbがぴったり収まるRectを返す
    Private Function GetRect(t As Thumb) As Rect
        Dim gt As GeneralTransform = t.TransformToVisual(canvas1)
        Dim r As Rect = gt.TransformBounds(
            New Rect(New Point(0, 0), New Size(t.Width, t.Height)))
        Return r
    End Function

    '渡されたThumbすべてがぴったり収まるRectを返す
    'RectのUnionメソッドを使う
    Private Function GetUnionRect(thumbList As List(Of Thumb)) As Rect
        Dim r As New Rect
        Dim ur As New Rect 'すべてのRectがぴったり収まるRect用
        Dim rl As New List(Of Rect) '左上座標取得用
        For Each t As Thumb In thumbList
            r = GetRect(t)
            rl.Add(r)
            ur.Union(r)
        Next
        Dim p As Point = GetLeftTop(rl) '左上座標取得
        ur.Location = ur.Location + p '座標変更
        'サイズ変更
        ur.Size = New Size(ur.Width - p.X, ur.Height - p.Y)
        Return ur

    End Function

    '複数Rectの一番左上取得
    Private Function GetLeftTop(rectList As List(Of Rect)) As Point
        Dim x As Double = rectList(0).X
        Dim y As Double = rectList(0).Y
        For i As Integer = 1 To rectList.Count - 1
            x = Math.Min(x, rectList(i).X)
            y = Math.Min(y, rectList(i).Y)
        Next
        Return New Point(x, y)
    End Function


    '赤枠描画
    Private Sub DrawRectPath(r As Rect)
        '前回の枠があったら消す
        If waku IsNot Nothing Then
            canvas1.Children.Remove(waku)
        End If
        '新しい赤枠描画
        Dim p As New Path With {.Stroke = Brushes.Red, .StrokeThickness = 1}
        Dim g As New RectangleGeometry(r)
        p.Data = g
        canvas1.Children.Add(p)
        waku = p
    End Sub



    'アプリ起動直後、Thumbを表示する
    Private Sub MainWindow_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
        Call AddThumb(New Point(80, 10), New Size(100, 100), 10)
        Call AddThumb(New Point(180, 50), New Size(50, 100), 30)
        Call AddThumb(New Point(200, 100), New Size(120, 100), 20)
    End Sub


    'グループ化した場合のRect表示
    Private Sub bt1_Click(sender As Object, e As RoutedEventArgs) Handles bt1.Click
        Dim ur As Rect = GetUnionRect(thumbList)
        Call DrawRectPath(ur)
    End Sub

End Class
 
 
イメージ 4
1個目のRect
 
イメージ 5
2個目
 
イメージ 6
3個め
 
3つの青枠から全体のRect(水色枠)を取得
イメージ 7
RectのUnionメソッドを使って全体のRectを取得
 
左上座標取得
イメージ 8
3つの青枠の中で一番上と一番左になる座標を取得、地道にMath.MinをFor Nextで回している
 
左上座標変更
イメージ 9
左上座標を(0,0)から(62,10)へ変更
 
イメージ 10
移動した分だけサイズも変更でぴったり収まる枠Rectが取得完了
 
目印の赤枠表示
イメージ 11
Pathを使って赤枠表示
 
書いている途中で思ったのが要は左上と右下になる座標がわかればいいんだからUnionメソッドを使わないで
左上座標をMath.Min求めるついでにMath.Maxも使って右下座標も求めたらいいんじゃないかってこと
 

 
Canvasを入れたControlTemplateをThumbのTemplateに指定して
Canvasの中にImageを配置
Thumb
	┗Canvas
		┗Image
こんな感じにしておいて、複数のThumbををグループ化したい
今のPixtack紫陽花2ndは
Thumb
	┗Image
になっているからそのままだとグループ化できないっぽい

Thumb
	┗Canvas
		┣Image
		┗Path
とかできるようにしたい

グループ化した時は
Thumb
	┗Canvas
		┣Thumb
		┃	┗Canvas
		┃		┣Image
		┃		┗Image
		┗Thumb
			┗Canvas
				┣Image
				┣Path
				┗Image
こんな感じになればいいのかなあ
 
今回のコード
2016年6月2日追記
関連記事、古い順
続きの記事
WPFVB.NET、エクセルのグループ化とグループ化解除を真似したい2 ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
http://blogs.yahoo.co.jp/gogowaten/14161262.html

別の方法
WPFVB.NET、エクセルのグループ化とグループ化解除を真似したい3 ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
http://blogs.yahoo.co.jp/gogowaten/14187560.html