![]()
![]()
![]()
WindowsAPIを使ってウインドウなどを表示する際のメモ
LastUpdate : 06/07/02
コントロールの使い方の、個人的なメモです。
しかも、サンプルのコードは、私が書いたソフトの内部で使用されているものからの、ただのコピペです。ですので、余計なコードも入ってますのでご注意くださいw
一度覚えたけど、どーだったかなぁ・・・、なんとなくしか覚えて無いなぁ〜っていうときに、見ると、役に立ちます。
内容については、正しいのかどうなのか、保証できません。
MSDN、もうちょっと便利にならんかなぁ・・・。
※レポート形式の場合のみについて書かれています。
ヘッダにcommctrl.hを使い、comctl32.libとリンクさせる必要が有り。
また、コードの初めの方に
InitCommonControls();
を呼ぶ(コモンコントロールの初期化のため)。
☆ リストビューで項目をクリックしたら、その行をすべてを選択させたい場合
HWND hList=GetDlgItem(hwnd,IDC_LIST_LAYER);
DWORD style=ListView_GetExtendedListViewStyle(hList);
style=style | LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT;
ListView_SetExtendedListViewStyle(hList,style);
と、する。
☆ 選択されているアイテムを調べたい場合
int order=ListView_GetNextItem(hList,-1,LVNI_SELECTED);
とやると、選択されているアイテムの順番(上から数えて何番目にあるか)が帰ってくる。
第二引き数に3とか5とか数字をやると、その番号の順番から探索を始める。
また、LVNI_SELECTED以外にも、flagとして指定できる値がある。
MSDNで、「LVM_GETNEXTITEM Message」を参照のこと(キーワード検索すればでてきます)。
エラーだと-1の値が返ってくる。
☆ COLUMNにデータの設定の仕方
LV_COLUMN Col;
memset(&Col,0,sizeof(LV_COLUMN));
Col.mask=LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
Col.fmt=LVCFMT_LEFT;
Col.cx=50;
Col.iSubItem=0;
Col.pszText="表示";
ListView_InsertColumn(hList,0,&Col);
Col.cx=100;
Col.iSubItem=1;
Col.pszText="レイヤーNo.";
ListView_InsertColumn(hList,1,&Col);
とすればよい。
☆ アイテムを追加したい場合
LV_ITEM Itm;
memset(&Itm,0,sizeof(LV_ITEM));
Itm.mask=LVIF_TEXT;
Itm.iItem=0; //何番目の行か
Itm.iSubItem=0; //何番目の列か
Itm.pszText="1";
ListView_InsertItem(hList,&Itm);
Itm.pszText="サンプル";
Itm.iSubItem=1;
ListView_SetItem(hList,&Itm);
☆ アイテムの削除
ListView_DeleteAllItems(HWND hList)
ですべてのアイテムを削除。
ListView_DeleteColumn(HWND hList,int order)
でorder番目のCOLUMNを削除
ListView_DeleteItem(HWND hList,int order)
でorder番目のアイテムを削除。
☆ コールバックでNOTIFYを使うと、リストビューのおのおののイベントに対し、検出
LVN_ITEMCHANGED以外にもいくつか、ある。
LVN_ITEMCHANGEDは、何かしらの変更があれば、常に呼ばれます。
//-------------------------------------------------------------
case WM_NOTIFY:
{
LayerSelectorDialogCallBack_WM_NOTIFY(lp);
break;
}
//-------------------------------------------------------------
static int LayerSelectorDialogCallBack_WM_NOTIFY(LPARAM lp)
{
HWND hList=GetDlgItem(g_hDlgLayer,IDC_LIST_LAYER);
LPNMHDR hdr=(LPNMHDR)lp;
//リストビュー用
if( hdr->hwndFrom == hList )
{
if( hdr->code == LVN_ITEMCHANGED )
{
//リストビューに変更があった場合の処理・・・
}
}
return 0;
}
☆ リストビューの中のアイテムの数を取得
ListView_GetItemCount(hList)
☆ チェックボックス付きのリストビューで、チェックボックスがチェックされているか調べる。
ListView_GetCheckState(hListLayer,c)
で、戻ってきた値がゼロ以外ならば、チェックされています。ゼロならば、チェックされていません。
☆ チェックボックス付きリストビューで、チェックボックスをチェックする。
ListView_SetCheckState(hList,0,TRUE); //チェックされた状態にする。
で、第二引き数が場所。
☆ リストビューのアイテムを選択し、フォーカスをセット。
ListView_SetItemState(hList,0,LVIS_SELECTED | LVIS_FOCUSED,LVIS_SELECTED | LVIS_FOCUSED);//一番最初の項目を選択。
第二引き数が場所。
なんだか理屈はよくわからないが、こうすればなるw
☆ 文字列の取得、設定
SetWindowText(HWND hwnd,LPSTR str)
GetWindowText(HWND hwnd,LPSTR str,int str_len);
で、基本的に、値のセット・取得は可能。取得する際、長さがあらかじめ知りたい場合は
GetWindowTextLength(HWND hwnd)
を使う。
☆ 数字だけしか入力できないようにする
SetWindowLong( hEdit , GWL_STYLE , ES_NUMBER | GetWindowLong(hEdit,GWL_STYLE) )
でよかったはず。
☆ 読み取り専用にする
SendMEssage(hEdit,ES_READONLY,0,0);
でよかった気がしないようでもない。
☆ WM_NOTIFY
switch( msg )
{
//...なんかのコード(switch( msg )以下
case WM_COMMAND:
{
switch( LOWORD(wp) )
{
case IDR_EDIT1: //エディットボックスのID
{
if( HIWORD(wp) == EN_UPDATE )
{
//エディットボックス(識別IDがIDR_EDIT1)に何か変更があった
//...
}
break;
}
}
break;
}
//...なんかのコード
}
とかやるとよい。EN_UPDATE以外にも色々ある。
また、EDITコントロールは、保持するテキストを無限には保証していない。
大量のテキストは処理できない・・・らしいw(そういう場面にまだ出くわしたことが無い)。
☆ 現在の選択位置を取得
int cursel=SendMessage(hCombo,CB_GETCURSEL,0,0);
で、エラーだとCB_ERRが帰ってきます。
☆ 内容をすべて消去
SendMessage(hCombo,CB_RESETCONTENT,0,0)
とする。
☆ アイテムを追加
SendMessage(hPalleteDialogImageCombo,CB_INSERTSTRING,(WPARAM)i,(LPARAM)str);
もしくは、
SendMessage(hPalleteDialogImageCombo,CB_ADDSTRING,(WPARAM)0,(LPARAM)str);
iは、挿入する位置、strは文字列。
ADDSTRINGは、そのまま、データが積まれて追加される。位置を指定したい場合は、INSERTSTRING
を使う。
☆ コンボボックスの内容が変更されたときを知る方法
コールバック関数の中で
//-------------------------------------------------------------
case WM_COMMAND:
{
switch( LOWORD(wp) )
{
//コンボボックスへのメッセージ
case IDC_COMBO_IMAGE:
{
if( HIWORD(wp) == CBN_SELCHANGE )
{
//選択項目に変更があった場合の処理
}
break;
}
}
break;
}
とする。
☆ スクロールバーの制御
コールバック関数の中で
int CALLBACK PalleteImageDialogCallBack(HWND hwnd,UINT msg,WPARAM wp,LPARAM lp)
{
switch( msg )
{
//-------------------------------------------------------------
case WM_VSCROLL:
{
SCROLLINFO Si;
memset(&Si,0,sizeof(PSCROLLBARINFO));
Si.cbSize=sizeof(SCROLLINFO);
Si.fMask=SIF_POS | SIF_RANGE | SIF_PAGE | SIF_DISABLENOSCROLL;
GetScrollInfo(g_hDlgPalleteImage,SB_VERT,&Si);
int page_size=Si.nPage; //1ページ分のサイズを取得。
int pos=0;
//スクロールバーの位置を設定。
switch( LOWORD(wp) )
{
case SB_LINEUP:
{
pos-=1;
break;
}
case SB_LINEDOWN:
{
pos+=1;
break;
}
case SB_PAGEUP:
{
pos-=page_size;
break;
}
case SB_PAGEDOWN:
{
pos+=page_size;
break;
}
case SB_THUMBTRACK:
{
pos=HIWORD(wp) - Si.nPos;
break;
}
default:
{
//処理を中止する。
return 0;
}
}
Si.nPos+=pos;
if( Si.nPos <= 0 )Si.nPos=0;
if( Si.nPos >= Si.nMax )Si.nPos=Si.nMax;
SetScrollInfo(g_hDlgPalleteImage,SB_VERT,&Si,TRUE);
break;
}
//-------------------------------------------------------------
case WM_HSCROLL:
{
//WM_VSCROLLの内容と同じ。ただしSetScrollInfoは
SetScrollInfo(g_hDlgPalleteImage,SB_VERT,&Si,TRUE);
//とすること。
break;
}
//以下省略
として、スクロールバーに対するイベントを検出。
コントロールとして作成し、たくさんスクロールバーがある場合
if( (HWND)lp == hScrollBar1 ){ //目的のスクロールバーだった場合の処理 }
とLPARAMの値がHWNDだそうだ。これで識別できるかも。
やったこと無いのでどうなるかわかりませんが^^;
☆ 縦横のスクロールバーの状態の取得
SCROLLINFO InfoH,InfoV;
memset(&InfoV,0,sizeof(SCROLLINFO));
memset(&InfoH,0,sizeof(SCROLLINFO));
InfoV.cbSize=sizeof(SCROLLINFO);
InfoV.fMask=SIF_ALL | SIF_DISABLENOSCROLL;
InfoH=InfoV;
GetScrollInfo(g_hWndEditor,SB_HORZ,&InfoH);
GetScrollInfo(g_hWndEditor,SB_VERT,&InfoV);
ただし、ウインドウに付属するようにして作られたスクロールバーの場合のみ。
コントロールとして作られたのならば、fMaskには、SB_CTLも追加すること。
SIF_DISABLENOSCROLLをなくせば、スクロールバーが不要な状態になると、自動的に消えます。
☆ スクロールバーの状態の設定(サンプルとして水平方向のスクロールバー
SCROLLINFO Info;
Info.cbSize=sizeof(SCROLLINFO);
Info.fMask=SIF_POS | SIF_RANGE | SIF_PAGE | SIF_DISABLENOSCROLL;
Info.nMin=0;
Info.nMax=width;
Info.nPage=Rc.right;
Info.nPos=0; //現在表示している位置
SetScrollInfo(g_hDlgPalleteImage,SB_HORZ,&Info,TRUE);
このInfo.nMaxとInfo.nPageの関係であるが、たとえば、イメージならば、nMaxに、表示したい
イメージの横幅、そして、nPageに、現在の表示エリアの横幅を設定しておけばよい。
GetScrollInfoで取得したnPosには、0〜(nMax - nPage-1)の値がはいる・・・だった気がした。
詳細はヘルプでしらべてくだちぃ(ぉ
普通に、CreateDialogすればよい。手を加えなければならないのは、メッセージループのところである。
☆ メッセージループ
//メッセージループへ
MSG msg;
while( GetMessage(&msg, NULL, 0, 0) )
{
if( IsDialogMessage(g_hDlgPallete,&msg) == 0 && IsDialogMessage(g_hDlgLayer,&msg) == 0 )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
}
return (int)msg.wParam;
と、IsDialogMessage関数で、自分のダイアログへのメッセージかを調べる(自分へのメッセージではなかったら、ゼロを返す)。
そして、自分のではなかったら、DispatchMessage関数とかを呼ぶ。
という処理の流れ。
☆ アクセラレーターを使う場合。
HACCEL hAccel=LoadAccelerators(hInst,MAKEINTRESOURCE(IDR_ACCEL1); //IDR_ACCEL1はresource.hで定義されてるとする
//メッセージループへ
MSG msg;
while( GetMessage(&msg, NULL, 0, 0) )
{
if( IsDialogMessage(g_hDlgPallete,&msg) == 0 && TranslateAccelerator(g_hDlgPallete,hAccel,&msg) == 0 )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
}
return (int)msg.wParam;
とするといいらしい。昔書いたコードなので、忘れた(ぉ
☆ アイテムの挿入・追加
SendMessage(hList,LB_ADDSTRING,(WPARAM)0,(LPARAM)str)
SendMessage(hList,LB_INSERTSTRING,(WPARAM)order,(LPARAM)str)
とする。
orderは、挿入する位置、strは挿入する文字列。
☆ アイテムの削除
SendMessage(hList,LB_DELETESTRING,(WPARAM)order,(LAPARAM)0)
で、order番目(ゼロがら数えて)のアイテムを削除
SendMessage(hList,LB_RESETCONTENT,(WPARAM)0,(LAPARAM)0)
で、全部削除。
☆ アイテムの数を取得
int count=SendMessage(hList,LB_GETCOUNT,(WPARAM)0,(LAPARAM)0)
で取得する。count == LB_ERRだと、エラーです。
☆ 選択カーソル位置を取得
int count=SendMessage(hList,LB_GETCURSEL,(WPARAM)0,(LAPARAM)0)
で取得する。count == LB_ERRだと、エラーです。
☆ 選択カーソル位置を設定
SendMessage(hList,LB_SETCURSEL,(WPARAM)order,(LAPARAM)0)
order番目に、カーソルをセットします。
☆ アイテムの文字列を取得。
char str[256];
memset(str,0,256);
SendMessage(hList,LB_GETTEXT,(WPARAM)order,(LAPARAM)str)
とかします。文字列の長さが不安ならば、
int len=SendMessage(hList,LB_GETTEXTLEN,(WPARAM)order,(LAPARAM)str)
とし、文字列の長さを取得してから処理するものよいかもしれません。
☆ NOTIFY
コールバック関数の中で
//-------------------------------------------------------------
case WM_COMMAND:
{
switch( LOWORD(wp) )
{
//エディットボックスへのメッセージ
case IDC_EDIT1:
{
if( HIWORD(wp) == LBN_SELCHANGE )
{
//選択項目に変更があった場合の処理
//..
}
break;
}
}
break;
}
ヘッダにcommctrl.hを使い、comctl32.libとリンクさせる必要が有る。
char str[256];
memset(str,0,256);
OPENFILENAME Ofn;
memset(&Ofn,0,sizeof(OPENFILENAME));
Ofn.lStructSize = sizeof(OPENFILENAME);
Ofn.Flags = OFN_FILEMUSTEXIST;
Ofn.lpstrFilter = "TargaFile(*tga)\0*.tga\0\0";
Ofn.nFilterIndex = 0;
Ofn.hwndOwner = g_hDlgPallete;
Ofn.lpstrFile = str;
Ofn.nMaxFile = 256;
if( GetOpenFileName(&Ofn) == 0 )return NULL; //キャンセルされた。
コードの中ではstr[256]としているが、str[MAX_PATH]とかやるほうが良さそうな雰囲気である。
Ofn.lpstrFilterであるが、書き方はこういう感じ。
ファイルが選択されて「開く」ボタンが押されると戻り値はゼロ以外の値が帰ってくる。
そして、strにそのパス(フルパス)が入っている。
表示する名前(1)\0*.bmp\0表示する名前(2)\0*.jpg表示する名前(3)\0*.png\0\0
最後は\0\0で終わる。
文字列+\0+検索用のコマンド\0
で一つのセット。増やしたい場合は\0以降、繋げる。
ヘッダにcommctrl.hを使い、comctl32.libとリンクさせる必要が有る。
コード内のcust_colorは、RGBの値を示す部分以外はゼロで埋める必要がある。
HWND hEditColor=GetDlgItem(hDlg,IDC_EDIT_SETTING_LINE_COLOR);
COLORREF cust_color[16];
memset(cust_color,0,sizeof(COLORREF) * 16);
CHOOSECOLOR Cc;
memset(&Cc,0,sizeof(CHOOSECOLOR));
Cc.lStructSize=sizeof(CHOOSECOLOR);
Cc.Flags=CC_FULLOPEN;
Cc.hwndOwner=g_hWndEditor;
Cc.rgbResult=0;
Cc.lpCustColors=cust_color;
if( ChooseColor(&Cc) == 0 ) return -1; //キャンセルボタンが押された。
//エディットボックスに色の値をセット。
char str[256];
memset(str,0,256);
sprintf(str,"R: %d G: %d B: %d",GetRValue(Cc.rgbResult),GetGValue(Cc.rgbResult),GetBValue(Cc.rgbResult));
SetWindowText(hEditColor,str);
とかやるとよい。
ダイアログなら、ドラッグ&ドロップを許可するように設定すること。
ウインドウならば、DragAcceptFiles関数なんかでドラッグ&ドロップを許可させること(DragAcceptFiles(hwnd,TRUE)とかやる)。
コールバック関数内でファイルがドロップされるとWM_DROPFILESで知らせてくれるので、こーする。
int CALLBACK FilerDialogCallback(HWND hwnd,UINT msg,WPARAM wp,LPARAM lp)
{
switch( msg )
{
//-------------------------------------------------------------
case WM_DROPFILES:
{
FilerDialogDroppedFile(hwnd,wp);
break;
}
・・・・・・(以下うだうだ。
で、このメッセージが来たときの処理方法は以下のとおり。
DragQueryFileの第二引数に-1を指定すると、ドロップしたファイルの数を取得できる。
この第二引数は、ドロップされたファイルの何番目のパスを取得したいのか、を指定するのに使う。
処理の最後にはDragFinishで内部で確保したらしいメモリを解放させる。
int FilerDialogDroppedFile(HWND hwnd,WPARAM wp)
{
//ドロップされたファイルの数を取得。
unsigned int count = DragQueryFile((HDROP)wp,-1,0,0);
//ファイルのパスを得る。
unsigned int len;
char path[ MAX_PATH ];
unsigned int i;
for( i=0;;i++ )
{
if( i >= count )break;
memset(path,0,MAX_PATH);
len = DragQueryFile((HDROP)wp,i,path,MAX_PATH-1);
path[ len ] = '\0';
//converterクラスにファイルパスを追加。
if( FilerDialogDroppedFile_add_path(hwnd,path) )
{
DragFinish((HDROP)wp);
return -1;
}
}
DragFinish((HDROP)wp);
return 0;
}