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; }