WPF、PolyLineの頂点にThumb表示、マウスドラッグで頂点移動、その2
前回の
WPF、PolyLineの頂点にThumb表示、マウスドラッグで頂点移動 - 午後わてんのブログ
これを少し書き直してみた
ついでに、ThumbのTemplateを変更して塗りつぶしなしの点線枠にした
コード
2022WPF/20220610_PolyLineとThumb/20220610_PolyLineとThumb at master · gogowaten/2022WPF
MainWindow.xaml
<Window x:Class="_20220610_PolyLineとThumb.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:_20220610_PolyLineとThumb" mc:Ignorable="d" Title="MainWindow" Height="450" Width="600"> <Grid x:Name="MyGrid" UseLayoutRounding="False"> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition Width="200"/> </Grid.ColumnDefinitions> <StackPanel Grid.Column="1"> <Button x:Name="MyButton1" Content="追加" Click="MyButton1_Click"/> <Button x:Name="MyButton2" Content="削除" Click="MyButton2_Click"/> <Button x:Name="MyButton3" Content="蚊取り線香" Click="MyButton3_Click"/> <Button x:Name="MyButton4" Content="Thumb表示切替" Click="MyButton4_Click"/> </StackPanel> <Canvas Name="MyCanvas"/> </Grid> </Window>
MainWindow.xaml.cs
using System; using System.Collections.Generic; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; using System.Windows.Shapes; using System.Windows.Controls.Primitives; namespace _20220610_PolyLineとThumb { public partial class MainWindow : Window { private PolyLineCanvas MyPolyLineCanvas; private PolyLineCanvas MyPolyLineCanvas2; private PolyLineCanvas? MyKatori; public MainWindow() { #if DEBUG Left = 100; Top = 100; #endif InitializeComponent(); MyPolyLineCanvas = new(Brushes.Crimson, 10); MyPolyLineCanvas.AddPoint(new Point(20, 20)); MyPolyLineCanvas.AddPoint(new Point(120, 20)); MyCanvas.Children.Add(MyPolyLineCanvas); MyPolyLineCanvas2 = new(Brushes.DarkMagenta, 10); MyPolyLineCanvas2.AddPoint(new Point(120, 120)); MyPolyLineCanvas2.AddPoint(new Point(220, 20)); MyCanvas.Children.Add(MyPolyLineCanvas2); } private void MyButton1_Click(object sender, RoutedEventArgs e) { MyPolyLineCanvas.AddPoint(new Point(300, 200)); } private void MyButton2_Click(object sender, RoutedEventArgs e) { MyPolyLineCanvas.RemovePoint(); } private void MyButton3_Click(object sender, RoutedEventArgs e) { AddPoint蚊取り線香(1000, Brushes.DarkGreen, 5, 20); } private void AddPoint蚊取り線香(int count, Brush brush, int syuukai, double width) { MyKatori = new(brush, width); double r = 200; double s = 360.0 * syuukai / count; double rr = r / (count * 1.0); double rrr = r; double x; double y; for (double i = 0.0; i < 360.0 * syuukai; i += s) { double rad = Radian(i); x = (Math.Cos(rad) * rrr) + r; y = (Math.Sin(rad) * rrr) + r; MyKatori.AddPoint(new Point(x, y)); rrr -= rr; } MyCanvas.Children.Add(MyKatori); } public static double Radian(double degrees) { return Math.PI / 180.0 * degrees; } private void MyButton4_Click(object sender, RoutedEventArgs e) { MyPolyLineCanvas.ChangeVisibleThumb(); MyPolyLineCanvas2.ChangeVisibleThumb(); MyKatori?.ChangeVisibleThumb(); } } /// <summary> /// PolyLineとその各頂点にドラッグ移動できるThumbの表示するCanvas /// 頂点とThumbは連動している、連動動作は追加、削除、移動 /// 削除処理の対象は最後にクリックしたThumbに対応する頂点 /// </summary> public class PolyLineCanvas : Canvas { public readonly List<TThumb> MyThumbs = new(); public readonly PointCollection MyPoints = new(); public readonly Polyline MyPolyline; //クリックしたThumb public TThumb? MyCurrentThumb { get; private set; } public bool IsThumbVisible = true; public PolyLineCanvas(Brush stroke, double thickness) { MyPolyline = new() { Stroke = stroke, StrokeThickness = thickness, Points = MyPoints }; this.Children.Add(MyPolyline); } public void AddPoint(Point p) { TThumb t = new() { Width = 20, Height = 20 }; t.DragDelta += Thumb_DragDelta; t.PreviewMouseDown += Thumb_PreviewMouseDown; SetLeft(t, p.X); SetTop(t, p.Y); MyPoints.Add(p); MyThumbs.Add(t); this.Children.Add(t); } public void RemovePoint() { if (MyCurrentThumb is null) { return; } int i = MyThumbs.IndexOf(MyCurrentThumb); MyPoints.RemoveAt(i); MyThumbs.Remove(MyCurrentThumb); this.Children.Remove(MyCurrentThumb); MyCurrentThumb = null; } public void ChangeVisibleThumb() { if (IsThumbVisible) { for (int i = 1; i < MyThumbs.Count; i++) { MyThumbs[i].Visibility = Visibility.Collapsed; } IsThumbVisible = false; } else { for (int i = 1; i < MyThumbs.Count; i++) { MyThumbs[i].Visibility = Visibility.Visible; } IsThumbVisible = true; } } private void Thumb_PreviewMouseDown(object sender, MouseButtonEventArgs e) { MyCurrentThumb = sender as TThumb; } private void Thumb_DragDelta(object sender, DragDeltaEventArgs e) { if (sender is not TThumb t) { return; } double x = GetLeft(t) + e.HorizontalChange; double y = GetTop(t) + e.VerticalChange; Point p = new(x, y); int i = MyThumbs.IndexOf(t); MyPoints[i] = p; SetLeft(t, x); SetTop(t, y); } } public class TThumb : Thumb { public TThumb() { this.Template = MakeTemplate(); } private ControlTemplate MakeTemplate() { FrameworkElementFactory elementF = new(typeof(Rectangle)); elementF.SetValue(Rectangle.FillProperty, Brushes.Transparent); elementF.SetValue(Rectangle.StrokeProperty, Brushes.Black); elementF.SetValue(Rectangle.StrokeDashArrayProperty, new DoubleCollection() { 2.0 }); ControlTemplate template = new(typeof(Thumb)); template.VisualTree = elementF; return template; } } }
ControlTemplateを変更して見た目を変えたThumb
構成要素を1個のRectangleだけにした、その塗りつぶしはTransparent(透明色)にして、枠は黒の点線
PolyLineCanvasクラス
PolyLine表示とその頂点にThumbを表示、移動とかの動作管理する部分
前回はMainWindowに書いていたけど、分けたほうがわかりやすいかなと思って別のクラスにしてみた
Canvasを継承して自分自身にPolyLineを表示している、ここはよくわかっていない、継承しなくても良かったかも?
さっきのPolyLineCanvasを使う
作成時に線の色と線の太さを指定
あとは頂点を追加して、MyCanvasに追加すれば表示される、25~28行目
30~33行目は2つ目のPolyLineCanvas
別のクラスに分けたから管理しやすくなったと思う
これで起動すると
2つのPolyLineが表示された
Thumbの構成要素数
前回の6万から2万まで減らせた
これでさぞかし動作が軽くなったのかと思いきや、ほとんど変わらなかった
関連記事
次回のWPF記事
gogowaten.hatenablog.com
前回のWPF記事
gogowaten.hatenablog.com
点線枠
gogowaten.hatenablog.com
このときは構成要素数を増やさないほうが負荷が小さいと思っていたけど、今回の記事の限りではそんなことはなかったので、2色の点線表示はお手軽に2つのRectangleを重ねる方法が一番良さそうね
265日後、ついにAdornerを使う
gogowaten.hatenablog.com