前回の続きです。メニュー [サムネイル]を選択すると登録されているファイルのサムネイルが表示されます。さらにドラッグアンドドロップで順番を入れ替えることができます。
まずサムネイルを表示するためのユーザーコントロールを作成します。
ユーザーコントロールにチェックボックスと画像を表示するためのピクチャーボックス、ファイルのパスを表示するためのテキストボックスを貼り付けています。
UserControlを継承したUserControlExクラスを示します。
まずピクチャーボックスやユーザーコントロールでマウスが移動したときやマウスボタンが押されたときのイベントを定義しています。これでこのコントロールをフォームに貼り付けたときにどのユーザーコントロールがクリックされたのかがわかります。
それからサイズ変更がおこなわれたときにピクチャーボックスやテキストボックスが自動で適切な位置に表示されるようにAnchorプロパティを設定しています。
このユーザーコントロールの高さはピクチャーボックスの幅に対して、チェックボックスやテキストボックス分だけ大きくなります。幅だけ設定すると高さも変更できるようにWidthExプロパティを作成しています。
そのほかにも画像を表示させたり、チェックボックスがチェックされているのかがわかるようにするためのメソッドを定義しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
public partial class UserControlEx : UserControl { public delegate void MouseMoveHandler(UserControlEx sender, EventArgs e); public event MouseMoveHandler MouseMoveEx; public delegate void MouseDownHandler(UserControlEx sender,EventArgs e); public event MouseDownHandler MouseDownEx; public UserControlEx() { InitializeComponent(); pictureBox1.MouseDown += UserControlEx_MouseDown; this.MouseDown += UserControlEx_MouseDown; pictureBox1.MouseMove += UserControlEx_MouseMove; this.MouseMove += UserControlEx_MouseMove; pictureBox1.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; pictureBox1.BorderStyle = BorderStyle.None; textBox1.Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; textBox1.BorderStyle = BorderStyle.None; this.BorderStyle = BorderStyle.Fixed3D; } public int WidthEx { get { return this.Size.Width; } set { this.Size = new Size(value, value + 50); } } private void UserControlEx_MouseMove(object sender, MouseEventArgs e) { MouseMoveEx?.Invoke(this, new EventArgs()); } private void UserControlEx_MouseDown(object sender, MouseEventArgs e) { MouseDownEx?.Invoke(this, new EventArgs()); } public void SetImage(string path) { pictureBox1.SizeMode = PictureBoxSizeMode.Zoom; pictureBox1.ImageLocation = path; textBox1.Text = path; } public string GetPath() { return textBox1.Text; } public bool IsChecked() { return checkBox1.Checked; } public void SetChecked(bool isChecked) { checkBox1.Checked = isChecked; } } |
じっさいにサムネイルを表示するときは新しいダイアログを表示させて、上記のユーザーコントロールを並べて表示することになります。
以下のようなクラスになっています。
ダイアログが生成されるとDatasから登録されているファイルからUserControlExオブジェクトが生成され、ダイアログ上に並べられます。このとき画像ファイルのイメージも表示されます。
そしてマウスがUserControlExコントロールの上を移動するとそのファイル名が表示され、ドラッグアンドドロップでこれらの表示順を変更することができます。
ダイアログが閉じられるとDatasが再構築されます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
public partial class FormThumbnail : Form { public List<Data> Datas = new List<Data>(); List<UserControlEx> userControlIces = new List<UserControlEx>(); public FormThumbnail() { InitializeComponent(); panel1.Resize += Panel1_Resize; this.FormClosed += FormThumbnail_FormClosed; panel1.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; panel1.AutoScroll = true; numericUpDown1.Anchor = AnchorStyles.Left | AnchorStyles.Bottom; numericUpDown1.ValueChanged += NumericUpDown1_ValueChanged; labelFilePath.Anchor = AnchorStyles.Left | AnchorStyles.Bottom; } // ダイアログがロードされたらDatasから画像が描画されたユーザーコントロールが生成される // ダイアログのうえにあるパネルの幅に応じて生成されたユーザーコントロールが並べられる protected override void OnLoad(EventArgs e) { int left = 0; int top = 0; numericUpDown1.Value = 100; foreach (Data data in Datas) { UserControlEx controlEx = new UserControlEx(); controlEx.WidthEx = 100; controlEx.Location = new Point(left, top); controlEx.SetImage(data.FilePath); // イメージをセット controlEx.SetChecked(data.IsChecked); // チェックボックスの状態を反映させる // サムネイルは隣のものと縦横10ピクセルの隙間をあける left += controlEx.WidthEx + 10; if (panel1.Width < left + controlEx.Size.Width) { left = 0; top += controlEx.Size.Height + 10; } controlEx.Parent = panel1; userControlIces.Add(controlEx); // サムネイルをドラッグアンドドロップに対応させる // またマウスの移動にも対応させる controlEx.AllowDrop = true; controlEx.MouseDownEx += ControlEx_MouseDownEx; ; controlEx.DragOver += ControlEx_DragOver; controlEx.DragDrop += ControlEx_DragDrop; controlEx.MouseMoveEx += ControlEx_MouseMoveEx; } } private void ControlEx_MouseDownEx(UserControlEx sender, EventArgs e) { // クリックされたらドラッグの開始 DoDragDrop(sender, DragDropEffects.Move); } private void ControlEx_MouseMoveEx(UserControlEx sender, EventArgs e) { // UserControlExにフォーカスしていると // labelFilePath.Text = sender.GetPath();を実行したときに勝手にスクロールしてしまうので // numericUpDown1にフォーカスを設定する numericUpDown1.Focus(); labelFilePath.Text = sender.GetPath(); } // サムネイル上をサムネイルがドラッグされている場合はドロップが可能 private void ControlEx_DragOver(object sender, DragEventArgs e) { if (e.Data.GetDataPresent(typeof(UserControlEx))) { e.Effect = DragDropEffects.Move; } } int FirstLocationY = 0; // 最初のアイテムを表示するY座標 // サムネイル上にサムネイルがドロップされたら表示順を変更する private void ControlEx_DragDrop(object sender, DragEventArgs e) { if (e.Data.GetDataPresent(typeof(UserControlEx))) { FirstLocationY = userControlIces[0].Location.Y; UserControlEx controlFrom = (UserControlEx)e.Data.GetData(typeof(UserControlEx)); int indexFrom = userControlIces.IndexOf(controlFrom); UserControlEx controlTo = (UserControlEx)sender; int indexTo = userControlIces.IndexOf(controlTo); if (indexFrom > indexTo) { userControlIces.RemoveAt(indexFrom); userControlIces.Insert(indexTo, controlFrom); SetControls(); } if (indexFrom < indexTo) { userControlIces.RemoveAt(indexFrom); userControlIces.Insert(indexTo-1, controlFrom); } SetControls(); // indexFrom > indexToのときは2回必要な場合がある } } // ダイアログがリサイズされたらサムネイルも再表示する private void Panel1_Resize(object sender, EventArgs e) { if (userControlIces.Count > 0) { FirstLocationY = userControlIces[0].Location.Y; SetControls(); } } void SetControls() { int left = 0; int top = FirstLocationY; if (userControlIces.Count > 0) top = userControlIces[0].Location.Y; int newWidht = (int)numericUpDown1.Value; foreach (UserControlEx ctrl in userControlIces) { ctrl.Location = new Point(left, top); ctrl.WidthEx = newWidht; left += ctrl.WidthEx + 10; if (panel1.Width < left + ctrl.WidthEx) { left = 0; top += ctrl.Size.Height + 10; } } } // サムネイルの表示サイズの変更 private void NumericUpDown1_ValueChanged(object sender, EventArgs e) { if (userControlIces.Count > 0) { FirstLocationY = userControlIces[0].Location.Y; SetControls(); } } // ダイアログが閉じられたら、Dataをサムネイルの表示順どおりにDatasに格納する private void FormThumbnail_FormClosed(object sender, FormClosedEventArgs e) { Datas.Clear(); foreach (UserControlEx ctrl in userControlIces) { Datas.Add(new Data(ctrl.GetPath(), ctrl.IsChecked())); } } } |
あとはメインフォームのメニューの[サムネイル]がクリックされたらダイアログを表示し、閉じられたら変更を反映させます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
public partial class Form1 : Form { private void MenuItemThumbnail_Click(object sender, EventArgs e) { // ツリービューコントロールからファイルのパスとチェックボックスの状態を取得し // datasに格納する List<Data> datas = new List<Data>(); foreach (TreeNode node in treeView1.Nodes) datas.Add(new Data(node.Text, node.Checked)); // ダイアログを生成して datasを渡す FormThumbnail form2 = new FormThumbnail(); form2.Datas = datas; form2.ShowDialog(); // ダイアログが閉じられたら変更を反映させる treeView1.BeginUpdate(); treeView1.Nodes.Clear(); foreach (Data data in form2.Datas) { TreeNode node = new TreeNode(); node.Text = data.FilePath; node.Checked = data.IsChecked; treeView1.Nodes.Add(node); } treeView1.EndUpdate(); } } |