C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[10]: カラーパレット任意の座標に表示する


(過去ログ 136 を表示中)

[トピック内 22 記事 (1 - 20 表示)]  << 0 | 1 >>

■79858 / inTopicNo.1)  カラーパレット任意の座標に表示する
  
□投稿者/ kazu (1回)-(2016/05/24(Tue) 11:46:05)

分類:[C#] 

お世話になっております。
現在、お絵かきソフトの様なプログラムを作成しております。
カラーパレット表示ボタンを押下時にカラーパレットを任意の座標に表示させるという動作はサイト(http://www.kanazawa-net.ne.jp/~pmansato/net/net_technics.htm)を参考にして実現できたのですが、
mainの画面が表示されれ、penで絵をかいたり、文字を入力した後に、カラーパレットボタンを押下した時に画面が固まる現象が起きています。

実際のコード

ボタン押下処理
private void StripColorBtn_Click(object sender, EventArgs e) {
// archPaint の左上隅にダイアログボックスの座標を合わせて表示する
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;
dlg.Dispose();
}

別クラス
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{ ←ここのif文がおかしいと思われる。
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;
}

ステップ実行してみると、if (msg == 0x110) 部分でmsg == 0x110がfalseになるため中の処理に入らず、永遠とループしている状態で座標が取れず表示ができないという状況になっているように見えます。
解決方法が見当たらず、困っております。
皆さま、ご教授よろしくお願いいたします。
引用返信 編集キー/
■79887 / inTopicNo.2)  Re[1]: カラーパレット任意の座標に表示する
□投稿者/ 魔界の仮面弁士 (727回)-(2016/05/26(Thu) 13:51:43)
No79858 (kazu さん) に返信
> dlg.Position = p;
  (中略)
> dlg.Dispose();

ShowDialog 後に、毎回 Dispose しているのは何故ですか?

StripColorBtn_Click で都度都度 new ColorDialogEx() しているのであればともかく、
もしもデザイン時に貼ったまま使っているのであれば、Dispose してはマズイでしょう。

このクラスに関しては Dispose してもしなくても変わりませんし、
そのことが本件に影響するかどうかは別問題ですけれども…。


> if (dlg.ShowDialog() == DialogResult.OK)
> this.StripSelectColorBtn.BackColor = dlg.Color;
> archPaint._selectColor = dlg.Color;

それだと

if (dlg.ShowDialog() == DialogResult.OK) {
 this.StripSelectColorBtn.BackColor = dlg.Color;
 archPaint._selectColor = dlg.Color;
}

ではなく、

if (dlg.ShowDialog() == DialogResult.OK) {
 this.StripSelectColorBtn.BackColor = dlg.Color;
}
archPaint._selectColor = dlg.Color;

の意味になりますが、本当にそれで良いのですか?



> GetWindowRect(hWnd, ref r);
ref ではなく out 引数の方が良いと思います。間違いではありませんけれどね。


> ステップ実行してみると、
メッセージ処理を阻害する可能性があるので、この場合のステップ実行は控えましょう。


> if (msg == 0x110) 部分でmsg == 0x110がfalseになるため中の処理に入らず、
その場合の msg は何でしたか?


> 永遠とループしている状態で
そもそも HookProc は WM_INIDIALOG 専用というわけではなく、
いろいろな msg 値が幾度も幾度も飛んでくる仕様です。

コメントにも「// WM_INIDIALOG 以外のメッセージに対しては」と書かれていますよね。
引用返信 編集キー/
■79910 / inTopicNo.3)  Re[2]: カラーパレット任意の座標に表示する
□投稿者/ kazu (3回)-(2016/05/27(Fri) 16:49:09)
No79887 (魔界の仮面弁士 さん) に返信
> ■No79858 (kazu さん) に返信
>>dlg.Position = p;
>   (中略)
>>dlg.Dispose();
>
> ShowDialog 後に、毎回 Dispose しているのは何故ですか?
>
> StripColorBtn_Click で都度都度 new ColorDialogEx() しているのであればともかく、
> もしもデザイン時に貼ったまま使っているのであれば、Dispose してはマズイでしょう。
>
> このクラスに関しては Dispose してもしなくても変わりませんし、
> そのことが本件に影響するかどうかは別問題ですけれども…。
>
>
使用的によくわからず、いろんなサイトを参考にして書いているため、disposeしました。
メソッド内でnewしてない場合はdisposeしない方がいいと言うのをしりませんでした。



>>if (dlg.ShowDialog() == DialogResult.OK)
>>this.StripSelectColorBtn.BackColor = dlg.Color;
>>archPaint._selectColor = dlg.Color;
>
> それだと
>
> if (dlg.ShowDialog() == DialogResult.OK) {
>  this.StripSelectColorBtn.BackColor = dlg.Color;
>  archPaint._selectColor = dlg.Color;
> }
>
> ではなく、
>
> if (dlg.ShowDialog() == DialogResult.OK) {
>  this.StripSelectColorBtn.BackColor = dlg.Color;
> }
> archPaint._selectColor = dlg.Color;
>
> の意味になりますが、本当にそれで良いのですか?
>
>


こちらのロジックは問題ありません。




>
>>GetWindowRect(hWnd, ref r);
> ref ではなく out 引数の方が良いと思います。間違いではありませんけれどね。
>
>
まだrefとoutの違いをきちんと理解していないため、わかりませんがサイトコピペの影響です…
outで書いた場合の書き方も教授していただけると幸いです


>>ステップ実行してみると、
> メッセージ処理を阻害する可能性があるので、この場合のステップ実行は控えましょう。
>
>
>>if (msg == 0x110) 部分でmsg == 0x110がfalseになるため中の処理に入らず、
> その場合の msg は何でしたか?
>

この部分のメソッドが呼ばれるたびにmsgの値は変わっているので、これと言ってひとつではなかったです。
3桁から4桁の数字が入っていました。

>
>>永遠とループしている状態で
> そもそも HookProc は WM_INIDIALOG 専用というわけではなく、
> いろいろな msg 値が幾度も幾度も飛んでくる仕様です。
>
> コメントにも「// WM_INIDIALOG 以外のメッセージに対しては」と書かれていますよね。

よろしくお願いします。
引用返信 編集キー/
■79917 / inTopicNo.4)  Re[3]: カラーパレット任意の座標に表示する
□投稿者/ 魔界の仮面弁士 (732回)-(2016/05/27(Fri) 20:28:05)
No79910 (kazu さん) に返信
> メソッド内でnewしてない場合はdisposeしない方がいいと言うのをしりませんでした。

メソッド内で new したかどうか、と言う話ではなく、
 「Dispose したオブジェクトは再利用してはいけない」
ということです。破棄したオブジェクトにアクセスした場合、
ObjectDisposedException などの例外になりえます。


ColorDialog は、Dispsose を処理していないクラスであるため、
今回は呼ぼうが呼ぶまいが影響しませんでしたが、もしも相手が
Form だった場合、Dispose 後のアクセスは御法度です。

var fm = new Form2();
fm.ShowDialog();
fm.Dispose();
fm.ShowDialog(); // 例外


>> ref ではなく out 引数の方が良いと思います。間違いではありませんけれどね。
> outで書いた場合の書き方も教授していただけると幸いです
動作に影響する部分ではないので、変えなくても問題は無いですが、変更するなら
  [DllImport("user32.dll", CharSet = CharSet.Auto)]
  private static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
などとします。この場合の RECT は class ではなく struct です。
呼び出し側も、ref → out に変更することになります。


>>> if (msg == 0x110) 部分でmsg == 0x110がfalseになるため中の処理に入らず、
>>その場合の msg は何でしたか?
> この部分のメソッドが呼ばれるたびにmsgの値は変わっているので、これと言ってひとつではなかったです。
> 3桁から4桁の数字が入っていました。

2 桁もありますよね。

HookProc の処理の冒頭に、if (msg == 0x110) を置いていると思いますが、
その if の直前に、下記のようなコードを一時的に加えてみてください。

 var m = Message.Create(hWnd, msg, wparam, lparam);
 System.Diagnostics.Debug.WriteLine(m.ToString());

その上でアプリを起動し、出力ウィンドウを確認してみてください。

出力ウィンドウが見当たらない場合は、メニューの
[デバッグ]-[ウィンドウ]-[出力]で表示できます。


そうすると恐らくは、
 msg=0x30 (WM_SETFONT) hwnd=…
 msg=0x55 (WM_NOTIFYFORMAT) hwnd=…
   :
のような記述が延々と表示されると思いますので、その中に、
msg=0x110 (WM_INITDIALOG) な行があるかどうか探してみてください。
引用返信 編集キー/
■79932 / inTopicNo.5)  Re[4]: カラーパレット任意の座標に表示する
□投稿者/ kazu (4回)-(2016/05/30(Mon) 11:43:44)
No79917 (魔界の仮面弁士 さん) に返信
> ■No79910 (kazu さん) に返信

お返事が遅くなり、申し訳ございません。

>>メソッド内でnewしてない場合はdisposeしない方がいいと言うのをしりませんでした。
>
> メソッド内で new したかどうか、と言う話ではなく、
>  「Dispose したオブジェクトは再利用してはいけない」
> ということです。破棄したオブジェクトにアクセスした場合、
> ObjectDisposedException などの例外になりえます。
>
>
> ColorDialog は、Dispsose を処理していないクラスであるため、
> 今回は呼ぼうが呼ぶまいが影響しませんでしたが、もしも相手が
> Form だった場合、Dispose 後のアクセスは御法度です。
>
> var fm = new Form2();
> fm.ShowDialog();
> fm.Dispose();
> fm.ShowDialog(); // 例外
>
>

Disposeのルールをまだよく理解していなかったです。
ご教授ありがとうございます。今後、注意しながらプログラミングして行きます。

> >> ref ではなく out 引数の方が良いと思います。間違いではありませんけれどね。
>>outで書いた場合の書き方も教授していただけると幸いです
> 動作に影響する部分ではないので、変えなくても問題は無いですが、変更するなら
>   [DllImport("user32.dll", CharSet = CharSet.Auto)]
>   private static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
> などとします。この場合の RECT は class ではなく struct です。
> 呼び出し側も、ref → out に変更することになります。
>

ご教授ありがとうございます。今、手前のプログラミングを変更して確認してみます。

>
> >>> if (msg == 0x110) 部分でmsg == 0x110がfalseになるため中の処理に入らず、
> >>その場合の msg は何でしたか?
>>この部分のメソッドが呼ばれるたびにmsgの値は変わっているので、これと言ってひとつではなかったです。
>>3桁から4桁の数字が入っていました。
>
> 2 桁もありますよね。
>
> HookProc の処理の冒頭に、if (msg == 0x110) を置いていると思いますが、
> その if の直前に、下記のようなコードを一時的に加えてみてください。
>
>  var m = Message.Create(hWnd, msg, wparam, lparam);
>  System.Diagnostics.Debug.WriteLine(m.ToString());
>
> その上でアプリを起動し、出力ウィンドウを確認してみてください。
>
> 出力ウィンドウが見当たらない場合は、メニューの
> [デバッグ]-[ウィンドウ]-[出力]で表示できます。
>
>
> そうすると恐らくは、
>  msg=0x30 (WM_SETFONT) hwnd=…
>  msg=0x55 (WM_NOTIFYFORMAT) hwnd=…
>    :
> のような記述が延々と表示されると思いますので、その中に、
> msg=0x110 (WM_INITDIALOG) な行があるかどうか探してみてください。

出力にmsg=0x110 (WM_INITDIALOG)のメッセージは存在しました。ただし、PictureBoxをクリックしてカラーパレットの標示ボタンを押すと
msg=0x110 (WM_INITDIALOG)は取得されない状況です。
msg=0x110 (WM_INITDIALOG)が取得されるされない条件等はあるのでしょうか?


引用返信 編集キー/
■79933 / inTopicNo.6)  Re[5]: カラーパレット任意の座標に表示する
□投稿者/ 魔界の仮面弁士 (733回)-(2016/05/30(Mon) 12:51:39)
No79932 (kazu さん) に返信
> 出力にmsg=0x110 (WM_INITDIALOG)のメッセージは存在しました。ただし、PictureBoxをクリックしてカラーパレットの標示ボタンを押すと
> msg=0x110 (WM_INITDIALOG)は取得されない状況です。
> msg=0x110 (WM_INITDIALOG)が取得されるされない条件等はあるのでしょうか?


・PictureBox クリック後に StripColorBtn を押すと固まる、という事なのでしょうか?
 それとも、PictureBox のクリック時にもカラーダイアログ表示のためのコードを書いてあるのでしょうか?

・後者だとした場合、「PictureBox をクリックした場合」にどのようなコードを書いていますか?
 また、PictureBox のどのイベントを利用していますか?

・そもそも カラーパレットの ShowDialog を呼び出すところまで到達していますか?
 WM_INITDIALOG 云々は関係なく、そもそもイベントが呼ばれていなかったという可能性はないでしょうか。

・カラーパレットをデザイン時に用意しておくのではなく、
 カラーパレットをイベント処理時に、毎回 new した場合はどうなりますか?

 using(var dlg = new ColorDialogEx())
 {
   // archPaint の左上隅にダイアログボックスの座標を合わせて表示する
   dlg.Position = this.PointToScreen(new Point(archPaint.Left + 20, archPaint.Top + 30));
   dlg.AllowFullOpen = false;
   if (dlg.ShowDialog() == DialogResult.OK)
   {
     this.StripSelectColorBtn.BackColor = dlg.Color;
     archPaint._selectColor = dlg.Color;
   }
 }
引用返信 編集キー/
■79934 / inTopicNo.7)  Re[6]: カラーパレット任意の座標に表示する
□投稿者/ kazu (6回)-(2016/05/30(Mon) 13:29:04)
No79933 (魔界の仮面弁士 さん) に返信
> ■No79932 (kazu さん) に返信
>>出力にmsg=0x110 (WM_INITDIALOG)のメッセージは存在しました。ただし、PictureBoxをクリックしてカラーパレットの標示ボタンを押すと
>>msg=0x110 (WM_INITDIALOG)は取得されない状況です。
>>msg=0x110 (WM_INITDIALOG)が取得されるされない条件等はあるのでしょうか?
>
>
> ・PictureBox クリック後に StripColorBtn を押すと固まる、という事なのでしょうか?
>  それとも、PictureBox のクリック時にもカラーダイアログ表示のためのコードを書いてあるのでしょうか?
>
> ・後者だとした場合、「PictureBox をクリックした場合」にどのようなコードを書いていますか?
>  また、PictureBox のどのイベントを利用していますか?
>

PictureBox クリック後に StripColorBtn を押すと固まります。
PictureBoxのクリックイベントとしてはPicturBoxにcontrolがあるかをforeachで全てのコントロールの背景色を透明にするというものと
stripTextConboボックスのテキストの内容を空白にするという処理は書いてあります。

private void archPaint_Click(object sender, EventArgs e) {
foreach (Control v in archPaint.Controls) {
     v.BackColor = Color.FromArgb(0, 0, 0, 0);
}
this.StripTextCombo.Text = "";
}


> ・そもそも カラーパレットの ShowDialog を呼び出すところまで到達していますか?

PictureBoxをクリックした場合は到達出来ません。
クリックしない場合はColorDialogExでWM_INITDIALOGを取得でき、if文の中に入るので座標が取得でき
StripColorBtn_Clickメソッドのif (dlg.ShowDialog() == DialogResult.OK)に行きカラーパレットが表示されています。



>  WM_INITDIALOG 云々は関係なく、そもそもイベントが呼ばれていなかったという可能性はないでしょうか。
>
> ・カラーパレットをデザイン時に用意しておくのではなく、
>  カラーパレットをイベント処理時に、毎回 new した場合はどうなりますか?
>
>  using(var dlg = new ColorDialogEx())
>  {
>    // archPaint の左上隅にダイアログボックスの座標を合わせて表示する
>    dlg.Position = this.PointToScreen(new Point(archPaint.Left + 20, archPaint.Top + 30));
>    dlg.AllowFullOpen = false;
>    if (dlg.ShowDialog() == DialogResult.OK)
>    {
>      this.StripSelectColorBtn.BackColor = dlg.Color;
>      archPaint._selectColor = dlg.Color;
>    }
>  }

毎回newしてみましたが、同じくpictureBoxをクリックまたは何かしらの動作後にカラーパレットを表示させようとすると固まります。
しかし、出力にはmsg=0x110 (WM_INITDIALOG) hwnd=0x140b52 wparam=0x140c82 lparam=0x109a7018 result=0x0
が表示されていました。
引用返信 編集キー/
■79936 / inTopicNo.8)  Re[7]: カラーパレット任意の座標に表示する
□投稿者/ kazu (7回)-(2016/05/30(Mon) 14:31:00)
No79934 (kazu さん) に返信
> ■No79933 (魔界の仮面弁士 さん) に返信
すみません追記です。

PictureBoxをクリックした場合でも、押さなかった場合でもShowDialogまでは通ってます。
その後でHookProcメソッドに行ってます。
引用返信 編集キー/
■79938 / inTopicNo.9)  Re[8]: カラーパレット任意の座標に表示する
□投稿者/ 魔界の仮面弁士 (734回)-(2016/05/30(Mon) 17:12:12)
No79936 (kazu さん) に返信
> PictureBox クリック後に StripColorBtn を押すと固まります。

提示された情報を元に検証してみましたが、PictureBox を Click しても
 (問題点1) ダイアログが表示されず、固まってしまう
 (問題点2) ShowDialog 後、WM_INITDIALOG が飛んでくる気配が無い
のいずれの現象も再現できていません。


> PictureBoxのクリックイベントとしてはPicturBoxにcontrolがあるかを
> foreachで全てのコントロールの背景色を透明にするというものと
> stripTextConboボックスのテキストの内容を空白にするという処理は書いてあります。

(1) まずは、PictureBox の Click 処理の内容を、すべてコメントアウトしてみてください。

もしもそれで現象が解決するのであれば、この部分に要因があることになります。


(2) 手順 1 で、すべてコメントアウトしても固まってしまう場合は、
今度は HookProc をオーバーライドしないように修正してみてください。

その場合、余計なコードが呼ばれないので、固まる事も無くなる見込みです。

ただし、画面の表示位置はデフォルトの位置のままになるはずです。
(WM_INITDIALOG が渡されてくるかどうかは別として)


(3) 手順 2 でも回避できない場合、プログラムコードと言うよりも、
 環境依存の不具合の可能性も考えられますが、今のところ検討がつきません。
 現象を再現するための検証用アプリケーションを新たに作成し、
 それを OneDrive 等で公開することはできますか?


(4) WM_INITDIALOG 時の戻り値ですが、今回は return (IntPtr)1; を返した方が良いかもしれません。
 WM_INITDIALOG が飛んできていない現状では、あまり意味が無いかも知れませんが。

※ 1 を返却 → 標準のフォーカス制御が実行されます。システム既定のフォーカス制御に任せることを意味します。
   wParam に、最初にフォーカスを受け取るウィンドウのハンドルが入っており、
   ダイアログ表示時には、そのウィンドウがフォーカスを受け取ります。

※ 0 を返却 → 標準のフォーカス制御を抑制し、独自のフォーカス制御を行うこと意味します。
   意図的に SetFocus API (あるいは Focus メソッド)を呼んだり、
   アクティブウィンドウを変更するようなコードを伴う場合に使います。


> カラーパレットボタンを押下した時に画面が固まる現象が起きています。

もしかしたら、本来はウィンドウの手前に表示されるべきダイアログが
ウィンドウの背後にモーダル表示されてしまい、操作不能に陥っているのかも。


> if (dlg.ShowDialog() == DialogResult.OK)

引数に、ダイアログの親ウィンドウを指定してみては如何でしょうか。
具体的には、dlg.ShowDialog() ではなく、
dlg.ShowDialog(this) にしてみるということです。

https://social.msdn.microsoft.com/Forums/ja-JP/1ac1bc49-8b00-45fb-b258-81c87aa9d7b5?forum=csharpgeneralja


以下蛇足:

> private void archPaint_Click(object sender, EventArgs e) {
>  foreach (Control v in archPaint.Controls) {

子コントロールの上に、さらに子コントロールが貼られているような
入れ子構造のケースは考えなくても良いのでしょうか。


>   v.BackColor = Color.FromArgb(0, 0, 0, 0);

コントロールによっては、不透明色しか指定できないものも
ありますので御注意あれ。(たとえば TextBox など)
引用返信 編集キー/
■79939 / inTopicNo.10)  Re[9]: カラーパレット任意の座標に表示する
□投稿者/ Hongliang (432回)-(2016/05/30(Mon) 17:35:26)
ColorDialogExの代わりにColorDialogで動かした場合は正常に動くのかどうか、って切り分けはお済みですか?
引用返信 編集キー/
■79940 / inTopicNo.11)  Re[9]: カラーパレット任意の座標に表示する
□投稿者/ kazu (8回)-(2016/05/30(Mon) 17:39:22)
No79938 (魔界の仮面弁士 さん) に返信
> ■No79936 (kazu さん) に返信
>>PictureBox クリック後に StripColorBtn を押すと固まります。
>
> 提示された情報を元に検証してみましたが、PictureBox を Click しても
>  (問題点1) ダイアログが表示されず、固まってしまう
>  (問題点2) ShowDialog 後、WM_INITDIALOG が飛んでくる気配が無い
> のいずれの現象も再現できていません。
>
再現までして頂いてありがとうございます。

>
>>PictureBoxのクリックイベントとしてはPicturBoxにcontrolがあるかを
>>foreachで全てのコントロールの背景色を透明にするというものと
>>stripTextConboボックスのテキストの内容を空白にするという処理は書いてあります。
>
> (1) まずは、PictureBox の Click 処理の内容を、すべてコメントアウトしてみてください。
>
> もしもそれで現象が解決するのであれば、この部分に要因があることになります。
>
>
コメントアウトしてみましたが、問題は解決できませんでした。

> (2) 手順 1 で、すべてコメントアウトしても固まってしまう場合は、
> 今度は HookProc をオーバーライドしないように修正してみてください。
>
> その場合、余計なコードが呼ばれないので、固まる事も無くなる見込みです。
>
> ただし、画面の表示位置はデフォルトの位置のままになるはずです。
> (WM_INITDIALOG が渡されてくるかどうかは別として)
>
>
デフォルトですと、フォームの真ん中に表示されてしまうため、今回の様な使用を考えています。
できる限り、任意の場所で表示できるようにしたいと考えております。

> (3) 手順 2 でも回避できない場合、プログラムコードと言うよりも、
>  環境依存の不具合の可能性も考えられますが、今のところ検討がつきません。
>  現象を再現するための検証用アプリケーションを新たに作成し、
>  それを OneDrive 等で公開することはできますか?
>
ソースを公開するのは難しいかと思います。



> (4) WM_INITDIALOG 時の戻り値ですが、今回は return (IntPtr)1; を返した方が良いかもしれません。
>  WM_INITDIALOG が飛んできていない現状では、あまり意味が無いかも知れませんが。
>
> ※ 1 を返却 → 標準のフォーカス制御が実行されます。システム既定のフォーカス制御に任せることを意味します。
>    wParam に、最初にフォーカスを受け取るウィンドウのハンドルが入っており、
>    ダイアログ表示時には、そのウィンドウがフォーカスを受け取ります。
>
> ※ 0 を返却 → 標準のフォーカス制御を抑制し、独自のフォーカス制御を行うこと意味します。
>    意図的に SetFocus API (あるいは Focus メソッド)を呼んだり、
>    アクティブウィンドウを変更するようなコードを伴う場合に使います。
>
>
>>カラーパレットボタンを押下した時に画面が固まる現象が起きています。
>
> もしかしたら、本来はウィンドウの手前に表示されるべきダイアログが
> ウィンドウの背後にモーダル表示されてしまい、操作不能に陥っているのかも。
>
>
>>if (dlg.ShowDialog() == DialogResult.OK)
>
> 引数に、ダイアログの親ウィンドウを指定してみては如何でしょうか。
> 具体的には、dlg.ShowDialog() ではなく、
> dlg.ShowDialog(this) にしてみるということです。
>
> https://social.msdn.microsoft.com/Forums/ja-JP/1ac1bc49-8b00-45fb-b258-81c87aa9d7b5?forum=csharpgeneralja
>

裏に隠れてる可能性が一番高いかと思っております。
サンプルでは
http://www.kanazawa-net.ne.jp/~pmansato/net/net_technics.htm
if (dlg.ShowDialog(button1) == DialogResult.OK)
this.BackColor = dlg.Color;
になっていましたが
if (dlg.ShowDialog() == DialogResult.OK) にしていたからです。
ですが、dlg.ShowDialog(this) で試してみたところ表には出てくれませんでした。
this以外に考えられる引数はありますか?


>
> 以下蛇足:
>
>>private void archPaint_Click(object sender, EventArgs e) {
>> foreach (Control v in archPaint.Controls) {
>
> 子コントロールの上に、さらに子コントロールが貼られているような
> 入れ子構造のケースは考えなくても良いのでしょうか。
>
>
>>  v.BackColor = Color.FromArgb(0, 0, 0, 0);
>
> コントロールによっては、不透明色しか指定できないものも
> ありますので御注意あれ。(たとえば TextBox など)

今回の仕様ではラベルのみ作成の為、このような判断で色を変更するようにしました。
できれば他の場所をクリックした時にpictureboxの上にあるコントロール(ラベル)の背景色を透過するという
うまい処理を書けたらいいのですが、何分未熟なので今はこの方法しか思いつきませんでした。
引用返信 編集キー/
■79941 / inTopicNo.12)  Re[10]: カラーパレット任意の座標に表示する
□投稿者/ kazu (9回)-(2016/05/30(Mon) 17:48:27)
No79939 (Hongliang さん) に返信
> ColorDialogExの代わりにColorDialogで動かした場合は正常に動くのかどうか、って切り分けはお済みですか?
はい、その切り分けは終わりました。
引用返信 編集キー/
■79942 / inTopicNo.13)  Re[10]: カラーパレット任意の座標に表示する
□投稿者/ 魔界の仮面弁士 (735回)-(2016/05/30(Mon) 17:51:06)
No79940 (kazu さん) に返信
>> 現象を再現するための検証用アプリケーションを新たに作成し、
>> それを OneDrive 等で公開することはできますか?
>
> ソースを公開するのは難しいかと思います。

検証コードをネットワーク上で公開するのが難しいのであれば、
そのコードを掲示板に貼る事はできますか?


・Visual Studio のバージョンとエディション、使っている .NET Framework のバージョン、
 そして 実行している OS が何かを明確にする。

・どんなコントロールを使っているか分かるよう、
 label1 や pictureBox1 といった名前のままにする。

・余計な処理等は極力加えず、現象を再現可能な最低限のコードのみで構成する。

・デザイン時設定のプロパティ等で特筆すべき点があればコメント等で併記しておく。
 (可能であれば、Load イベントでコントロールを動的配置する)

・コードをアップする時には、掲示板の投稿モードを「図表モード」に変更する。

・掲示板に投稿した内容をそのまま新規プロジェクトに当てはめたときに
 自身の環境で再現することを確認しておく。
引用返信 編集キー/
■79943 / inTopicNo.14)  Re[10]: カラーパレット任意の座標に表示する
□投稿者/ kazu (10回)-(2016/05/30(Mon) 17:52:13)
No79940 (kazu さん) に返信
> ■No79938 (魔界の仮面弁士 さん) に返信
追記です。

if (dlg.ShowDialog() == DialogResult.OK) の箇所を
if (dlg.ShowDialog(this.archPaint) == DialogResult.OK) としたところ
ボタンを押した後は変わりませんが、Alt + Tabで違うアプリケーションへ(他のテキストやエクセル)行き
戻ると表示されています。
なんだかよくわかりませんが、はやり表に出ておらず固まってるように見えているというのが濃厚そうです。
ただ、なぜアプリケーションを変更しないと思うように表に表示されないのかが不明です。

引用返信 編集キー/
■79944 / inTopicNo.15)  Re[11]: カラーパレット任意の座標に表示する
□投稿者/ 魔界の仮面弁士 (736回)-(2016/05/30(Mon) 18:13:46)
No79943 (kazu さん) に返信
> if (dlg.ShowDialog() == DialogResult.OK) の箇所を
> if (dlg.ShowDialog(this.archPaint) == DialogResult.OK) としたところ
> ボタンを押した後は変わりませんが、Alt + Tabで違うアプリケーションへ(他のテキストやエクセル)行き
> 戻ると表示されています。

その場合、WM_INITDIALOG は飛んできていますか?


> ただ、なぜアプリケーションを変更しないと思うように表に表示されないのかが不明です。

IntPtr.Zero を返却しているから…とか? ( No79938 を参照)

引用返信 編集キー/
■79945 / inTopicNo.16)  Re[12]: カラーパレット任意の座標に表示する
□投稿者/ kazu (11回)-(2016/05/30(Mon) 18:20:27)
No79944 (魔界の仮面弁士 さん) に返信
> ■No79943 (kazu さん) に返信
>>if (dlg.ShowDialog() == DialogResult.OK) の箇所を
>>if (dlg.ShowDialog(this.archPaint) == DialogResult.OK) としたところ
>>ボタンを押した後は変わりませんが、Alt + Tabで違うアプリケーションへ(他のテキストやエクセル)行き
>>戻ると表示されています。
>
> その場合、WM_INITDIALOG は飛んできていますか?
>
はい、飛んできています。

>
>>ただ、なぜアプリケーションを変更しないと思うように表に表示されないのかが不明です。
>
> IntPtr.Zero を返却しているから…とか? ( No79938 を参照)
>
IntPtr.Zero をコメントアウトしたところ、表示はされますが真ん中(デフォルト)で表示されてしまいます。

引用返信 編集キー/
■79946 / inTopicNo.17)  Re[13]: カラーパレット任意の座標に表示する
□投稿者/ kazu (12回)-(2016/05/30(Mon) 18:25:34)
No79945 (kazu さん) に返信
> ■No79944 (魔界の仮面弁士 さん) に返信
>>■No79943 (kazu さん) に返信
> >>if (dlg.ShowDialog() == DialogResult.OK) の箇所を
> >>if (dlg.ShowDialog(this.archPaint) == DialogResult.OK) としたところ
> >>ボタンを押した後は変わりませんが、Alt + Tabで違うアプリケーションへ(他のテキストやエクセル)行き
> >>戻ると表示されています。
>>
>>その場合、WM_INITDIALOG は飛んできていますか?
>>
> はい、飛んできています。
>
>>
> >>ただ、なぜアプリケーションを変更しないと思うように表に表示されないのかが不明です。
>>
>>IntPtr.Zero を返却しているから…とか? ( No79938 を参照)
>>
> IntPtr.Zero をコメントアウトしたところ、表示はされますが真ん中(デフォルト)で表示されてしまいます。

追記、
IntPtr.Zeroをreturn (IntPtr)1;に変えてみましたが、変わりませんでした。
>
引用返信 編集キー/
■79947 / inTopicNo.18)  Re[11]: カラーパレット任意の座標に表示する
□投稿者/ とっちゃん (364回)-(2016/05/30(Mon) 18:59:55)
No79943 (kazu さん) に返信
> ■No79940 (kazu さん) に返信
>>■No79938 (魔界の仮面弁士 さん) に返信
> 追記です。
>
> if (dlg.ShowDialog() == DialogResult.OK) の箇所を
> if (dlg.ShowDialog(this.archPaint) == DialogResult.OK) としたところ
> ボタンを押した後は変わりませんが、Alt + Tabで違うアプリケーションへ(他のテキストやエクセル)行き
> 戻ると表示されています。
> なんだかよくわかりませんが、はやり表に出ておらず固まってるように見えているというのが濃厚そうです。
> ただ、なぜアプリケーションを変更しないと思うように表に表示されないのかが不明です。
>
ShowDialog に渡すウィンドウオブジェクトをトップレベルのオブジェクトにしてみてください。
トップレベルとは、子ウィンドウではないフォームのことです。
引用返信 編集キー/
■79949 / inTopicNo.19)  Re[13]: カラーパレット任意の座標に表示する
□投稿者/ 魔界の仮面弁士 (737回)-(2016/05/30(Mon) 19:08:40)
No79943 (kazu さん) に返信
> はやり表に出ておらず固まってるように見えているというのが濃厚そうです。

背後に表示されている可能性を調査するため、
フォームの Opacity プロパティを半分程度にしておいては如何でしょう。



■No79945 (kazu さん) に返信
> IntPtr.Zero をコメントアウトしたところ、表示はされますが真ん中(デフォルト)で表示されてしまいます。

return 値を変更する事で、表示位置が異なると言うことでしょうか。

その現象も、当方では再現しませんでした。
Windows 7x64 Pro + VS2015 Enterprise Update 1 + .NET 4.6.01055 です。


以下に、今回の検証コードを貼っておきます。


using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        private Button button1;
        private TextBox textBox1;

        public Form1()
        {
            // InitializeComponent();

            Controls.Add(button1 = new Button());
            Controls.Add(textBox1 = new TextBox());
            button1.Location = new Point(16, 16);
            button1.Width = 200;
            textBox1.Location = new Point(16, button1.Bottom + 16);
            textBox1.Anchor = AnchorStyles.Left | AnchorStyles.Right;
            button1.Click += delegate
            {
                using (var dlg = new ColorDialogEx())
                {
                    dlg.AllowFullOpen = true;

                    Point p = PointToScreen(new Point(textBox1.Left + 20, textBox1.Top + 8));
                    textBox1.Text = p.ToString();

                    dlg.Location = p;
                    if (dlg.ShowDialog(this) == DialogResult.OK)
                    {
                        textBox1.BackColor = dlg.Color;

                        button1.Text = new ColorConverter().ConvertToString(dlg.Color);
                    }
                }
            };
        }

        internal class ColorDialogEx : ColorDialog
        {
            public Point? Location = null;

            public ColorDialogEx() { }

            protected override IntPtr HookProc(IntPtr hWnd, int msg, IntPtr wparam, IntPtr lparam)
            {
                const int WM_INITDIALOG = 0x110;
                if (msg == WM_INITDIALOG && Location != null)
                {
                    base.HookProc(hWnd, msg, wparam, lparam);

                    RECT r;
                    GetWindowRect(hWnd, out r);
                    Point xy = Location.Value;
                    MoveWindow(hWnd, xy.X, xy.Y, r.right - r.left, r.bottom - r.top, true);

                    return (IntPtr)1;
                }
                else
                {
                    return base.HookProc(hWnd, msg, wparam, lparam);
                }
            }

            [DllImport("user32.dll")]
            private static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);

            [DllImport("user32.dll")]
            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;
            }
        }
    }
}


以下、ColorDialogEx の動作について:


・Location プロパティを null のままにした場合
→ 既定の動作(中央表示)

・Location プロパティをセットした場合
→ 指定した座標に表示(特に固まる様子は無い)
  ※ただし、MoveWindow を呼んだ後で base.HookProc を呼びだすようにすると中央表示になる。

・base.HookProc を呼ばず、0 を return した場合
→ カラーダイアログのキーボード操作ができない。
  ※ダイアログをクリックすると、キーボード操作できるようになる。

・1 を return した場合
→ カラーダイアログのキーボード操作ができる。
  ※base.HookProc を呼び出したかどうかとは無関係。

引用返信 編集キー/
■79951 / inTopicNo.20)  Re[12]: カラーパレット任意の座標に表示する
 
□投稿者/ 魔界の仮面弁士 (738回)-(2016/05/30(Mon) 19:22:14)
No79947 (とっちゃん さん) に返信
>>if (dlg.ShowDialog(this.archPaint) == DialogResult.OK) としたところ
> ShowDialog に渡すウィンドウオブジェクトをトップレベルのオブジェクトにしてみてください。

# そういえば、普段は Form を指定するばかりで、
# 子ウィンドウを指定した事は無かったです。>自分


> トップレベルとは、子ウィンドウではないフォームのことです。

実験のため、あえて他プロセスのウィンドウを指定してみました。
さらに、自フォームは TopMost = true を設定しています。

NativeWindow n = new NativeWindow();
n.AssignHandle( メモ帳のウィンドウハンドル );
if (dlg.ShowDialog(n) == DialogResult.OK)


この場合、呼び出し元フォームが操作不能な状態に陥りました。

メモ帳をクリックすると、カラーダイアログが操作可能になりますが、
自フォームが TopMost のため、それより手前には出てこられません。
(カラーダイアログが閉じられれば、操作可能な状態に戻ります)


操作できないという点だけ見れば、kazu さんのいう「固まった」状態に近い気がしますので、
やはり、ShowDialog の引数で、呼び出し元フォームを指定しておいた方が良いと思います。
引用返信 編集キー/

次の20件>
トピック内ページ移動 / << 0 | 1 >>

管理者用

- Child Tree -