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

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

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

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

Q&A

1回答

3452閲覧

再投稿。カラーパレット任意の座標に表示する方法

DENQ

総合スコア19

C#

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

0グッド

0クリップ

投稿2016/05/23 03:58

編集2016/05/31 02:13

お世話になっております。
再度、質問させてください。

現在、お絵かきソフトの様なプログラムを作成しております。
カラーパレット表示ボタンを押下時にカラーパレットを任意の座標に表示させるという動作はサイトを参考にして実現できたのですが、pictureBoxをクリックした後にカラーパレットの標示させるボタンを押すと画面がフリーズしてしまいます。カラーパレットのボタン部分はToolStripを使用しています。

※追記部分
分かった事。
1、dlg.ShowDialog()の時に引数としてtopmostのFromを入れていない事が原因でした。

2、pictureBoxをクリックした後にカラーパレット表示用ボタン押下時にカラーパレットが表示されない。
手前のプログラムはユーザーコントロールでPictureBoxを継承しており、自作でマウスムーブイベントを作っています。
dlg.ShowDialog(this)にする事によりpictureBoxをクリックしたあとalt + Tabを押下し再度アプリケーションに戻れば、カラーパレットは表示されるようになりました。
しかし、やりたい事はカラーパレットボタンを押下した時にfromの最前に表示される事です。
そこでユーザーコントロール(PictureBox)のイベントを一度すべて消しpictureBoxをクリックまたはムーブ後、カラーパレットボタンを押下したら
期待通りにカラーパレットが表示されました。
切り分けにより、マウスムーブイベントでカラーパレットがFromの後ろに行くということが判明。
以下、マウスムーブイベントの切り分けした結果を記載します。

マウスムーブイベントがしている事
pictureBoxのbitmapのZoomサイズの取得
マウスの開始点の座標を取得
refreshで再描画
マウスの終了点の座標を取得

切り分け
1 マウスムーブイベント全てをコメントアウト
ピクチャーボックスをクリックしてカラーボックス表示ボタンを押下
期待の場所にカラーボックスが表示される
ただし、penや消しゴムでの描画ができなくなってしまう。
(本末転倒)

2 マウスムーブイベント左クリック内の座標取得部分をコメントアウト
ピクチャーボックスをクリックしてカラーボックス表示ボタンを押下
カラーパレットがFromの後ろに行く Alt +Tabで表示可能
ペンや消しゴムを使えない上に表示もできない。

3 マウスムーブイベントのrefresh()部分だけをコメントアウト
ピクチャーボックスをクリックしてカラーボックス表示ボタンを押下
期待の場所にカラーボックスが表示される
ただし、penや消しゴムでの描画ができなくなってしまう。
(本末転倒)

切り分け結果
開始点と終了点の間にrefresh()をしているのですが、このrefresh()が原因でカラーパレットが表示されない(Fromの後ろに行く) 事が判明しました。

聞きたい事
なぜrefreshをすることによりカラーパレットがfromの後ろに行くのか。
ペンや消しゴムを使えた上でカラーパレットも表示できるようにするにはどうすればよいでしょうか?
マウスムーブイベントで取得した開始点と終了点を元にペンモードや消しゴムを描画しているのでなくてはならない機能だと考えております。
お手数ですが、ご教授よろしくお願い足します。

実際のコード
private const float INIT_POINT = 99999.9f;
/// 開始:X座標、Y座標
private PointF _st = new PointF(INIT_POINT, INIT_POINT);
/// 終了:X座標、Y座標
private PointF _ed = new PointF(INIT_POINT, INIT_POINT);
//画像取り込み用ビットマップ
public Bitmap bmp;

ボタン押下処理
ColorDialogEx dlg = new ColorDialogEx();
private void StripColorBtn_Click(object sender, EventArgs e) {
// OekakiPaint の左上隅にダイアログボックスの座標を合わせて表示する
Point p = this.PointToScreen(new Point(OekakiPaint.Left + 20, OekakiPaint.Top + 30));
dlg.Position = p;
dlg.AllowFullOpen = false;
if (dlg.ShowDialog(this) == DialogResult.OK)
this.StripSelectColorBtn.BackColor = dlg.Color;
}

//マウスムーブイベント
private void MouseMove(object sender, MouseEventArgs e) {
// 左クリック押下中
if (e.Button == MouseButtons.Left) {
// ZOOM率に合わせたサイズを取得
SizeF size = this.getZoomSize();
//// コントロール側の座標値と描画用BITMAP座標値の計算:終点
this._ed.X = e.X - (((float)this.ClientSize.Width - size.Width) / 2);
this._ed.X = this._ed.X * ((float)this.bmp.Width / size.Width);
this._ed.Y = e.Y - (((float)this.ClientSize.Height - size.Height) / 2);
this._ed.Y = this._ed.Y * ((float)this.bmp.Height / size.Height);
//// 再描画
this.Refresh();
//// コントロール側の座標値と描画用BITMAP座標値の計算:始点
this._st.X = e.X - (((float)this.ClientSize.Width - size.Width) / 2);
this._st.X = this._st.X * ((float)this.bmp.Width / size.Width);
this._st.Y = e.Y - (((float)this.ClientSize.Height - size.Height) / 2);
this._st.Y = this._st.Y * ((float)this.bmp.Height / size.Height);
}
}

//画面サイズの取得
public SizeF getZoomSize() {
float img_w = this.bmp.Width;
float img_h = this.bmp.Height;
float pic_w = this.ClientSize.Width;
float pic_h = this.ClientSize.Height;

float mag_w = pic_w / img_w; float mag_h = pic_h / img_h; SizeF zoomSize; if (mag_w < mag_h) { zoomSize = new SizeF(img_w * mag_w, img_h * mag_w); } else { zoomSize = new SizeF(img_w * mag_h, img_h * mag_h); } return zoomSize; }

別クラス
internal class ColorDialogEx : ColorDialog {
private Point FPosition;
public Point Position { set { FPosition = value; } }

public ColorDialogEx() : base() { } protected override IntPtr HookProc(IntPtr hWnd, int msg, IntPtr wparam, IntPtr lparam) { if (msg == 0x110) { // WM_INITDIALOG{ RECT r = new RECT(); // ダイアログボックスの位置とサイズを取得する GetWindowRect(hWnd, ref r); // ダイアログボックスの位置を変更する MoveWindow(hWnd, FPosition.X, FPosition.Y, r.right - r.left, r.bottom - r.top, true); return IntPtr.Zero; // HookProc メソッドでメッセージを処理済みにする } // WM_INIDIALOG 以外のメッセージに対しては元のコントロールにまかせる return base.HookProc(hWnd, msg, wparam, lparam); } [DllImport("user32.dll", CharSet = CharSet.Auto)] private static extern bool GetWindowRect(IntPtr hWnd, [In, Out] ref RECT lpRect); [DllImport("user32.dll", CharSet = CharSet.Auto)] private static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint); [StructLayout(LayoutKind.Sequential)] private struct RECT { public int left; public int top; public int right; public int bottom; }

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

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

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

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

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

gusao

2016/05/27 05:58

StripColorBtn_Click()の前にColorDialogExのインスタンスを作成していますが、StripColorBtn_Click()以外でも参照しているのでしょうか? もしそうでしたら、参照している箇所のコードを教えてください。
DENQ

2016/05/27 06:11 編集

public ArchForm(ArchBusiness business) : base() { // インスタンス変数へ退避 _business = business; // 画面構成部品の生成 InitializeComponent(); //デフォルトカラー archPaint._selectColor = dlg.Color; } 初期値の色を指定する為に一度使用しています。
gusao

2016/05/27 07:12

うーん…手元の環境でいろいろやってますが、再現しませんね… dlgにColorDialogExではなく、ColorDialogのインスタンスを設定しても固まってしまいますか? StripColorBtn_Click()イベントをステップ実行して、どこで固まるのか教えていただけますか?
DENQ

2016/05/27 07:29

固まる場所はStripColorBtn_Click()の中の dlg.AllowFullOpen = false; まで行ってそのあとprotected override IntPtr HookProc()に入ってif (msg == 0x110) のif文の中を入らずずっと return base.HookProc(hWnd, msg, wparam, lparam); 行ってメソッドの最初に戻って永遠にそこでループしてる状態です。
DENQ

2016/05/27 07:30

ColorDialogExをインスタンスしないでColorDialogのインスタンスを作成してもColorDialogEx内で座標計算してるのでたぶん、思うように座標が取れないと思います。一応やってみます。
DENQ

2016/05/27 07:32

ColorDialogだと座標を指定するdig.Positionが使えなくなるので、デフォルトで中央に表示される使用となるはずです。
guest

回答1

0

こんにちわ。

dlg.Dispose();

とダイアログのインスタンスを破棄してますが、
どこかで新たにnew しているのでしょうか?

投稿2016/05/24 10:19

mugicya

総合スコア1046

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

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

DENQ

2016/05/25 01:34

お返事ありがとうございます。 最初にインスタンスは作成しております。 ボタンが押された時にインスタンスを作成するという処理も試してみたのですが、変わらない状況です。
mugicya

2016/05/25 03:55 編集

なるほど。 using(dlg = new ColorDialogEx()) { Point p = this.PointToScreen(new Point(archPaint.Left + 20, archPaint.Top + 30)); dlg.Position = p; dlg.AllowFullOpen = false; if (dlg.ShowDialog() == DialogResult.OK) this.StripSelectColorBtn.BackColor = dlg.Color; archPaint._selectColor = dlg.Color; } としてもダメでしょうか? というのは、一度表示して Disposeされているので、2回目以降は正常に動かない気がします。
DENQ

2016/05/25 07:41

mugicyaさんのコードでやってみましたがダメでした。 状況としてはアプリケーションを立ち上げてすぐにカラー選択ボタンを押下すれば、カラーパレットは開いてくれます。 しかし、何かしらの動作(penで絵をかいたり、文字を入力したり、消しゴムでペイントを消す)と言った作業をした後にカラーパレットを開くボタンを押下すると画面が固まるようです。ステップ実行でColorDialogEx クラスのHookProcメソッドにブレイクポイントを置くと止まりますが、if分に入らず永遠とループしてるようです。 そのせいでカラーパレットを表示する座標を取得する事が出来ず、永遠とループしているため表面上では画面が固まっているようになっていると思われます。 他に手がかりがございました、またご教授お願いします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

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

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

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問