Выбрать главу

case WM_COMMAND:

 switch(LOWORD(wParam)) {

 case IDC_LIST:

  // It's our listbox, check the notification code

  switch(HIWORD(wParam)) {

  case LBN_SELCHANGE:

   // Selection changed, do stuff here.

   break;

  }

  break;

  // … other controls

 }

 break;

Getting Data from the ListBox

Now that we know the selection has changed, or at the request of the user, we need to get the selection from the listbox and do something useful with it.

In this example I've used a multiselection list box, so getting the list of selected items is a little trickier. If it were a single selection listbox, than you could simply send LB_GETCURSEL to retrieve the item index.

First we need to get the number of selected items, so that we can allocate a buffer to save the indexes in.

HWND hList = GetDlgItem(hwnd, IDC_LIST);

int count = SendMessage(hList, LB_GETSELCOUNT, 0, 0);

Then we allocate a buffer based on the number of items, and send LB_GETSELITEMS to fill in the array.

int *buf = GlobalAlloc(GPTR, sizeof(int) * count);

SendMessage(hList, LB_GETSELITEMS, (WPARAM)count, (LPARAM)buf);

// … Do stuff with indexes

GlobalFree(buf);

In this example, buf[0] is the first index, and so on up to buf[count – 1].

One of the things you would likely want to do with this list of indexes, is retreive the data associated with each item, and do some processing with it. This is just as simple as setting the data was originally, we just send another message.

int data = SendMessage(hList, LB_GETITEMDATA, (WPARAM)index, 0);

If the data was some other type of value (anything that is 32-bits) you could simply cast to the appropriate type. For example if you stored HBITMAP s instead of ints…

HBITMAP hData = (HBITMAP)SendMessage(hList, LB_GETITEMDATA, (WPARAM)index, 0);

Statics

Like buttons, static controls are largely trivial, but for the sake or being complete I include them here. Static controls are usually just that, static, meaning they don't change or really do anything else very special, they're largely for displaying text to the user. However you can make them slightly more useful by assigning them a unique ID (VC++ assigns a default ID of IDC_STATIC , which is -1 and effectively means "No ID") and then setting the text at runtime to present dynamic data to the user.

In the example code, I use one to display the data of the item selected in the list box, assuming one and only one is selected.

SetDlgItemInt(hwnd, IDC_SHOWCOUNT, data, FALSE);

Dialog FAQs

Example: dlg_three

Now don't get me wrong, this is a Tutorial, not a Reference, but some questions people ask SO often that I figured I might as well include them here.

Changing Colours

In general, the only reason you'd want to do this is to simulate an link on a dialog box or some similar task, because otherwise you're probably just making your program ugly and hard on the eyes if you go adding a bunch of colors to the dialogs, but that doesn't stop people from doing it, and there are actually a few valid reasons, so here you go :)

Windows sends a variety of messages related to colours to your dialog procedure, and by handling these messages you can change what colour certain things are displayed in. For example, to change the color of the dialog box itself, you can handle WM_CTLCOLORDLG, to change the colors for a static control you handle WM_CTLCOLORSTATIC and so on.

First you can create a brush to use to paint the background and store it for later. the WM_CTLCOLORDLG and related messages will get called often during the course of your program, and if you created a new brush every time, eventually you would use up a great deal of RAM with dead brushes. This way we have more control, and we can delete it when the dialog is destroyed and we know we won't need it any more.

HBRUSH g_hbrBackground = CreateSolidBrush(RGB(0, 0, 0));

case WM_CTLCOLORDLG:

 return (LONG)g_hbrBackground;

case WM_CTLCOLORSTATIC:

 {

  HDC hdcStatic = (HDC)wParam;

  SetTextColor(hdcStatic, RGB(255, 255, 255));

  SetBkMode(hdcStatic, TRANSPARENT);

  return (LONG)g_hbrBackground;

 }

 break;

Notice the line that sets the background mode to transparent… if you leave this line off the background will be filled in with the brush you specify, but when the control draws the text it will get written over with the default background color! Setting the text drawing mode to transparent fixes this problem. The other option would be to SetBkColor() to the same color as our background brush, but I like this solution better.

Changing the colors on pretty much any other standard control works the same way, just look up the WM_CTLCOLOR* messages in your Win32 reference. Note that an edit control will send a WM_CTLCOLORSTATIC if it is read only, and WM_CTLCOLOREDIT if it isn't.

Giving the Dialog an Icon

A fairly simple task, you just need to send WM_SETICON to your dialog. Since windows uses two icons however, you need to call it twice, once for the small icon displayed in the corner of the window, and once for the large one displayed when you hit Alt-Tab. You can just send the same handle both times unless you have multi-sized icons.

To just set the default application icon, you can use the following code:

SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(NULL, MAKEINTRESOURCE(IDI_APPLICATION)));

SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM)LoadIcon(NULL, MAKEINTRESOURCE(IDI_APPLICATION)));

When you substitute your own icon resource for the default, remember to change the HINSTANCE parameter of LoadIcon() to your applications instance (you can get it by calling GetModuleHandle(NULL) if you don't have it stored from WinMain()).