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

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

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

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

1回答

2674閲覧

コントロール操作 ( For Border, Effect )

BeatStar

総合スコア4958

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2017/05/20 03:54

編集2017/05/27 06:00

C/C++ ( Windows API 実装 ) でやっています。

Excel VBA もいじったりしているのですが、

Excel VBA で フォームモジュールでUserForm ( 以下 UF ) 内の コントロール をモジュール内から操作することできますよね。

VBA

1' ボタン ( Button1 ) が押されたときの挙動 2TextBox1.Height = 300 ' テキストボックスの高さを 300 にする

みたいに。

VBAでできる

■ BorderColor : 枠の色の変更及び取得 ■ BorderStyle : 枠の有無? ■ SpecialEffect: フラットにするとか

がC/C++のGUIでもできたらいいのですが...

私はコントロールをクラス化しています。

[定義] + : public member(s) # : protected member(s) - : private member(s) // ~ : explanation

たとえば EDITコントロール 用クラスを WEdit クラスとすると

[WEdit] + WEdit(HWND,int) // コンストラクタ + ~WEdit() // デストラクタ + Create(x,y,w,h,caption) : HWND + SetText(const std::string) : bool + GetText(void) : std::string + Visible(bool) ... // その他のメンバ関数 - hWnd : HWND // 親ウィンドウハンドル - ControlID : int // コントロールID

みたいにしています。

コンストラクタで 親ウィンドウハンドルとコントロールIDを引き受けて メンバ変数にセット。
それ以降は メンバ変数にアクセス...

という感じで。

また、コントロール独特のもの ( EDIT なら マルチラインなのか そうじゃないのか等 ) もありますから、

それは 今のところコンストラクタに渡しています。

このクラス( 複数 ) に 「枠の取り消し・出現」と 「フラットにする・しない」のメンバ関数を追加したいのです。

できたら枠の色も変更できたらいいですが、コントロールの色づけが WM_CTLCOLOREDITメッセージのところだったりと限定的なのでちょっと面倒。

そこから考えて、枠の色ももしかすると大体そんな感じだろうと推測しますから 無くてもいいです。

ですが、 「枠の取り消し・出現」と 「フラットにする・しない」 は 必ず入れたいのです。

枠のやつは Border ですから ウィンドウスタイルとして

WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT

渡していますから これ( WS_BORDER ) を外せばいいとわかります。

ウィンドウスタイルはGetWindowLong関数で取得できたはず ( 入門系のサイトには書かれている場合が多い? ) ので

実際に試してみました。

WEditクラスから オブジェクト Edit1 を生成して, Createメンバ関数で生成, その後 クラス外 ( 呼び出し側 ) で GetWindowLongを使って「WS_BORDER」があるかどうか

をチェックしてみました。

ウィンドウスタイルは ビット演算らしいので &演算子 ? で抽出してみました。

( Createメンバ関数 内で スタイルの設定は WS_BORDER が入っているとします。 )

C++

1// WM_CREATEメッセージ内: 2 3WEdit* Edit1 = new WEdit( hWnd, 102 ); 4 5HWND hEdit = Edit1->Create( 0, 0, 100, 20, "" ); 6 7DWORD dwStyle; // スタイルは DWORDだったはずなので。 8 9dwStyle = (DWORD)GetWindowLong( hEdit, GWL_STYLE ); 10 11if( dwStyle & WS_BORDER ){ 12 MessageBox( hWnd, "Found", "Result", MB_OK ); 13}else{ 14 MessageBox( hWnd, "Not Found", "Result", MB_OK ); 15} 16 17// ※ オブジェクトの破棄は デストラクタ内で。

のようにしてみました。

( 実際には MessageBox等もクラス化していたりしていますが、説明のため。 )

それでCompile and Run したところ、

"Not Found" というメッセージボックスが表示されました。

Createメンバ関数での スタイル の部分ではちゃんと WS_BORDERがセットされているのに...

別の コントロール独自のスタイル ( ES_MULTILINE 等? ただし、設定されているやつ。 ) をチェックしてみたところ、

"Found" でした。

ヘルプファイルで"GetWindowLong" を検索すると関連ページとして "GetWindowLongPtr" がありました。

そのページを見ると「この関数は、GetWindowLong 関数の改訂版です」とあるので、

関数を GetWindowLong から GetWindowLongPtr に切り替えてみましたが結果は同じでした。

WS_*** のやつは 無理なのでしょうか?

それともやり方が別にあるのでしょうか?

ソースコードを(私が)提示するのは構いませんが、

私用のライブラリとして固めていて、ごちゃごちゃしているので...

[情報]
言語 : C/C++
WindowsAPI : あり
環境 : MinGW ( g++ )
聞きたいこと: コントロールの操作関連 ( 特に Border系と フラットにすること )

宜しくお願い致します。


Chironianさん ご回答ありがとうございます。

ご回答ありがとうございます。

外出先で質問&アンサーしているので、

帰宅後に試してみました。

まず "3. WM_BORDERが設定されていても..." の方が怪しいと仰ったので、

先に試してみました。

ShowWindow( hEdit, SW_SHOW ); // Edit1 を Show!

を置いて やっても同じでした。

次に "1. そもそもウィンドウハンドルではない" をチェックしてみました。

C++

1LRESULT CALLBACK EditProc( HWND hWnd, UINT msg, WPARAM wp, LPARAM lp ){ 2 // 省略。 EDITのサブクラスってとこ。 3} 4 5 6 7LRESULT CALLBACK WindProc( HWND hWnd, UINT msg, WPARAM wp, LPARAM lp ){ 8 static CMsgBox MsgBox(hWnd); // MessageBoxをクラス化したもの。 9 static WEdit* Edit1; // 質問にあるWEditクラスのオブジェクト 10 static HWND hEdit; // Edit1 のウィンドウハンドル 11 CWindowInfo* Info; // ウィンドウの情報を取得する自作クラス 12 DWORD dwStyle; 13 14 switch( msg ){ 15 case WM_CREATE: 16 Edit1 = new WEdit( hWnd, 102, EditProc ); // 引数そのものは正しいとする。定義を書くのが面倒なので。 17 hEdit = Edit1->Create( 0, 0, 20, 100 ); // これも正しいとする。 18 ShowWindow( hEdit, SW_SHOW ); 19 break; 20 case WM_RBUTTONDOWN: 21 // 右クリックされたら Edit1 の情報 ( 特に ウィンドウスタイル ) を取得する 22 Info = new CWindowInfo( hWnd, 102 ); 23 24 dwStyle = Info->GetStyle(); 25 26 if( dwStyle & WS_BORDER ){ 27 MsgBox.Show( "Found" ); // WS_BORDER があれば "Found" というメッセージボックスを表示 28 }else{ 29 MsgBox.Show( "Not Found" ); 30 } 31 32 // 試しに Edit1 を非表示にしてみる。 33 ShowWindow( hEdit, SW_HIDE ); 34 delete Info; 35 break; 36 case WM_DESTROY: 37 delete Edit1; 38 PostQuitMessage( 0 ); 39 break; 40 } 41return DefWindowProc( hWnd, msg, wp, lp ); 42}

みたいにしました。

すると、

"Not Found" というMessageBox表示後、 Edit1 に相当する部分が非表示になりました。

非表示になるということは、hEdit は ウィンドウハンドルで、ちゃんと格納されているってことですよね。

なので

1 & 3 は違うと思います。

"2. そもそも WS_BORDERが設定されていない" ... (パターンからすると)ありえそうですが、

コードを見ると設定されていると思います。

( 実際、実行時も 黒のボーダーが Edit1 に相当する部分に出ていますから。 )

よって、2もあり得ないと思います。


Chironianさん。

どうしてもパターンが思いつかない
( 一応、思いついたものはすべてやりました。 )
のでネットで検索したところ、
エディットコントロール [VC++の使い方] - トップ [nitoyon . com]

がヒットしました。

これによると

リソースエディタで作成するような枠をつけたい場合は、 WS_EX_CLIENTEDGE スタイルを有効にするのがよいでしょう。 CreateWindowEx(WS_EX_CLIENTEDGE, ...); とします。 (省略した残りの引数は、CreateWindow 関数と同じものを書く。 ただし、WS_BORDER ははずしておいたほうがよいでしょう)

とありました。

なので

1. ( Createメンバ関数内 ) CreateWindowEx の第一引数としてWS_EX_CLIENTEDGE を渡し、 通常のウィンドウスタイルから WS_BORDER をはずしておく 2. ( SetBorderメンバ関数が呼ばれたら ) WS_EX_CLIENTEDGE を外す

みたいにしようかと思っています。

ありがとうございます!!

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

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

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

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

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

guest

回答1

0

ベストアンサー

こんにちは。

単にWindows APIの使い方の問題ではないかと思います。
VBなども、結局Windows APIを使って実装していますから。

現象から、少なくともWM_BORDERがhEditが示すウィンドウに設定されていないのは間違いないように思います。(何か見落としがあったらごめんなさい。)

hEditにWM_BORDERが設定されていない原因として考えられることは多数あります。

  1. そもそもウィンドウ・ハンドルではない
  2. そもそもWM_BORDERが設定されていない
  3. WM_BORDERが設定されていてもまだ反映されていない

一番疑わしいのは3.ですね。例えばShowWindowしないと反映されないとかあるかも知れません。(これは単なる思いつきです。昔、この辺の振る舞いが読めなくて苦労した記憶があるので、意外な振る舞いを想定してみただけです。)

Windows APIの振る舞いを確認することは結構重要です。意外な振る舞い(というか振る舞いを理解しそこなうこと)は多いですから。
FindWindowして得たhWndに対して同様なことをやってみるとか、Spy++を使ってウィンド・スタイルを見てるとのは有用と思います。(昔のSpyは確か見れたと思います。今のSpy++が見れるかどうかは把握していません。見れなかったらすいません。)

投稿2017/05/20 05:23

Chironian

総合スコア23272

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

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

BeatStar

2017/05/22 04:26

Chironianさん。 質問の方に文章を追加しました。 ご面倒をかけますが、宜しくお願い致します。
Chironian

2017/05/22 04:48 編集

> コードを見ると設定されていると思います。 コードを見てそれがバグっていないと断定するのはプログラマとして如何なものかと感じます。 よくよくみてもなかなか解らないようなバグってたいへん良くあります。 > ( 実際、実行時も 黒のボーダーが Edit1 に相当する部分に出ていますから。 ) それが本当にWM_BORDERによるものであることは検証できていますでしょうか? 例えば、WM_BORDERを与えるのをやめたら、表示されなくなるなどなど。 *** コードを見る限り動作する筈のプログラムが設計通りに動作しない時は、「全て」を疑うしかありません。 なので、1つ1つ検証することになります。 まずは、基本に立ち返って単純なコードでWM_BORDERをセット/リセットして、表示とGetWindowLongの結果が想定通りかを検証しては如何でしょうか? そして、その振る舞いが、もしもBeatStarさんの想定と同じであればBeatStarさんのプログラムがバグっています。その場合は、そのバグを見つけるしか無いでしょう。
BeatStar

2017/05/27 05:57

返信ありがとうございます。 >> コードを見てそれがバグっていないと断定するのはプログラマとして如何なも... 確かにそうですよね。 ですが、一応私なりに思いついた手はすべてチェックしてみました。 ですが、しっくり来ませんでした。
BeatStar

2017/05/27 06:01

質問の文章に 解決方法 ( まだ試していないので 可能性ですが。 ) を追加記述しました。 ご協力有難うございました!!
Chironian

2017/05/27 07:13

ということは、 > まずは、基本に立ち返って単純なコードでWM_BORDERをセット/リセットして、表示とGetWindowLongの結果が想定通りかを検証しては如何でしょうか? をトライして、WS_BORDERの有無で表示が変わらない、もしくは、予想外のふるまいだったということですね。 WS_BORDERの仕様が思っていたのと違っていた場合、他の手段を探すしか無いので、再度リサーチした結果、WS_EX_CLIENTEDGEを見つけたのは良かったですね。 Windows APIとの戦いはその連続です。 お疲れ様です。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問