• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:Win32APIで作るコンボボックスの高さの調整)

Win32APIで作るコンボボックスの高さの調整

このQ&Aのポイント
  • CreateWindowExとかリソースとかで指定する高さがコンボボックスでCBS_DROPDOWNLISTスタイル込みの場合、ドロップダウンを表示させたときのドロップダウンリストの高さを含むように予約領域先に作っておかなければいけないとのこと。
  • クリックすると表示になる割に「内部的に別々で自動的に高さ計算」とかになっている。
  • Setup関数の中でコンボボックスの高さを調整している。XP以降のWindowsは問題ないが、その他の突っ込みどころがあるかどうかも知りたい。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.4

> LOGFONTのlfHeightが「XP以降のどれについても」そのまんまコンボボックスの高さとして使えるかどうか > っていうのは、MSDN確実な問題って言う表記はありましたでしょうか? ないでしょう。 画面の解像度(ディスプレイの画素数だけでなく、DPI値を含む)にも影響されるでしょうし。 リソースエディタを使う場合も含めて、最初に(見た目など適当な数値で)高さを決めておけば、行が中途半端に表示されるとか空白の行がいくつも表示されるようなことはないようにWindowsが調整してくれるので、環境によって表示される行数が多少違っても問題ないのであれば、任せちゃったほうが楽だというだけです。 厳密にどの環境でも同じ行数を表示したいということなら、提示されたコードでいいんじゃないでしょうか。

LongSecret
質問者

お礼

いや~ 細かく何度もありがとうございます♪ 全く同じ見解のようで、安心しました。 ちょっと貸してもらって、試すことが出来ましたよ 結果、やった範囲の全てのテーマ(デザイン)などで、XPでもVistaでも7でも 下のコードで全部思い通りの行数表示になることが分かりました。 もちろん もし仮にずれる環境があったとしてもWS_VSCROLLを指定しておけば 計算した高さ > 指定されるべきぴったりの高さ であれば、表示数が多くなるだけか 限界まで表示されてれば 自動的に縮小されて表示される仕様により、問題なし。 逆に 計算した高さ < 指定されるべき高さ であれば、意図してないとこでスクロールバーが表示されるか 表示される数が少なくなるけども スクロールはできるのでドロップダウンリスト上での選択の可否ということであれば 問題なし。 (WS_VSCROLL指定しとくと最小以下でも1個は表示されるっぽい(?)) ということで また CB_GETITEMHEIGHT は、やはりいかにも専用のメッセージっぽく思うので このコードで行こうと思います。 (少しだけ変えたので、現時点での、調整後の最終コードを載せておきます) ////////myComboBox.h//////// #pragma once class myComboBox { HWND wnd; szt num; public: myComboBox( HWND hw, int x, int y, int cx, DWORD style_ = WS_CHILD|WS_VSCROLL|CBS_DROPDOWNLIST ); ~myComboBox(); BOOL Enable( BOOL b ) const { return EnableWindow( wnd, b ); } Void Select( Dword i ) const { SendMessage( wnd, CB_SETCURSEL, (WPARAM)i, 0 ); } Int GetIndex() const { return (Int)SendMessage( wnd, CB_GETCURSEL, 0, 0 ); } Void Setup( Dword index_to_select = 0, szt max_num_to_show = 0 ) const; Void AddString( TcsLiteral s ){ SendMessage( wnd, CB_ADDSTRING , 0 , (LPARAM)s ); ++num; } Void AddStrings( TcsLiteral* const s, const szt num_ ){ for ( szt i = 0; i < num_; ++i ) SendMessage( wnd, CB_ADDSTRING , 0 , (LPARAM)s[i] ); num += num_; } }; ////////myComboBox.cpp//////// #include "StdAfx.h" #include "myComboBox.h" #include "FontLibrary.h" myComboBox::myComboBox( HWND hw, int x, int y, int cx, DWORD style ) : num(0) { wnd = CreateWindowEx( 0, _T("COMBOBOX"), null, style, x, y , cx, 0, hw, null, HINST::me, null); } myComboBox::~myComboBox(){ DestroyWindow( wnd ); } Void myComboBox::Setup( Dword i, const szt maxnum_ ) const { SendMessage( wnd, WM_SETFONT, (WPARAM)FontLibrary::Default, False ); RECT rc; GetWindowRect( wnd, &rc ); const szt n_ = ( maxnum_ && maxnum_ < num ) ? maxnum_: num; int cy = (int)SendMessage( wnd, CB_GETITEMHEIGHT, -1, 0 ); cy += (int)SendMessage( wnd, CB_GETITEMHEIGHT, 0, 0 ) * n_; cy += GetSystemMetrics(SM_CYEDGE) * 4; SetWindowPos( wnd, null, 0, 0, rc.right-rc.left, cy, SWP_NOMOVE|SWP_NOZORDER|SWP_SHOWWINDOW ); Select( i ); } (もしまたなんか変な個所が見つかったら直すと思いますが) どうもありがとうございました♪

その他の回答 (3)

回答No.3

調整される方向は、縮小だけです。勝手にサイズを大きくしたりはしません。 10.5行分の高さを指定して作成すると、10行分の大きさで表示される。選択肢が5つしかなければ、5行分に縮小されるということです。 フォントの高さは、LOGFONT情報を取得すればわかります。 HFONT hFont = FontLibrary::Default; LOGFONT lf; ZeroMemory(&lf, sizeof(lf)); GetObject(hFont, sizeof(lf), &lf); とすると、lf.lfHeightにフォントの高さが取得できます。

LongSecret
質問者

お礼

どうもどうも いずれも書いた後で文章見直してみて 同様のことを思いました。 >調整される方向は、縮小だけです。勝手にサイズを大きくしたりはしません。 10.5行分の高さを指定して作成すると、10行分の大きさで表示される。選択肢が5つしかなければ、5行分に縮小されるということです。 はい、なので限界まで表示する分には質問文の方法で問題なかった→限界まで表示する分には余分に確保しておけばいいとなるはず ただし、スクロールバーを表示させたいとなると話は変わってくる、というわけです。 >フォントの高さは、LOGFONT情報を取得すればわかります。 はい、そうなんですよね。 実際アプリケーションのユーザー設定をファイルに保存したり、取り出したりといったこともやってるので、その時LOGFONTの情報も取り扱っているので 使い方はOKですが そのことと LOGFONTのlfHeightが「XP以降のどれについても」そのまんまコンボボックスの高さとして使えるかどうか っていうのは、MSDN確実な問題って言う表記はありましたでしょうか? もし一つでも確かめてみないと分かんない環境があれば不確実ってことになりますし もしコンボボックスの内容を後で変更したい場合って言うのが生じれば 結局Setup関数が必要になるのには変わりないってのがあるんですよね。

回答No.2

なんか、そもそも論になっちゃいそうですが、コンボボックスの高さは、スタイルにCBS_NOINTEGRALHEIGHTを付けなければ、 ・選択肢が中途半端に表示されないように行の境界に調整される ・項目数が少ない場合は、すべての項目が表示可能な最小の高さに調整される となってませんでしたか? なので、例えば選択肢が10を超えたらスクロールするようにしたければ、最初からドロップダウン部分が10行+αになるようにコントロールを作成すればよかったと思いますけど。+αも適当に0.5行分とかで問題ないと。

LongSecret
質問者

お礼

>CBS_NOINTEGRALHEIGHT はい、そうですね。つけてませんw 付けて試してみましたが >・選択肢が中途半端に表示されないように行の境界に調整される こっちに関しては変わったようだけども >・項目数が少ない場合は、すべての項目が表示可能な最小の高さに調整される これは、私の環境では少なくとも変わった感じはありません。 SendMessageでWM_SETFONTやるかどうかとも関係ないっぽいです。 やはり 少ない高さに設定して「なんにも手を加えてなかったら」「線しか表示されてなかった」ので質問文のとおりの状況、って事です。 環境で違うんでしょうかね? まあ、下のコードで万事OKということなら何ら問題はないのですが。

LongSecret
質問者

補足

>最初からドロップダウン部分が10行+αになるようにコントロールを作成すればよかったと その場合、リソースでなく、CreateWindowExでやるとしたら 最初から高さを計算して、ってことでしょうか? そうなるとちょーっとムズイんですよね FontLibrary::Defaultの内容は GetStockObject(DEFAULT_GUI_FONT); なんですが SendMessage( wnd, WM_SETFONT, (WPARAM)FontLibrary::Default, False ); こいつがあると下の「直したバージョン」のコードの計算手順じゃないと単純化出来ないという問題があったんです。 (質問文の段階の時はたまたま 変更前>変更後だったためOKだったてことかな) そこさえなんとかできれば簡易化できるかもしれませんが そうなると余計「環境依存の恐れ」が増えてしまうと思ってしまいます。

回答No.1

コンポボックスのドロップダウン部分の高さは、ダイアログの配置なんかと一緒でデザインの一部だと思いますよ。 元のダイアログの大きさを超えてドロップダウンするとみっとない時もあるから、全項目が一度に表示できなくてもスクロールバー表示で対応したいときもあるし。項目数が固定の時は、全項目が一目でわかるように、多少はみ出してもOKの時もあるし。そもそも、全項目が画面に入りきらない場合もあるし。 あと、コンボボックスの横幅って、ウィンドウ領域とクライアント領域で同じでした? 個人的には、同じだったとしてもGetWindowRectを使うな。

LongSecret
質問者

お礼

ご回答ありがとうございます♪ >コンポボックスのドロップダウン部分の高さは、ダイアログの配置なんかと一緒でデザインの一部だと思いますよ。 なるほど。 Expressだとリソースエディタが使えないので.rcファイルに数値を打ち込むか 最終的にはほとんどはAPI呼び出しに書き変えるという手順で作っていたので そういう意識がありませんでしたが そっちからいってれば迷いがなかったかもしれませんね。 >元のダイアログの大きさを超えてドロップダウンするとみっとない時もあるから、全項目が一度に表示できなくてもスクロールバー表示で対応したいときもあるし。項目数が固定の時は、全項目が一目でわかるように、多少はみ出してもOKの時もあるし。そもそも、全項目が画面に入りきらない場合もあるし。 なるほど! 「え?コンボボックスでのドロップダウンリストでの縦のスクロールバーってどうやって表示できるんだろう」と思って色々いじってたら ウインドウスタイルに WS_VSCROLL を加えつつ myComboBox::myComboBox( HWND hw, int x, int y, int cx ) : num(0) { wnd = CreateWindowEx(0, _T("COMBOBOX"), null , WS_CHILD | WS_VSCROLL | WS_VISIBLE | CBS_DROPDOWNLIST , x, y , cx, 0, hw, null, HINST::me, null); } 高さを「全部は収まらない」ようにする と出来るって事ですね?(一応確認) ※あるいはCBS_DISABLENOSCROLLが追加してあれば全部収まる高さがあっても無効状態で表示になりますが 一昨日までの段階ではWS_VSCROLLを付けてない状態でしかも高さが1つ分も表示出来ない指定だったので「線」しか出てなかったので「なんじゃこりゃ」な状態でしたが >あと、コンボボックスの横幅って、ウィンドウ領域とクライアント領域で同じでした? >個人的には、同じだったとしてもGetWindowRectを使うな。 それ私も最初思ったのですが どこだったかな…この部分は、英語のページで書いてあったのをWindowsAPI用にそのまんまなおしたって言う感じでした。 で、私の環境では少なくともYESですね。 ただ、↓こうやっても同じになりますし、感覚的にはやっぱGetWindowRectの方が良いと思いますので 現時点ではこう直しておくことにします。 宣言は Void Setup( Dword index_to_select = 0, szt max_num_to_show = 0 ) const; 定義は Void myComboBox::Setup( Dword i, const szt maxnum_ ) const { SendMessage( wnd, WM_SETFONT, (WPARAM)FontLibrary::Default, False ); RECT rc; GetWindowRect( wnd, &rc ); const szt n_ = ( maxnum_ ) ? maxnum_: num; int cy = (int)SendMessage( wnd, CB_GETITEMHEIGHT, -1, 0 ); cy += (int)SendMessage( wnd, CB_GETITEMHEIGHT, 0, 0 ) * n_; cy += GetSystemMetrics(SM_CYEDGE) * 4; SetWindowPos( wnd, null, 0, 0, rc.right-rc.left, cy, SWP_NOMOVE|SWP_NOZORDER ); Select( i ); } combo_measden->Setup(2,4); //選択インデックスと最大表示数を指定できる。 こいでどうでしょう?

関連するQ&A