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

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

ただいまの
回答率

88.77%

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

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,352

BeatStar

score 1802

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

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

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

' ボタン ( Button1 ) が押されたときの挙動
TextBox1.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 が入っているとします。 )

// WM_CREATEメッセージ内:

WEdit* Edit1 = new WEdit( hWnd, 102 );

HWND hEdit = Edit1->Create( 0, 0, 100, 20, "" );

DWORD dwStyle; // スタイルは DWORDだったはずなので。

dwStyle = (DWORD)GetWindowLong( hEdit, GWL_STYLE );

if( dwStyle & WS_BORDER ){
       MessageBox( hWnd, "Found", "Result", MB_OK );
}else{
       MessageBox( hWnd, "Not Found", "Result", MB_OK );
}

// ※ オブジェクトの破棄は デストラクタ内で。

のようにしてみました。

( 実際には 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. そもそもウィンドウハンドルではない" をチェックしてみました。

LRESULT CALLBACK EditProc( HWND hWnd, UINT msg, WPARAM wp, LPARAM lp ){
        // 省略。 EDITのサブクラスってとこ。
}



LRESULT CALLBACK WindProc( HWND hWnd, UINT msg, WPARAM wp, LPARAM lp ){
        static CMsgBox MsgBox(hWnd); // MessageBoxをクラス化したもの。
        static WEdit*       Edit1; // 質問にあるWEditクラスのオブジェクト
        static HWND         hEdit; // Edit1 のウィンドウハンドル
               CWindowInfo* Info; // ウィンドウの情報を取得する自作クラス
               DWORD        dwStyle;

        switch( msg ){
                 case WM_CREATE:
                                  Edit1 = new WEdit( hWnd, 102, EditProc ); // 引数そのものは正しいとする。定義を書くのが面倒なので。
                                  hEdit = Edit1->Create( 0, 0, 20, 100 ); // これも正しいとする。
                                  ShowWindow( hEdit, SW_SHOW );
                                  break;
                 case WM_RBUTTONDOWN:
                                  // 右クリックされたら Edit1 の情報 ( 特に ウィンドウスタイル ) を取得する 
                                  Info = new CWindowInfo( hWnd, 102 );

                                  dwStyle = Info->GetStyle();

                                  if( dwStyle & WS_BORDER ){
                                         MsgBox.Show( "Found" ); // WS_BORDER があれば "Found" というメッセージボックスを表示
                                  }else{
                                         MsgBox.Show( "Not Found" );
                                  }

                                  // 試しに Edit1 を非表示にしてみる。
                                  ShowWindow( hEdit, SW_HIDE );
                                  delete Info;
                                  break;
                 case WM_DESTROY:
                                  delete Edit1;
                                  PostQuitMessage( 0 );
                                  break;
        }
return DefWindowProc( hWnd, msg, wp, lp );
}

みたいにしました。

すると、

"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 を外す


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

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

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

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/27 14:57

    返信ありがとうございます。

    >> コードを見てそれがバグっていないと断定するのはプログラマとして如何なも...

    確かにそうですよね。

    ですが、一応私なりに思いついた手はすべてチェックしてみました。
    ですが、しっくり来ませんでした。

    キャンセル

  • 2017/05/27 15:01

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

    キャンセル

  • 2017/05/27 16:13

    ということは、

    > まずは、基本に立ち返って単純なコードでWM_BORDERをセット/リセットして、表示とGetWindowLongの結果が想定通りかを検証しては如何でしょうか?

    をトライして、WS_BORDERの有無で表示が変わらない、もしくは、予想外のふるまいだったということですね。
    WS_BORDERの仕様が思っていたのと違っていた場合、他の手段を探すしか無いので、再度リサーチした結果、WS_EX_CLIENTEDGEを見つけたのは良かったですね。
    Windows APIとの戦いはその連続です。

    お疲れ様です。

    キャンセル

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

  • ただいまの回答率 88.77%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る