Win32APIで作るコンボボックスの高さの調整
作成中のアプリもだいぶ必要機能を網羅出来て来て
よーし、もうちょっとだ!ってとこに来て
コンボボックスのドロップダウンが「ほとんど表示されてない」事に気付きました。
なんでやのんということで調べてみると
どうやらCreateWindowExとかリソースとかで指定する「高さ」が
コンボボックスでCBS_DROPDOWNLISTスタイル込みの場合
ドロップダウンを表示させたときのドロップダウンリストの高さを含むように
予約領域先に作っておかなければいけない、とのこと
えー、クリックすると表示になる割に 「内部的に別々で自動的に高さ計算」 とかになってるんじゃないのー?
ということで
またしてもMicrosoftちゃんにしてやられたって気分ですが
しょうがないのでちゃっちゃとクラス化してみました。
(ていうか、なんで他のコントロールはほとんど独自クラスにしてあるのに、コンボボックスはクラス化してなかったんだろうと、小一時間(ry))
なお、現状ではMFCは使えません(w | orz)
あ、たぶん
TcsLiteral → const TCHAR* const
szt → size_t
以外のtypedefやdefineは見れば元が何なのか分かる(か、分かんなくても問題ないはず)
と思うので省略しまふ(お)
ヘッダ
#pragma once
class myComboBox {
HWND wnd;
szt num;
public:
myComboBox( HWND hw, int x, int y, int cx );
~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() 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_;
}
};
ソース
#include "StdAfx.h"
#include "myComboBox.h"
#include "FontLibrary.h"
myComboBox::myComboBox( HWND hw, int x, int y, int cx ) : num(0) {
wnd = CreateWindowEx(0, _T("COMBOBOX"), null ,
WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST ,
x, y , cx, 0, hw, null, HINST::me, null);
}
myComboBox::~myComboBox(){
DestroyWindow( wnd );
}
Void myComboBox::Setup() const {
RECT rc;
GetClientRect( wnd, &rc );
int cy = (int)SendMessage( wnd, CB_GETITEMHEIGHT, -1, 0 );
cy += (int)SendMessage( wnd, CB_GETITEMHEIGHT, 0, 0 ) * num;
cy += GetSystemMetrics(SM_CYEDGE) * 2;
cy += GetSystemMetrics(SM_CYEDGE) * 2;
SetWindowPos( wnd, null, 0, 0, rc.right, cy, SWP_NOMOVE|SWP_NOZORDER );
SendMessage( wnd, CB_SETCURSEL, 0 , 0 );
SendMessage( wnd, WM_SETFONT, (WPARAM)FontLibrary::Default, True );
}
使い方の例はこんな感じです。
wnd = CreateWindowEx( ~
・
・
・
combo_measden = new myComboBox( wnd, 50, 200, 60 );
TcsLiteral c[] = { _T("1"), _T("2"), _T("4"), _T("8"), _T("16"), _T("32") };
combo_measden->AddStrings( c, sizeof c / sizeof(c[0]) );
combo_measden->Setup();
解放時
/* Windows的には「HWNDの、子ウインドウ」のみについて言えば親ウインドウのDestroyのときに同時に自動解放してくれるようですが、どっちみちcombo_measdenポインタはdeleteかけないといけないので */
delete combo_measden;
DestryWindow( wnd );
で、今回何が知りたいのかというと
このSetup関数の中の
int cy = (int)SendMessage( wnd, CB_GETITEMHEIGHT, -1, 0 );
cy += (int)SendMessage( wnd, CB_GETITEMHEIGHT, 0, 0 ) * num;
cy += GetSystemMetrics(SM_CYEDGE) * 2;
cy += GetSystemMetrics(SM_CYEDGE) * 2;
SetWindowPos( wnd, null, 0, 0, rc.right, cy, SWP_NOMOVE|SWP_NOZORDER );
この調整部分です。
こんでXP以降のWindowsは全部OKですかね?
XPはクラシックでもXP用のVisualスタイルでもおkっぽいですが。
その他の突っ込みどころもあれば募集致します。
補足
ありがとうございます。クラスCを通してクラスAをクラスBから操作することができました。 //クラスC.cpp ON_COMMAND(ID_TEST, test) void クラスC::OnCreate(LPCREATESTRUCT lpCreateStruct){ m_wndA.Create(... CListBox m_LISTBOX = &m_wndA.m_ListBox; } void クラスC::test(void){ m_LISTBOX->AddString(_T("test")); } //クラスB WPARAM wPara = MAKEWPARAM ( ID_TEST, NULL ) ; GetAncestor(GA_PARENT)->SendMessage(WM_COMMAND, (WPARAM)wPara, (LPARAM)lPara); 教えてください。 これ以上少しでも直接的に操作することはできないのでしょうか? GetAncestor(GA_PARENT)->FindWindowExW(NULL,NULL,NULL,_T("クラスAタイトル"))->SendMessage(WM_COMMAND, (WPARAM)wPara, (LPARAM)lPara); これでクラスAに直接メッセージを送れないのはなぜでしょうか? 親の親を取得する場合は、 GetAncestor(GA_PARENT)->GetAncestor(GA_PARENT)-> ではなくて GetAncestor(GA_PARENT)-> でいいのはなぜですか?