Donnerstag, 24. März 2011

Getting static - Tips with static controls

Aloha

This article covers handling of static controls. Those controls are a bit nasty and need to be tweaked so they work correctly. Also it sometimes is not obvious that a control is a static control which we will see later!

The following code is based on the project created in this article. If you dont remember how interacting with controls works check out this article.

Our final application will load an image when a button is pressed and display it inside a picturebox. You maybe are wondering now where there is a static control involved because neither a button nor a picturebox is really static. But in fact a picturebox is considered a static control. To be clearer a picturebox is nothing more than a simple static control with a style that indicates that this control accepts bitmaps as background.

To start we drag a picturebox control on the dialog and we add a button. I renamed the button to IDB_LOADIMG and left the picturebox as it is. If you save now and open the resource.h you may see that there is only the IDB_LOADIMG and the ID from the picturebox is not present! Why?

Static controls by default are not listed and cannot be accessed. To change that you have to change the ID of every static control you create. This will immediatly add it to the resource.h. Ok, i renamed my picturebox control to IDC_PICBOX. To set the background of a static control you have to send a message to that control. This is done using the function SendMessage. The message to use is STM_SETIMAGE. So the code looks like that:
#include <Windows.h>
#include "resource.h"

#pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")

BOOL WINAPI DialogProc(HWND hWindow, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
 static HWND hButtonLoad = NULL;
 static HWND hPicBox = NULL;
 static HBITMAP hBmp = (HBITMAP)LoadImage(NULL, "image.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);

 switch(uMsg)
 {
 case WM_CLOSE:
  EndDialog(hWindow, 0);
  DestroyWindow(hWindow);
  return TRUE;

 case WM_INITDIALOG:
  {
   hButtonLoad = GetDlgItem(hWindow, IDB_LOADIMG);
   hPicBox = GetDlgItem(hWindow, IDC_PICBOX);
   if(hButtonLoad == NULL || hPicBox == NULL)
   {
    MessageBox(hWindow, "Unable to retrieve controls! Closing....", "Error!", MB_OK);
    EndDialog(hWindow, 0);
    DestroyWindow(hWindow);
    return TRUE;
   }

   break;
  }
  return TRUE;

 case WM_COMMAND:
  {
   if(HIWORD(wParam) != BN_CLICKED) // we are only interested in clicks
    break;

   switch(LOWORD(wParam))
   {
   case IDB_LOADIMG:
    {
     SendMessage(hPicBox, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hBmp);
     break;
    }
    break;
   }
  }
  return TRUE;
 }

 return FALSE;
}

int main()
{
 DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_DIALOG1), GetDesktopWindow(), DialogProc);
}

If you run this you need to make sure that an image called image.bmp is in the folder of the executable. LoadImage is used to load that image as a bitmap. The WPARAM of STM_SETIMAGE indicates which type of background we are sending and the LPARAM is in this case a handle to the bitmap.

When you compile this and run the application and press the button to load the image most likely you will see something like that:


Hey, where is our image?! The answer: Its not displayed at all! Why? Pretty simple: Have a look at the properties page of the picturebox control inside the dialog editor. You can find the column "type" which currently contains "Frame" (unless you have changed it). This tells the system that the control is just a frame. If you send an image to that control Windows will think "Wow, its nice he sends me an image, but actually im just a frame, i dont display images!". So we need to instruct the operating system that our control should accept bitmaps. We change the "Type" to "Bitmap". You may notice that the control now isnt scalable anymore. This is because it will automatically scale to fit the size of the image that gets loaded.

If we compile now and rerun the application after pressing the button the image gets displayed, in my case it looks like that:


Cool, isnt it? :)

Thanks for reading and cya
Yanick

Kommentare:

  1. BOOL CALLBACK AppDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
    static HWND hPicBox = NULL;


    static HBITMAP hBmp = (HBITMAP)LoadImage(NULL, "C:\immagine.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
    switch(uMsg)
    {

    case WM_INITDIALOG:
    hPicBox = GetDlgItem(hDlg, IDC_STATIC);
    DragAcceptFiles(hDlg,true);
    SetClassLongPtr(hDlg, GCLP_HICON, (long)LoadIcon(0, IDI_APPLICATION));
    return 1;
    case WM_COMMAND:
    switch(wParam)
    {
    case IDOK:
    return 0;
    case IDCANCEL:
    EndDialog(hDlg, 0);
    }
    switch(wParam)
    {
    case IDC_BUTTON1:
    /* ShellExecute(hDlg,
    "open",
    "C:\immagine1.jpg",
    NULL,
    NULL,
    IDC_STATIC);*/

    SendMessage(hPicBox, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hBmp);
    break;
    }

    switch(wParam)
    {
    case IDC_BUTTON4:
    ShellExecute(hDlg,
    "open",
    "C:\log.txt",
    NULL,
    NULL,
    SW_SHOWDEFAULT);
    break;
    }






    }
    return 0;
    }



    i've followed all your steps but still doesn't work :(

    AntwortenLöschen
  2. i've solved, i was compiling and running the cpp, with the .exe there's no problem, another info, there another simple way to load jpg image? thank you! you are great!

    AntwortenLöschen
  3. Hey

    I have written two entries for GDI+ which covers Jpg/Png and so on. Here is part 1 which links to part 2
    http://win32easy.blogspot.ch/2012/11/working-with-gdi-part-1.html

    AntwortenLöschen