前提
splitContainer1.Panel2に
x軸の10間隔でラベルを自動生成し、罫線を作成しています。
左からData1,Data2~~~とラベルには値を入れています。
(Width1にして見えないようにしてます)
splitContainer1.Panel2をクリックした時に、
自動でラベルを作成するようにしました。(参考)
https://teratail.com/questions/oa0qgwebrssgdm#reply-lkzvdc0u3zkrd6
実現したいこと
クリックした位置に従い、Data1などの背面にある
ラベルの値を取得して表示させたいと思います。
「GetChildAtPoint」を利用すれば取得できそうなことは分かったのですが、
右から左にドラッグしてラベルを自動生成した時に
自動生成しているラベルを読み取ってしまいます。
リアルタイムで値をヒントテキストのように表示させるのが最終目標です。
該当のソースコード
【対応方法】
・スクロールバーの領域を含めた、splitContainer1.Panel1の座標を取得する
100,100で右下にスクロールした後に、1000,800などの値になれば
Data1のデータを逆算できます
→でも、なんとなく難しそう
・指定座標の特定名を含んだラベルを検索する
GetChildAtPointでラベルを取得する
試したこと
罫線のラベルを伸ばし、GetChildAtPointで取得する
next_data = splitContainer1.Panel2.GetChildAtPoint(new Point(next_x, 40)).Text;
(y座標40の位置までLabelを伸ばしました)
教えてほしい事
・マウスでドラッグしたまま枠外にでた場合などの対応方法
Mouse_Leaveでcontainerから出た時に終了させる処理を組もうとしましたが、
Leaveを認識せず断念。
・ヒントテキストをドラッグ中に表示させる方法
ラベルの値を常に取得できれば、それをツールチップに表示させられると思います。
何か他の動作に支障が出そうな気もしており、どうするか迷ってます。
ヒントテキストで問題ないでしょうか?
・ドラッグで自動生成しているラベルを重ねない方法
ドラッグしてラベルを自動生成していますが、
自動生成しているラベルを重ねたくありません。
重なるようだったら自動で確定するようにしたいです。
これが一番知りたいです…。
ラベルを新規挿せく制する際にBringToFront();としています。
補足情報(FW/ツールのバージョンなど)
.NET Framework 4.7.2
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

回答2件
0
ベストアンサー
Schedule Boardというフリーソフトがイメージに一番近いです。
なるほど横型のスケジュールのようなものですか(あるいはガントチャートのような)
商用ならそういうのもいっぱいあるんですけどねぇ^^;
暇だったので試しに作ってみましたが、思ったよりは少コードでできたなって印象です。
SplitContainer
の余計なお世話がウザかったので、さらにパネルを入れました(だいぶ座標計算が楽)
・マウスでドラッグしたまま枠外にでた場合などの対応方法
特に問題なさそう。
・ヒントテキストをドラッグ中に表示させる方法
ToolTip
で問題なし。
・ドラッグで自動生成しているラベルを重ねない方法
自動確定は嫌なので、移動・リサイズと同様に単に操作が効かないようにした。
cs
1using System; 2using System.Drawing; 3using System.Linq; 4using System.Windows.Forms; 5 6namespace Qozvvdivu7h1ow0 7{ 8 public partial class Form1 : Form 9 { 10 private const int cellWidth = 50; 11 private const int cellHeight = 30; 12 13 private readonly SplitContainer splitContainer1; // 本体部 14 private readonly SplitContainer splitContainer2; // ヘッダー部 15 private readonly TableLayoutPanel tableLayoutPanel1; // ヘッダー 16 private readonly PanelEx panel2; // グリッド線とPanel2の余計なお世話除け 17 private readonly ToolTip toolTip1 = new ToolTip(); 18 private readonly ContextMenuStrip contextMenuStrip1 = new ContextMenuStrip(); 19 private readonly Size halfCellSize = new Size(cellWidth / 2, cellHeight / 2); 20 21 private Label label; 22 private Point start; // ドラッグ開始位置(panel2基準) 23 private Point offset; // ドラッグ開始時のLabel内位置(label基準) 24 25 public Form1() 26 { 27 InitializeComponent(); 28 29 splitContainer1 = new SplitContainer 30 { 31 BorderStyle = BorderStyle.Fixed3D, 32 Dock = DockStyle.Fill, 33 }; 34 splitContainer1.Panel2.AutoScroll = true; 35 splitContainer1.Panel2.Paint += Panel2_Paint; // ヘッダー同期(Scrollイベントではスプリッターサイズ変更等でダメ) 36 splitContainer1.SplitterMoved += SplitContainer_SplitterMoved; // スプリッター同期 37 Controls.Add(splitContainer1); 38 39 panel2 = new PanelEx(cellWidth, cellHeight) 40 { 41 Size = new Size(cellWidth * 24 + 1, cellHeight * 10 + 1), 42 }; 43 panel2.MouseDown += Panel2_MouseDown; 44 panel2.MouseMove += Panel2_MouseMove; 45 panel2.MouseUp += Panel2_MouseUp; 46 splitContainer1.Panel2.Controls.Add(panel2); 47 48 // ヘッダー部 49 splitContainer2 = new SplitContainer 50 { 51 BorderStyle = BorderStyle.Fixed3D, 52 Dock = DockStyle.Top, 53 Height = 20, 54 }; 55 splitContainer2.SplitterMoved += SplitContainer_SplitterMoved; // スプリッター同期 56 Controls.Add(splitContainer2); 57 58 // ヘッダー 59 tableLayoutPanel1 = new TableLayoutPanel 60 { 61 ColumnCount = 25, // 23+2 23個の数字のマスと両端に半分サイズのマスでグリッド線上に数字が来るように 62 Width = cellWidth * 24 + 1, 63 Height = 20, 64 }; 65 66 tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100f / 24 / 2)); 67 tableLayoutPanel1.Controls.Add(new Label()); 68 for (var i = 1; i < 24; i++) 69 { 70 tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100f / 24)); 71 var label = new Label 72 { 73 Dock = DockStyle.Fill, 74 Text = $"{i}", 75 TextAlign = ContentAlignment.MiddleCenter, 76 }; 77 tableLayoutPanel1.Controls.Add(label); 78 } 79 tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100f / 24 / 2)); 80 splitContainer2.Panel2.Controls.Add(tableLayoutPanel1); 81 82 83 contextMenuStrip1.Items.Add("削除", null, ContextMenu_Click); 84 } 85 86 private void Panel2_MouseDown(object sender, MouseEventArgs e) 87 { 88 start = panel2.PointToClient(Cursor.Position); // 同じ new Point(e.X, e.Y); 89 offset = new Point(e.X % cellWidth, e.Y % cellHeight); 90 Cursor = Cursors.SizeWE; 91 92 var x = e.X / cellWidth * cellWidth; 93 var y = e.Y / cellHeight * cellHeight; 94 95 label = new Label 96 { 97 BackColor = Color.MistyRose, 98 BorderStyle = BorderStyle.FixedSingle, 99 ContextMenuStrip = contextMenuStrip1, 100 Location = new Point(x, y), 101 Size = new Size(cellWidth, cellHeight), 102 Text = "テスト", 103 TextAlign = ContentAlignment.MiddleCenter, 104 }; 105 label.MouseDown += Label_MouseDown; 106 label.MouseMove += Label_MouseMove; 107 label.MouseUp += Label_MouseUp; 108 109 panel2.Controls.Add(label); 110 } 111 private void Panel2_MouseMove(object sender, MouseEventArgs e) 112 { 113 if (label != null) TryResize(label); 114 } 115 private void Panel2_MouseUp(object sender, MouseEventArgs e) 116 { 117 Cursor = Cursors.Default; 118 if (label != null) toolTip1.Hide(label); 119 label = null; 120 } 121 122 private void Label_MouseDown(object sender, MouseEventArgs e) 123 { 124 if (sender is Label label) 125 { 126 // リサイズ時に反対の辺をstartに設定 127 offset = new Point(e.X, e.Y); 128 if (e.X < 8) 129 { 130 start = label.Location + label.Size - halfCellSize; 131 } 132 if (label.Width - 8 < e.X) 133 { 134 start = label.Location + halfCellSize; 135 } 136 } 137 } 138 private void Label_MouseMove(object sender, MouseEventArgs e) 139 { 140 if (sender is Label label) 141 { 142 if (e.Button == MouseButtons.None) 143 { 144 if (e.X < 8 || label.Width - 8 < e.X) label.Cursor = Cursors.SizeWE; 145 else label.Cursor = Cursors.Hand; 146 } 147 148 if (e.Button == MouseButtons.Left) 149 { 150 if (label.Cursor == Cursors.SizeWE) TryResize(label); 151 if (label.Cursor == Cursors.Hand) TryMove(label); 152 } 153 } 154 } 155 private void Label_MouseUp(object sender, MouseEventArgs e) 156 { 157 toolTip1.Hide((Label)sender); 158 } 159 160 private void ContextMenu_Click(object sender, EventArgs e) 161 { 162 if (sender is ToolStripMenuItem item && item.Owner is ContextMenuStrip contextMenu) 163 { 164 if (contextMenu.SourceControl is Label label) 165 { 166 label.MouseDown -= Label_MouseDown; 167 label.MouseMove -= Label_MouseMove; 168 label.MouseUp -= Label_MouseUp; 169 panel2.Controls.Remove(label); 170 } 171 } 172 } 173 174 // スプリッターの同期 175 private void SplitContainer_SplitterMoved(object sender, SplitterEventArgs e) 176 { 177 if (sender == splitContainer1 && splitContainer2 != null) 178 splitContainer2.SplitterDistance = splitContainer1.SplitterDistance; 179 if (sender == splitContainer2 && splitContainer1 != null) 180 splitContainer1.SplitterDistance = splitContainer2.SplitterDistance; 181 } 182 // ヘッダーの同期 183 private void Panel2_Paint(object sender, PaintEventArgs e) 184 { 185 var p = splitContainer1.Panel2.AutoScrollPosition; 186 tableLayoutPanel1.Left = p.X; 187 } 188 189 private void TryMove(Label target) 190 { 191 var p = panel2.PointToClient(Cursor.Position); 192 var x = (p.X - offset.X + cellWidth / 2) / cellWidth * cellWidth; 193 var y = (p.Y - offset.Y + cellHeight / 2) / cellHeight * cellHeight; 194 195 var rect = target.Bounds; 196 rect.X = x; 197 rect.Y = y; 198 TrySetBounds(target, rect); 199 } 200 private void TryResize(Label target) 201 { 202 var end = panel2.PointToClient(Cursor.Position); 203 var s = start.X / cellWidth * cellWidth; 204 var e = end.X / cellWidth * cellWidth; 205 var rect = target.Bounds; 206 207 if (start.X < end.X) 208 { 209 rect.X = s; // 本来不要なはずだが謎挙動に悩まされた... 210 rect.Width = e - s + cellWidth; 211 } 212 else 213 { 214 rect.X = e; 215 rect.Width = s - e + cellWidth; 216 } 217 TrySetBounds(target, rect); 218 } 219 private void TrySetBounds(Label target, Rectangle rect) 220 { 221 if (target.Bounds == rect) return; // ToolTipがちらつくし無駄なので 222 223 // panel2の中で自分以外と交差するものがあったら動かさない(=重ねられない) 224 foreach (var label in panel2.Controls.OfType<Label>()) 225 { 226 if (label == target) continue; 227 if (label.Bounds.IntersectsWith(rect)) return; 228 } 229 target.Bounds = rect; 230 231 var t = $"Location: {target.Location}\nSize: {target.Size}"; 232 toolTip1.Show(t, target, 0, -50); 233 } 234 } 235 236 237 public class PanelEx : Panel // グリッド線付きPanel 238 { 239 private readonly int cellWidth; 240 private readonly int cellHeight; 241 242 public PanelEx(int cellWidth, int cellHeight) 243 { 244 this.cellWidth = cellWidth; 245 this.cellHeight = cellHeight; 246 DoubleBuffered = true; 247 } 248 249 protected override void OnPaint(PaintEventArgs e) 250 { 251 base.OnPaint(e); 252 253 var right = ClientRectangle.Right; 254 var bottom = ClientRectangle.Bottom; 255 256 for (var x = 0; x < right; x += cellWidth) 257 { 258 e.Graphics.DrawLine(Pens.Gray, x, 0, x, bottom); 259 } 260 for (var y = 0; y < bottom; y += cellHeight) 261 { 262 e.Graphics.DrawLine(Pens.Gray, 0, y, right, y); 263 } 264 } 265 } 266}
投稿2022/04/09 10:24
編集2023/07/30 05:55総合スコア10022
0
右から左にドラッグしてラベルを自動生成した時に
自動生成しているラベルを読み取ってしまいます。
罫線のラベルを(さらに)パネルにくるんだりすればどうですか?
Panel2
にばらばらに入れるのではなく、Panel2
に入れたhogePanel
(例えばの名前)に罫線のラベルだけ入れればhogePanel.GetChildAtPoint
でいいことになります。
・マウスでドラッグしたまま枠外にでた場合などの対応方法
ドラッグ操作中はマウスキャプチャしてしまうほうが普通かなと思います。
マウス キャプチャ - Windows Forms .NET Framework | Microsoft Docs
例えばWindows標準のペイントでペンツールを使うとき(ドラッグ中)は、ウィンドウ外にマウスが出てもペン描画が継続します。
・ヒントテキストをドラッグ中に表示させる方法
なんのヒントなんですかね?前回の質問でいうピンクのラベルのサイズ等?
よくわかりませんがToolTip
でダメだったら、ほかの手段を考えることになりますね。
・ドラッグで自動生成しているラベルを重ねない方法
ピンクのラベルはすべてわかってるわけですから、計算することはできますよね?
全ラベルを交差判定しても、大した負荷でもないんじゃないですかね。
Rectangle.IntersectsWith(Rectangle) メソッド (System.Drawing) | Microsoft Docs
ピンクのラベルを(範囲選択のような感じで)、ドラッグで作るように変えたってことですよね?
「自動で確定」はUX的にどうか(ユーザーの意図に反してドラッグが終了する)とは思います(代案を思いついてるわけではないが^^;
そもそも罫線をラベルで表現する必要あるんでしょうか?
OnPaint
ででも線を引くだけでいいような。
Control.OnPaint(PaintEventArgs) メソッド (System.Windows.Forms) | Microsoft Docs
投稿2022/04/07 10:32
総合スコア10022
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2022/04/09 10:25
2022/04/11 02:59
2022/04/11 08:41
2022/04/13 07:02 編集