回答編集履歴

1

見直しキャンペーン中

2023/07/17 13:47

投稿

TN8001
TN8001

スコア9337

test CHANGED
@@ -1,341 +1,171 @@
1
1
  > PhotoShopの機能を模倣していくこと
2
+
3
+ 入門者にはあまりに壮大な目標に感じますが、まあどこまでやるかによりますね。
4
+
5
+ PhotoShopは持っていませんが、ツールバーにある[TEXT]ボタンを選択して画面をクリックするとそこに枠が出る(ドラッグで範囲指定?)みたいなやつですね?
6
+ フォントや色を変更できて、欲を言えばマウスで移動やリサイズができる。と
7
+
8
+
9
+ 凝ったUIの作りこみはロジック以上に難しいことが多いです(私はあまり手を出さないようにしています^^;
10
+ とはいえ出発点としてミニマムかつ、そこそこ遊べるような参考コードを書いてみました。
11
+
12
+ [仕様]
13
+ 画像エリアをダブルクリックでその場所に`TextBox`を生成
14
+ `TextBox`の右クリックメニューに削除(コピー等は`TextBox`のコピーではなく、テキストのコピー)
15
+ テキストの編集はその場で可能(複数行に対応)
16
+ ほかのプロパティは`PropertyGrid`で編集(クリックした`TextBox`を`PropertyGrid`に割り当てるため、選択が少し重いです)
17
+ - 移動は`CanvasLeft`・`CanvasTop`
18
+ - サイズは`Width`・`Height`(`NaN`で自動調整)
19
+ - フォントはFontなんちゃら
20
+ - 色は`Foreground`
2
21
 
3
22
 
4
23
 
5
- 入門者にはあまりに壮大な目標に感じますが、まあどこまでやるによりますね。
24
+ NuGetら`Extended.Wpf.Toolkit`をインストールしてください(`PropertyGrid`だけ使います
6
25
 
7
-
8
-
9
- PhotoShopは持っていませんが、ツールバーにある[TEXT]ボタンを選択して画面をクリックするとそこに枠が出る(ドラッグで範囲指定?)みたいなやつですね?
10
-
11
- フォントや色を変更できて、欲を言えばマウスで移動やリサイズができる。と
12
-
13
-
14
-
15
-
16
-
17
- 凝ったUIの作りこみはロジック以上に難しいことが多いです(私はあまり手を出さないようにしています^^;
18
-
19
- とはいえ出発点としてミニマムかつ、そこそこ遊べるような参考コードを書いてみました。
20
-
21
-
22
-
23
- [仕様]
24
-
25
- 画像エリアをダブルクリックでその場所にTextBoxを生成
26
-
27
- TextBoxの右クリックメニューに削除(コピー等はTextBoxのコピーではなく、テキストのコピー)
28
-
29
- テキストの編集はその場で可能(複数行に対応)
30
-
31
- ほかのプロパティはPropertyGridで編集(クリックしたTextBoxをPropertyGridに割り当てるため、選択が少し重いです)
32
-
33
- - 移動はCanvasLeft CanvasTop
34
-
35
- - サイズはWidth Height(NaNで自動調整)
36
-
37
- - フォントはFontなんちゃら
38
-
39
- - 色はForeground
40
-
41
-
42
-
43
-
44
-
45
-
46
-
47
- NuGetから`Extended.Wpf.Toolkit`をインストールしてください(PropertyGridだけ使います)
48
-
49
-
50
-
51
- ```xaml
26
+ ```xml
52
-
53
27
  <Window
54
-
55
28
  x:Class="Questions233943.MainWindow"
56
-
57
29
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
58
-
59
30
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
60
-
61
31
  xmlns:local="clr-namespace:Questions233943"
62
-
63
32
  xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
64
-
65
33
  Width="800"
66
-
67
34
  Height="450">
68
-
69
35
  <Window.Resources>
70
-
71
36
  <ContextMenu x:Key="TextBoxContextMenu">
72
-
73
37
  <MenuItem Command="ApplicationCommands.Copy" />
74
-
75
38
  <MenuItem Command="ApplicationCommands.Cut" />
76
-
77
39
  <MenuItem Command="ApplicationCommands.Paste" />
78
-
79
40
  <MenuItem Click="DelMenuItem_Click" Header="削除" />
80
-
81
41
  </ContextMenu>
82
42
 
83
-
84
-
85
43
  <Style x:Key="TextBoxStyle" TargetType="{x:Type local:TextBoxEx}">
86
-
87
44
  <Setter Property="AcceptsReturn" Value="True" />
88
-
89
45
  <Setter Property="AcceptsTab" Value="True" />
90
-
91
46
  <Setter Property="Background" Value="{x:Null}" />
92
-
93
47
  <Setter Property="BorderBrush" Value="{x:Null}" />
94
-
95
48
  <Setter Property="ContextMenu" Value="{StaticResource TextBoxContextMenu}" />
96
-
97
49
  <Setter Property="FontSize" Value="16px" />
98
-
99
50
  <Setter Property="FontWeight" Value="bold" />
100
-
101
51
  <Setter Property="Foreground" Value="Red" />
102
-
103
52
  <Setter Property="Text" Value="テキスト" />
104
-
105
53
  <Setter Property="TextWrapping" Value="Wrap" />
106
-
107
54
  <Setter Property="Template">
108
-
109
55
  <Setter.Value>
110
-
111
56
  <ControlTemplate TargetType="{x:Type TextBox}">
112
-
113
57
  <Border
114
-
115
58
  x:Name="border"
116
-
117
59
  Background="{TemplateBinding Background}"
118
-
119
60
  BorderBrush="{TemplateBinding BorderBrush}"
120
-
121
61
  BorderThickness="{TemplateBinding BorderThickness}"
122
-
123
62
  SnapsToDevicePixels="True">
124
-
125
63
  <ScrollViewer
126
-
127
64
  x:Name="PART_ContentHost"
128
-
129
65
  Focusable="false"
130
-
131
66
  HorizontalScrollBarVisibility="Hidden"
132
-
133
67
  VerticalScrollBarVisibility="Hidden" />
134
-
135
68
  </Border>
136
-
137
69
  <ControlTemplate.Triggers>
138
-
139
70
  <Trigger Property="IsMouseOver" Value="true">
140
-
141
71
  <Setter TargetName="border" Property="BorderBrush" Value="#FF7EB4EA" />
142
-
143
72
  </Trigger>
144
-
145
73
  <Trigger Property="IsFocused" Value="true">
146
-
147
74
  <Setter TargetName="border" Property="BorderBrush" Value="#FF7EB4EA" />
148
-
149
75
  </Trigger>
150
-
151
76
  </ControlTemplate.Triggers>
152
-
153
77
  </ControlTemplate>
154
-
155
78
  </Setter.Value>
156
-
157
79
  </Setter>
158
-
159
80
  </Style>
160
-
161
81
  </Window.Resources>
162
-
163
82
  <Grid>
164
-
165
83
  <Grid.ColumnDefinitions>
166
-
167
84
  <ColumnDefinition Width="2*" />
168
-
169
85
  <ColumnDefinition Width="5" />
170
-
171
86
  <ColumnDefinition />
172
-
173
87
  </Grid.ColumnDefinitions>
174
-
175
88
  <Canvas x:Name="canvas" MouseLeftButtonDown="Canvas_MouseLeftButtonDown">
176
-
177
89
  <Image Source="Resources\whippet.jpg" />
178
-
179
90
  </Canvas>
180
-
181
91
  <GridSplitter Grid.Column="1" HorizontalAlignment="Stretch" />
182
-
183
92
  <xctk:PropertyGrid x:Name="propertyGrid" Grid.Column="2" />
184
-
185
93
  </Grid>
186
-
187
94
  </Window>
188
-
189
95
  ```
190
96
 
191
-
192
-
193
- ```C#
97
+ ```cs
194
-
195
98
  using System.Windows;
196
-
197
99
  using System.Windows.Controls;
198
-
199
100
  using System.Windows.Input;
200
101
 
201
-
202
-
203
102
  namespace Questions233943
204
-
205
103
  {
206
-
207
104
  // PropertyGridでいじれるようにCanvas.Left Canvas.Topをラップ
208
-
209
105
  public class TextBoxEx : TextBox
210
-
211
106
  {
212
-
213
107
  public static readonly DependencyProperty CanvasLeftProperty
214
-
215
108
  = DependencyProperty.Register(nameof(CanvasLeft), typeof(double), typeof(TextBoxEx),
216
-
217
109
  new FrameworkPropertyMetadata(0d, new PropertyChangedCallback(OnCanvasLeftChanged)));
218
-
219
110
  public double CanvasLeft { get => (double)GetValue(CanvasLeftProperty); set => SetValue(CanvasLeftProperty, value); }
220
-
221
111
  private static void OnCanvasLeftChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
222
-
223
112
  {
224
-
225
113
  if(obj is TextBoxEx ctrl) Canvas.SetLeft(ctrl, ctrl.CanvasLeft);
226
-
227
114
  }
228
115
 
116
+ public static readonly DependencyProperty CanvasTopProperty
117
+ = DependencyProperty.Register(nameof(CanvasTop), typeof(double), typeof(TextBoxEx),
118
+ new FrameworkPropertyMetadata(0d, new PropertyChangedCallback(OnCanvasTopChanged)));
119
+ public double CanvasTop { get => (double)GetValue(CanvasTopProperty); set => SetValue(CanvasTopProperty, value); }
120
+ private static void OnCanvasTopChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
121
+ {
122
+ if(obj is TextBoxEx ctrl) Canvas.SetTop(ctrl, ctrl.CanvasTop);
123
+ }
124
+ }
229
125
 
126
+ public partial class MainWindow : Window
127
+ {
128
+ public MainWindow() => InitializeComponent();
230
129
 
231
- public static readonly DependencyProperty CanvasTopProperty
232
-
233
- = DependencyProperty.Register(nameof(CanvasTop), typeof(double), typeof(TextBoxEx),
234
-
235
- new FrameworkPropertyMetadata(0d, new PropertyChangedCallback(OnCanvasTopChanged)));
236
-
237
- public double CanvasTop { get => (double)GetValue(CanvasTopProperty); set => SetValue(CanvasTopProperty, value); }
238
-
239
- private static void OnCanvasTopChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
130
+ private void Canvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
240
-
241
131
  {
242
-
132
+ if(e.ClickCount == 2)
133
+ {
134
+ var textBox = new TextBoxEx
135
+ {
136
+ Style = FindResource("TextBoxStyle") as Style,
243
- if(obj is TextBoxEx ctrl) Canvas.SetTop(ctrl, ctrl.CanvasTop);
137
+ CanvasLeft = e.GetPosition(canvas).X,
244
-
138
+ CanvasTop = e.GetPosition(canvas).Y
139
+ };
140
+ textBox.GotFocus += TextBox_GotFocus;
141
+ canvas.Children.Add(textBox);
142
+ }
245
143
  }
246
144
 
247
- }
248
-
249
-
250
-
251
- public partial class MainWindow : Window
252
-
253
- {
254
-
255
- public MainWindow() => InitializeComponent();
256
-
257
-
258
-
259
- private void Canvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
260
-
261
- {
262
-
263
- if(e.ClickCount == 2)
264
-
265
- {
266
-
267
- var textBox = new TextBoxEx
268
-
269
- {
270
-
271
- Style = FindResource("TextBoxStyle") as Style,
272
-
273
- CanvasLeft = e.GetPosition(canvas).X,
274
-
275
- CanvasTop = e.GetPosition(canvas).Y
276
-
277
- };
278
-
279
- textBox.GotFocus += TextBox_GotFocus;
280
-
281
- canvas.Children.Add(textBox);
282
-
283
- }
284
-
285
- }
286
-
287
-
288
-
289
145
  private void TextBox_GotFocus(object sender, RoutedEventArgs e)
290
-
291
146
  => propertyGrid.SelectedObject = sender;
292
147
 
293
-
294
-
295
148
  private void DelMenuItem_Click(object sender, RoutedEventArgs e)
296
-
297
149
  {
298
-
299
150
  if(sender is MenuItem menuItem)
300
-
301
151
  {
302
-
303
152
  if(menuItem.Parent is ContextMenu contextMenu)
304
-
305
153
  {
306
-
307
154
  if(contextMenu.PlacementTarget is TextBoxEx textBox)
308
-
309
155
  {
310
-
311
156
  propertyGrid.SelectedObject = null;
312
-
313
157
  textBox.GotFocus -= TextBox_GotFocus;
314
-
315
158
  canvas.Children.Remove(textBox);
316
-
317
159
  }
318
-
319
160
  }
320
-
321
161
  }
322
-
323
162
  }
324
-
325
163
  }
326
-
327
164
  }
328
-
329
165
  ```
330
-
331
-
332
166
 
333
167
  ---
334
168
 
335
-
336
-
337
169
  マウスでサイズ変更・移動をちゃんとやるなら、この辺を参考に頑張ってください。
338
-
339
170
  * 大変古いが公式の [ResizingAdorner のサンプル | Microsoft Docs](https://docs.microsoft.com/ja-jp/previous-versions/dotnet/netframework-3.5/ms771714(v=vs.90)?redirectedfrom=MSDN)(ざっとやってみたが移動とテキストの編集を、どう両立させるかがむずかしい)
340
-
341
171
  * 「WPF ラバーバンド」あたりで検索