質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

1回答

8443閲覧

C#でpictureBoxの上に編集用の枠を描画したい

退会済みユーザー

退会済みユーザー

総合スコア0

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

0グッド

0クリップ

投稿2016/06/03 10:19

編集2022/01/12 10:55

pictureBoxの上に画像にあるような編集用の枠(移動・スケールあり)を作りたいと思っていますが、このような描画を作ったことがないのでどのように作るのかお教えいただければと思います。

イメージ説明

画像のグレーの部分がpictureBoxに表示される画像です。
そして破線の枠が今回作りたいと思っている編集用の枠です。

一応自分でやってみた方法は、pictureBoxの上にもうひとつ編集枠用のpictureBoxを表示してみました。

イメージ説明

しかし、編集枠の上下左右にある□をどうやって作るのかがわかりません。
ネットで検索しているのですが、そもそもこのような描画をなんていうのかわからず行き詰まりましたのでこちらで質問させていただきました。

なお、この編集枠は画像を表示するpictureBoxに描画はしない方法がよいです。マウスで移動したりスケールしたりしますので、pictureBoxの上に重ねるようにして配置したいです。
今は、
pictureBox_child.Parent = pictureBox_parent;
のようにしています。

どうぞ宜しくお願いします。

開発環境:
windows10 + VisualStudio 2015 C# FrameWork4 (or 4.5)


追加情報

右と下のラインをドラッグするとラインが残ってしまいます(上と左のラインは問題ありません)。
イメージ説明
イメージ説明

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

言われてみれば、私もその部分の正式名称を知りませんでした。なんて言うのですかね(サイズ変更つまみ?)。さすがに名前がわからないと検索難しいですね。

ちょっと判りづらいのですが、要するに、マウスのドラッグでサイズ変更できるような編集枠をPictureBoxで作りたいということでよろしいでしょうか。
それなら、ウィンドウメッセージのWM_NCHITTESTに反応して然るべき値を返せば、移動させたり端をドラッグしてサイズ変更したりできるようになります。

仮想メソッドをオーバーライドするので、PictureBoxを派生させる必要がありますが、このような感じでマウスによるサイズ変更と移動が可能なPictureBoxを作ることができます。

C#

1class SizablePictureBox : PictureBox 2{ 3 protected override void WndProc(ref Message m) 4 { 5 const int WM_NCHITTEST = 0x0084; 6 const int HTCAPTION = 2; 7 const int HTLEFT = 10; 8 const int HTRIGHT = 11; 9 const int HTTOP = 12; 10 const int HTTOPLEFT = 13; 11 const int HTTOPRIGHT = 14; 12 const int HTBOTTOM = 15; 13 const int HTBOTTOMLEFT = 16; 14 const int HTBOTTOMRIGHT = 17; 15 if(m.Msg == WM_NCHITTEST) 16 { 17 var pos = new Point((int)m.LParam & 0xFFFF, ((int)m.LParam >> 16) & 0xFFFF); 18 pos = this.PointToClient(pos); 19 if(pos.Y <= 20) 20 { 21 if(pos.X <= 20) 22 { 23 m.Result = (IntPtr)HTTOPLEFT; 24 } 25 else if(pos.X > this.Width - 20) 26 { 27 m.Result = (IntPtr)HTTOPRIGHT; 28 } 29 else 30 { 31 m.Result = (IntPtr)HTTOP; 32 } 33 } 34 else if(pos.Y > this.Height - 20) 35 { 36 if(pos.X <= 20) 37 { 38 m.Result = (IntPtr)HTBOTTOMLEFT; 39 } 40 else if(pos.X > this.Width - 20) 41 { 42 m.Result = (IntPtr)HTBOTTOMRIGHT; 43 } 44 else 45 { 46 m.Result = (IntPtr)HTBOTTOM; 47 } 48 } 49 else if(pos.X <= 20) 50 { 51 m.Result = (IntPtr)HTLEFT; 52 } 53 else if(pos.X > this.Width - 20) 54 { 55 m.Result = (IntPtr)HTRIGHT; 56 } 57 else 58 { 59 m.Result = (IntPtr)HTCAPTION; 60 } 61 return; 62 } 63 base.WndProc(ref m); 64 } 65}

この例では端のドラッグでサイズ変更、それより内側で移動となります。

投稿2016/06/03 13:13

catsforepaw

総合スコア5938

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2016/06/04 07:05 編集

ありがとうございます! まず、WndProcというのを初めて知りました・・・。 ウインドウメッセージを受け取って処理するメソッドなのですね。 ちょっと調べてみましたがなかなか難しい・・・。 catsforepawさんが示していただいたコードの処理、なぜこのようなことがわかるのかも今の私には到底及ばないものでした・・・。 なんとなくマウスの位置を取得して処理しているのはわかります。 あと、枠の上と左のライン(辺)をドラッグすると問題なくサイズ変更できるのですが、右と下のラインをドラッグすると描画がおかしくなります。 これはなぜそうなるのかわかりますでしょうか・・・? (※質問の追加情報に画像を追加しました。) また、枠の上下左右と四隅に□を描画することは可能でしょうか? (編集用枠としてpictureBoxを使わなくてもよいのですが・・・) お手数ですがどうぞ宜しくお願いします。
catsforepaw

2016/06/04 08:09

ウィンドウメッセージはWindowsのウィンドウ制御の仕組みを理解しないと難しいかもしれませんね。イベント駆動の一種ですが、そのメカニズムにメッセージ通信を利用するようなイメージで、各種機能を割り当てたメッセージをやりとりすることで様々な制御を行っています。 余計なラインが残るのは、たぶん、サイズが変わってラインを描き直す際に、前のを消さずに残しているからだと思います。 まず透明色(ARGB=0)でクリア(Clearメソッド)してからラインを描くようにすると余分なラインは残らないと思います。 □の描画は単純に`DrawRectangle`で良いのではないでしょうか。小さな正方形の左上と右下の座標を計算してDrawRectangleに渡せば四角を描いてくれます。
退会済みユーザー

退会済みユーザー

2016/06/04 08:46 編集

すみません、枠の上下左右の四隅の□は、PanelをpictuewBox_childの子にすることでとりあえず解決しました。 しかしせっかくお教えいただいたのでDrawRectangleでもやってみようと思います。 あと余計なラインの部分も修正してみます。 ご親切にありがとうございます! 次の質問なのですが、ドラッグ中にイベントを発行できるようにしたいのです。 ドラッグしてサイズや位置が変更されたらLabelにその数値を表示させようと思っています。
退会済みユーザー

退会済みユーザー

2016/06/04 08:54

何度もすみません・・・。 上記の >ドラッグ中にイベントを発行できるようにしたいのです。 >ドラッグしてサイズや位置が変更されたらLabelにその数値を表示させようと思っています。 これは単純にMoveイベントを追加するだけで実現できました。 protected override void WndProc(ref Message m)メソッドの中にイベントを書かないといけないかと思っていました。
catsforepaw

2016/06/04 09:48

> これは単純にMoveイベントを追加するだけで実現できました。 はい。WndProcメソッドの最後で基底クラスのメソッドを呼んでいるので、WM_NCHITTEST以外は従来のままで問題ありません。 > PanelをpictuewBox_childの子にすることでとりあえず解決しました。 □部分を別のコントロールで表示するという発想は思いつきませんでした。確かにそれでもいけそうですね。 ただ、フォームアプリでは透過処理をさせると描画がかなり重くなるので、いくつもコントロールを重ねると、ドラッグで動かしたときに表示が乱れるかもしれません。 グラフィカルなアプリを作るときは`WPF`(Windows Presentation Foundation)が具合が良いですよ。描画処理にDirect3Dを使っているのでフォームアプリと違って透過処理は本物ですし、描画処理が軽いのでコントロールを何枚重ねても平気です。編集枠を例に挙げると、フォームアプリではビットマップに絵を描くというやり方ですが、WPFでは絵の構成要素を配置する、というアプローチが有効なのでクリアして描き直す必要がなくなります。結果、負荷も軽くできます。 フォームアプリとは仕組みが違うのですぐに移行できるものではありませんが、興味がおありならいろいろいじってみると面白いかもしれませんよ。
退会済みユーザー

退会済みユーザー

2016/06/04 11:07

いろいろとありがとうございます! >ただ、フォームアプリでは透過処理をさせると描画がかなり重くなるので、いくつもコントロールを重ねると、ドラッグで動かしたときに表示が乱れるかもしれません。 はい・・・すでにPictureBoxの上にpictureBoxを重ねているので下のほうのpictureBoxに表示している画像が移動などで乱れてしまっています・・・。 なのでDrawRectangleで描画してみようと思います。 >グラフィカルなアプリを作るときは`WPF`(Windows Presentation Foundation)が具合が良いですよ。 そうなのですね。WPFもいろいろやってみたのですがかんり勉強しないと作れそうになかったので今回見送りました。また次の機会に挑戦してみようと思います。 また、以下の >まず透明色(ARGB=0)でクリア(Clearメソッド)してからラインを描くようにすると余分なラインは残らないと思います。 はPictureBox_child.Reflesh()を実行することで再描画されました。 いろいろとありがとうございました! かなり実現できそうな感じです!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問