am trying to create class to encapsulate toolbar but the background turns black. c++ win32api - c++

I created a simple class to hide the details of creating a toolbar in win32 API but I don't like the toolbars it is producing. (See image for clarification. I don't have reputation points so I have just posted a link)
http://i35.tinypic.com/1zmfeip.jpg
I have no idea now the black background is coming into my application.
Here is the class declaration in file CToolBar.h
#ifndef _CTOOLBAR_H
#define _CTOOLBAR_H
#include<windows.h>
#include<commctrl.h>
class CToolBar
{
public:
CToolBar();//constructor
~CToolBar();//destructor
void AddButton(int iconID, int command);//add Both a button, its icon and its command ID
void Show();//display the toolbar
void Initialise(HINSTANCE hInst, HWND hParent);
protected:
HINSTANCE m_hInst;
HWND m_hParent;
HWND m_hToolBar;
HIMAGELIST m_hImageList;
TBBUTTON m_Tbb[4]; //toolbar buttons
int m_numberButtons;
};
#endif
here is the implementation in file CToolBar.cpp
//CToolBar.cpp
#include "CToolBar.h"
#include<windows.h>
#include<commctrl.h>
CToolBar::CToolBar()//the constructor
{
m_hImageList=ImageList_Create(32, 32, ILC_COLOR32, 0, 15);//returns NULL if the function fails
//finish other initialisations
InitCommonControls();//initialise commctrl.dll whatever.. or else your toolbar wont appear
}
void CToolBar::Initialise(HINSTANCE hInst, HWND hParent)
{
m_hInst=hInst;
m_hParent=hParent;
m_hToolBar=CreateWindowEx(
WS_EX_PALETTEWINDOW ,
TOOLBARCLASSNAME,
"",
WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS |WS_VISIBLE|TBSTYLE_BUTTON | TBSTYLE_TOOLTIPS | CCS_ADJUSTABLE | CCS_TOP ,
0, 0,
0, 0,
m_hParent,
NULL,
m_hInst,
0);
}
CToolBar::~CToolBar()//destructor
{
ImageList_Destroy(m_hImageList);
}
void CToolBar::AddButton(int iconID, int command)
{
HICON hIcon = LoadIcon(m_hInst, MAKEINTRESOURCE(iconID));
ImageList_AddIcon(m_hImageList, hIcon);
DeleteObject(hIcon);
if(iconID!= -1)//-1 means the separator. The rest are mere buttons
{
m_Tbb[m_numberButtons].iBitmap =m_numberButtons;
m_Tbb[m_numberButtons].idCommand = command;
m_Tbb[m_numberButtons].fsState = TBSTATE_ENABLED;
m_Tbb[m_numberButtons].fsStyle = TBSTYLE_BUTTON;
m_Tbb[m_numberButtons].dwData = 0;
m_Tbb[m_numberButtons].iString = 0;
}
else//ie if (iconID== -1) ; then display the separator. the command value is ignored
{
m_Tbb[m_numberButtons].iBitmap =-1;
m_Tbb[m_numberButtons].idCommand = 0;
m_Tbb[m_numberButtons].fsState = TBSTATE_ENABLED;
m_Tbb[m_numberButtons].fsStyle = TBSTYLE_SEP;
m_Tbb[m_numberButtons].dwData = 0;
m_Tbb[m_numberButtons].iString = 0;
}
m_numberButtons++;
}
void CToolBar::Show()
{
SendMessage(m_hToolBar, TB_SETIMAGELIST , (WPARAM)0, (LPARAM)m_hImageList);
SendMessage(m_hToolBar, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);//message for backward
//compatibility
SendMessage(m_hToolBar, TB_ADDBUTTONS, m_numberButtons, (LPARAM)m_Tbb);
SendMessage(m_hToolBar,WM_SIZE,0,0);
ShowWindow(m_hToolBar, SW_SHOW);
}
How i used the class
in main.cpp, i created a global instance of the class.
CToolBar myToolBar;
in the callback procedure, under WM_CREATE, I used some member functions.
case WM_CREATE:
myToolBar.Initialise(g_hInst,hwnd);
myToolBar.AddButton(IDI_OPEN, ID_OPEN);
myToolBar.AddButton(IDI_MAIN,ID_OPEN);//Separator button
myToolBar.AddButton(IDI_CLOSE, ID_CLOSE);
myToolBar.AddButton(IDI_CLOSEALL, ID_CLOSE);
myToolBar.Show();
break;
That's about it.

Try modifying the flags parameter of ImageList_Create to include ILC_MASK as well

Looks like you are using bitmap with transparency channel. GDI does not support alpha channel. It uses special color which will be transparent. If you want to support 32-bit bitmaps you could use GDI+ for drawing such bitmaps. Another option is to use CAplhaToolbar which already supports bitmaps with alpha transparency.

Related

Can not assign different Icons in Win32 ImageList only one Icon is being shown

I am working on a project that uses Win32 listview to arrange and visualize some data and files. And I would like to add different kind of icons to the list items along with their names. I have seen screenshots of many applications that has different kind of icons assigned to it and mine one , with no icons , looks very much odd and old styled.
I tried the example code from Microsoft's official page which was supposed to add different icons into imagelists.I then tried to assign the imagelist to my listbox but unfortunately , only one of the icons is being assigned to all the other items and other icons are being completely ignored.
As you can see in the screenshot, the parent window has the IDI_NETWORK icon which means our resource files has successfully been configured by my application. But the problem is...
Even after adding this code from Microsoft's official site in my application to insert icons, the function InitListViewImageLists assigns the same icon to all the items in the listview.
BOOL InitListViewImageLists(HWND hWndListView)
{
int index=0;
HICON hIconItem; // Icon for list-view items.
HIMAGELIST hLarge; // Image list for icon view.
HIMAGELIST hSmall; // Image list for other views.
// Create the full-sized icon image lists.
hLarge = ImageList_Create(32,
32,
ILC_COLOR32, 1, 1);
hSmall = ImageList_Create(32,
32,
ILC_COLOR32, 1, 1);
// Add an icon to each image list.
/*hiconItem = LoadIcon(g_hInst, MAKEINTRESOURCE(IDI_ITEM));
ImageList_AddIcon(hLarge, hiconItem);
ImageList_AddIcon(hSmall, hiconItem);
DestroyIcon(hiconItem);*/
// When you are dealing with multiple icons, you can use the previous four lines of
// code inside a loop. The following code shows such a loop. The
// icons are defined in the application's header file as resources, which
// are numbered consecutively starting with IDS_FIRSTICON. The number of
// icons is defined in the header file as C_ICONS.
for(index = 0; index < 5; index++)
{
hIconItem = LoadIcon (GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_MALE+index));
ImageList_AddIcon(hSmall, hIconItem);
ImageList_AddIcon(hLarge, hIconItem);
DestroyIcon(hIconItem);
}
// Assign the image lists to the list-view control.
ListView_SetImageList(hWndListView, hLarge, LVSIL_NORMAL);
ListView_SetImageList(hWndListView, hSmall, LVSIL_SMALL);
return TRUE;
}
you can see in the screenshot that the listview items only have IDI_FEMALE icon assigned ignoring rest of the icons.
for(index = 0; index < 5; index++)
{
hIconItem = LoadIcon (GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_MALE+index));
ImageList_AddIcon(hSmall, hIconItem);
ImageList_AddIcon(hLarge, hIconItem);
DestroyIcon(hIconItem);
}
This code in function InitListViewImageLists was supposed to add add all the icons but unfortunately this is only assgning only one icon that is IDI_FEMALE
I am leaving my codes below
Contents of resource.rc
#include "resource.h"
IDI_MALE ICON "male.ico"
IDI_FEMALE ICON "female.ico"
IDI_NETWORK ICON "net.ico"
IDI_WIFI ICON "wifi.ico"
IDI_TRANS ICON "trans.ico"
Contents of resource.h
#define IDI_MALE 1
#define IDI_FEMALE 2
#define IDI_TRANS 3
#define IDI_WIFI 4
#define IDI_NETWORK 5
Compiled into resource.rs and is being used in my application
My Application code
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <string>
#include <windows.h>
#include <commctrl.h>
#include "resource.h"
HWND Wmain , ListView;
char col[][255] = {"Filename","Size"};
// InitListViewImageLists: Creates image lists for a list-view control.
// This function only creates image lists. It does not insert the items into
// the control, which is necessary for the control to be visible.
//
// Returns TRUE if successful, or FALSE otherwise.
//
// hWndListView: Handle to the list-view control.
// global variable g_hInst: The handle to the module of either a
// dynamic-link library (DLL) or executable (.exe) that contains
// the image to be loaded. If loading a standard or system
// icon, set g_hInst to NULL.
//
BOOL InitListViewImageLists(HWND hWndListView)
{
int index=0;
HICON hIconItem; // Icon for list-view items.
HIMAGELIST hLarge; // Image list for icon view.
HIMAGELIST hSmall; // Image list for other views.
// Create the full-sized icon image lists.
hLarge = ImageList_Create(32,
32,
ILC_COLOR32, 1, 1);
hSmall = ImageList_Create(32,
32,
ILC_COLOR32, 1, 1);
// Add an icon to each image list.
/*hiconItem = LoadIcon(g_hInst, MAKEINTRESOURCE(IDI_ITEM));
ImageList_AddIcon(hLarge, hiconItem);
ImageList_AddIcon(hSmall, hiconItem);
DestroyIcon(hiconItem);*/
// When you are dealing with multiple icons, you can use the previous four lines of
// code inside a loop. The following code shows such a loop. The
// icons are defined in the application's header file as resources, which
// are numbered consecutively starting with IDS_FIRSTICON. The number of
// icons is defined in the header file as C_ICONS.
for(index = 0; index < 5; index++)
{
hIconItem = LoadIcon (GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_MALE+index));
ImageList_AddIcon(hSmall, hIconItem);
ImageList_AddIcon(hLarge, hIconItem);
DestroyIcon(hIconItem);
}
// Assign the image lists to the list-view control.
ListView_SetImageList(hWndListView, hLarge, LVSIL_NORMAL);
ListView_SetImageList(hWndListView, hSmall, LVSIL_SMALL);
return TRUE;
}
void LV_addColumns(HWND hwnd , char name[] , char size[]){
LVCOLUMN lvc;
lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
int counter=0;
lvc.iSubItem = counter++;
lvc.pszText = (LPSTR)name;
lvc.cx = 200;
lvc.fmt = LVCFMT_LEFT;
ListView_InsertColumn(hwnd, counter, &lvc);
lvc.iSubItem = counter;
lvc.pszText = (LPSTR)size;
lvc.cx = 200;
lvc.fmt = LVCFMT_LEFT;
ListView_InsertColumn(hwnd, counter, &lvc);
}
void AddLVItem(HWND hwnd , int index,char Name[] , char Size[]){
LVITEM lvi;
int x=0;
lvi.mask= LVIF_TEXT | LVIF_IMAGE;
lvi.iItem=index; //cRecord is raised 1 before every function call
lvi.iImage = 1;
lvi.iSubItem=0;
lvi.pszText=(LPSTR)"1";
SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &lvi);
//Add Subitems from a structur
lvi.iSubItem=0;
lvi.pszText=(LPSTR)Name;
lvi.mask = LVIF_TEXT | LVIF_STATE ;
SendMessage(hwnd, LVM_SETITEM, 0,(LPARAM) &lvi);
lvi.iSubItem=1;
lvi.pszText=(LPSTR)Size;
lvi.mask = LVIF_TEXT | LVIF_STATE ;
SendMessage(hwnd, LVM_SETITEM, 0,(LPARAM) &lvi);
}
LRESULT CALLBACK WndProc(HWND hwnd , UINT Msg , WPARAM wParam , LPARAM lParam){
switch(Msg){
case WM_DESTROY: {
PostQuitMessage(0);
break;
}
case WM_CREATE: {
ListView= CreateWindowEx(WS_EX_CLIENTEDGE, WC_LISTVIEW, NULL, LVS_REPORT | WS_VISIBLE|WS_CHILD | LVS_ICON , 0, 0, 400, 500, hwnd, NULL, NULL, NULL);
LV_addColumns(ListView,(char*)"FileName",(char*)"Size");
AddLVItem(ListView,0,(char*)"AudioFile",(char*)"3GB");
AddLVItem(ListView,1,(char*)"ImageFile",(char*)"10MB");
AddLVItem(ListView,2,(char*)"VideoFile",(char*)"100MB");
AddLVItem(ListView,3,(char*)"TextFile",(char*)"300B");
InitListViewImageLists(ListView);
break;
}
case WM_COMMAND: {
break;
}
default:
return DefWindowProc(hwnd,Msg,wParam,lParam);
}
return 0;
}
/* Below are the codes for parent Window (WinMain) that have not been provided here to keep the code short and more readable */
After more googling ...
I further tried codes from CodeProject and StackOverflow but I dont seem to have luck.
Now how can I achieve something like this ? This is what I want.
I have been trying to figure it out since the day before yesterday but I think I am in need of some advices from the experienced community. The compilers I am using are gcc and g++ (MinGW on Windows 10).Please provide a working source code along with a good explanation . A working source code will make it easier for me to understand my errors.
Thank You So Much!

C++ changing image on user input in WinAPI

I am having issues in getting my .bmp image displayed to change to another one on user input. The image can be successfully printed at the start (title.bmp), but is supposed to change when pressing 1 or 2 followed by enter (to introduction.bmp & start.bmp). I must be missing something!
Where this happens is around the bottom of the code from while (running == 1) { so skip down to there.
I am using loadImage("title.bmp"); to print my images (I change the filename appropriately of course), and cin >> menuSelection; to pause the program and wait until the user presses one or two followed by enter.
I've searched many, many pages on how to print and change images in WinAPI, and this is the closest I can get. If there is any other information I have missed please tell me and I will comment it. Thanks in advance for helping!
//These are the libraries (external files) to include at the start.
#include <cstdio>
#include <windows.h>
#include <iostream>
#include <stdlib.h>
#include <time.h>
#include <string>
using namespace std;
//Defining the [global] variables that will be used throughout the program
int running = 1;
int menuSelection = 0;
int userInput;
int userInputDummy;
int intPointer;
//Starter variables used in creating a window and printing images. These are global.
HDC imageDC; // the DC to hold our image
HBITMAP imageBmp; // the actual bitmap which contains the image (will be put in the DC)
HBITMAP imageBmpOld; // the DC's old bitmap (for cleanup)
const int screenSize_X = 640;
const int screenSize_Y = 480;
//Functions! Sections of code to re-used in the program
// Function to load the image into our DC so we can draw it to the screen
void loadImage(const char* pathname)
{
imageDC = CreateCompatibleDC(NULL); // create an offscreen DC
imageBmp = (HBITMAP)LoadImageA( // load the bitmap from a file
NULL, // not loading from a module, so this is NULL
pathname, // the path we're loading from
IMAGE_BITMAP, // we are loading a bitmap
0, 0, // don't need to specify width/height
LR_DEFAULTSIZE | LR_LOADFROMFILE// use the default bitmap size (whatever the file is), and load it from a file
);
imageBmpOld = (HBITMAP)SelectObject(imageDC, imageBmp); // put the loaded image into our DC
}
// Function to clean up
void cleanUpImage()
{
SelectObject(imageDC, imageBmpOld); // put the old bmp back in our DC
DeleteObject(imageBmp); // delete the bmp we loaded
DeleteDC(imageDC); // delete the DC we created
}
// The function to draw our image to the display (the given DC is the screen DC)
void drawImage(HDC screen)
{
BitBlt(
screen, // tell it we want to draw to the screen
0, 0, // as position 0,0 (upper-left corner)
screenSize_X, // width of the rect to draw
screenSize_Y, // height of the rect
imageDC, // the DC to get the rect from (our image DC)
0, 0, // take it from position 0,0 in the image DC
SRCCOPY // tell it to do a pixel-by-pixel copy
);
}
// A callback to handle Windows messages as they happen
LRESULT CALLBACK wndProc(HWND wnd, UINT msg, WPARAM w, LPARAM l)
{
// what kind of message is this?
switch (msg)
{
// we are interested in WM_PAINT, as that is how we draw
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC screen = BeginPaint(wnd, &ps); // Get the screen DC
drawImage(screen); // draw our image to our screen DC
EndPaint(wnd, &ps); // clean up
}break;
// we are also interested in the WM_DESTROY message, as that lets us know when to close the window
case WM_DESTROY:
PostQuitMessage(0);
break;
}
// for everything else, let the default window message handler do its thing
return DefWindowProc(wnd, msg, w, l);
}
// A function to create the window and get it set up
HWND createWindow(HINSTANCE inst)
{
WNDCLASSEX wc = { 0 }; // create a WNDCLASSEX struct and zero it
wc.cbSize = sizeof(WNDCLASSEX); // tell windows the size of this struct
wc.hCursor = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW)); // tell it to use the normal arrow cursor for this window
wc.hInstance = inst; // give it our program instance
wc.lpfnWndProc = wndProc; // tell it to use our wndProc function to handle messages
wc.lpszClassName = TEXT("DisplayImage"); // give this window class a name.
RegisterClassEx(&wc); // register our window class with Windows
// the style of the window we want... we want a normal window but do not want it resizable.
int style = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU; // normal overlapped window with a caption and a system menu (the X to close)
// Figure out how big we need to make the window so that the CLIENT area (the part we will be drawing to) is
// the desired size
RECT rc = { 0,0,screenSize_X,screenSize_Y }; // desired rect
AdjustWindowRect(&rc, style, FALSE); // adjust the rect with the given style, FALSE because there is no menu
return CreateWindow( // create the window
TEXT("DisplayImage"), // the name of the window class to use for this window (the one we just registered)
TEXT("Display an Image"), // the text to appear on the title of the window
style | WS_VISIBLE, // the style of this window (OR it with WS_VISIBLE so it actually becomes visible immediately)
100, 100, // create it at position 100,100
rc.right - rc.left, // width of the window we want
rc.bottom - rc.top, // height of the window
NULL, NULL, // no parent window, no menu
inst, // our program instance
NULL); // no extra parameter
}
//||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// _________________________________________________________________________________________
// The actual entry point for the program!
// This is Windows' version of the 'main' function:
int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmd, int show)
{
// load our image
loadImage("title.bmp");
// create our window
HWND wnd = createWindow(inst);
// Do the message pump! keep polling for messages (and respond to them)
// until the user closes the window.
MSG msg;
while (GetMessage(&msg, wnd, 0, 0)) // while we are getting non-WM_QUIT messages...
TranslateMessage(&msg); // translate them
DispatchMessage(&msg); // and dispatch them (our wndProc will process them)
{
while (running == 1) {
//Welcoming the user to the program, and asking them what they want to do (starts functions)
cin >> menuSelection;
//Selecting the introduction option
if (menuSelection == 1) {
loadImage("introduction.bmp");
cin >> userInputDummy;
menuSelection = 0;
}
//Selecting the start option
else if (menuSelection == 2) {
loadImage("start");
cin >> userInputDummy;
menuSelection = 0;
}
//Selecting the exit option
else if (menuSelection == 3) {
menuSelection = 0;
running = 0;
}
}
// once the user quits....
cleanUpImage();
return 0;
return EXIT_SUCCESS;
}
}
you cannot use cin in win32 use an editbox then get the user's input from it as character string then if you want convert it to an integer value otherwise use the API:
GetDlgItemInt(...);
you are also handling only GetMessage in while-loop while you only handle dispatchmessage outside the loop which means you handle it only once, when getmessage fails (the end of program) so the result is a freezing windows as long as there's no one who takes messages from getmessage to the target windo.
the solution: make DispatchMessage inside while loop:
another thing: you pass hwnd to getmessage the result destroying the window won't make the application exit.
take a look at GetMessage() when passing a non-null value:
link text
the correct thing in your case:
while (GetMessage(&msg, 0, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
* don't load image inside loop just load at the time wanted:
make an edit box with style ES_NUMBER and another button names for example change image so when clicked take the content of edit box convert it to integer, check whether it is 1 or 2 then load imaged depending the value.
you may ask "why I can't use iostream input and output streams in win32" because I ask you "where is console windows?" and if it is here what is the role of while-loop (blocking waiting for messages)?

Changing MFC List Control header color

I am looking for the simplest way to change the header color of a 'List Control' header in MFC C++. I have found ways to change individual cells and rows, but can't get a working version that changes the header color. This is all the code I am using that deals with the header:
//Initializes the List Control with four columns
m_CListCtrl.InsertColumn(0, _T("Option"), LVCFMT_LEFT, 200);
m_CListCtrl.InsertColumn(1, _T("User"), LVCFMT_LEFT, 60);
m_CListCtrl.InsertColumn(2, _T("Value"), LVCFMT_LEFT, 80);
m_CListCtrl.InsertColumn(3, _T("Description"), LVCFMT_LEFT, 800);
This can be done, but, not without a little extra coding. What you’ll need to do:
Derive your own class from CListCtrl.
Derive your own class from CHeaderCtrl.
Replace the standard CListCtrl header with yours.
Use custom drawing for the header control.
In derived CListCtrl,
void MyListCtrl::PreSubclassWindow()
{
// TODO: Add your specialized code here and/or call the base class
CHeaderCtrl* pHeader = NULL;
pHeader = GetHeaderCtrl();
if (pHeader != NULL)
{
VERIFY(m_HeaderCtrl.SubclassWindow(pHeader->m_hWnd)); // m_HeaderCtrl is the new wrapper object
}
CListCtrl::PreSubclassWindow();
}
In the header class,
void MyHeader::OnNMCustomdraw(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMCUSTOMDRAW pNMCD = reinterpret_cast<LPNMCUSTOMDRAW>(pNMHDR);
// TODO: Add your control notification handler code here
*pResult = CDRF_DODEFAULT;
if (pNMCD->dwDrawStage == CDDS_PREPAINT)
{
CDC* pDC = CDC::FromHandle(pNMCD->hdc);
CRect rect(0, 0, 0, 0);
GetClientRect(&rect);
pDC->FillSolidRect(&rect, RGB(255, 0, 0));
*pResult = CDRF_NOTIFYITEMDRAW;
}
else if (pNMCD->dwDrawStage == CDDS_ITEMPREPAINT)
{
HDITEM hditem;
TCHAR buffer[MAX_PATH] = { 0 };
SecureZeroMemory(&hditem, sizeof(HDITEM));
hditem.mask = HDI_TEXT;
hditem.pszText = buffer;
hditem.cchTextMax = MAX_PATH;
GetItem(pNMCD->dwItemSpec, &hditem);
CDC* pDC = CDC::FromHandle(pNMCD->hdc);
pDC->SetTextColor(RGB(0, 0, 0));
pDC->SetBkColor(RGB(255, 0, 0));
CString str(buffer);
pDC->DrawText(str, CRect(pNMCD->rc), DT_VCENTER | DT_LEFT);
*pResult = CDRF_SKIPDEFAULT;
}
}
Using my sample code, you should see....
I'll leave any customization for you to finish.

how to change the position of the child window inside the parent window and show the toolbar?

I have the following code which passes a window handler form OpenCV window to win32 handler, therefore I can show the grabbed images from camera to the screen and the images will show as a child window of my main API.
but the problem is that when I want to add a tooldbar to my program, the image window handler comes at the top of the toolbar. how can I sort this out?
//create a window and set the handler from openCV to win32
cv::namedWindow("test",cv::WINDOW_AUTOSIZE);
hWnd2 = (HWND) cvGetWindowHandle("test");
hParent = ::GetParent(hWnd2);
::SetParent(hWnd2, hWnd);
::ShowWindow(hParent, SW_HIDE);
_liveCapturing=true;
lastPicNr = 0;
SetWindowTextW(hStatus, L"Live Capturing ... ");
if(FullScreen()){
::ShowWindow(hWnd, SW_MAXIMIZE);
}
code for the toolbar :
HWND CreateToolbar(HWND hwnd){
HWND hTbar = CreateWindowEx(0, TOOLBARCLASSNAME, NULL, WS_CHILD | WS_VISIBLE | CCS_TOP , 0, 0, 0, 0, hwnd, (HMENU)12, GetModuleHandle(NULL), NULL);
SendMessage(hTbar, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);
TBBUTTON tbb[3];
TBADDBITMAP tbab;
tbab.hInst = HINST_COMMCTRL;
tbab.nID = IDB_STD_SMALL_COLOR;
SendMessage(hTbar, TB_ADDBITMAP, 0, (LPARAM)&tbab);
return hTbar;
}
Probably you have found the solution a long time ago, but i want to post my anwers in case other users need it.
You can simply add the OpenCV window with the same code you have to a child window in your window (which you set it position in advance). For example you can add it to a static text window (label) ...
If you want to move the OpenCV window, call SetWindowPos() with the desired coordinates.
SetWindowPos(hWnd2, 0, 0, 30, 0, 0, SWP_NOSIZE | SWP_NOZORDER);

Transparent radio button control with themes using Win32

I am trying to make a radio button control with a transparent background using only Win32 when themes are enabled. The reason for doing this is to allow a radio button to be placed over an image and have the image show (rather than the grey default control background).
What happens out of the box is that the control will have the grey default control background and the standard method of changing this by handling either WM_CTLCOLORSTATIC or WM_CTLCOLORBTN as shown below does not work:
case WM_CTLCOLORSTATIC:
hdcStatic = (HDC)wParam;
SetTextColor(hdcStatic, RGB(0,0,0));
SetBkMode(hdcStatic,TRANSPARENT);
return (LRESULT)GetStockObject(NULL_BRUSH);
break;
My research so far indicates that Owner Draw is the only way to achieve this. I've managed to get most of the way with an Owner Draw radio button - with the code below I have a radio button and a transparent background (the background is set in WM_CTLCOLORBTN). However, the edges of the radio check are cut off using this method - I can get them back by uncommenting the call to the function DrawThemeParentBackgroundEx but this breaks the transparency.
void DrawRadioControl(HWND hwnd, HTHEME hTheme, HDC dc, bool checked, RECT rcItem)
{
if (hTheme)
{
static const int cb_size = 13;
RECT bgRect, textRect;
HFONT font = (HFONT)SendMessageW(hwnd, WM_GETFONT, 0, 0);
WCHAR *text = L"Experiment";
DWORD state = ((checked) ? RBS_CHECKEDNORMAL : RBS_UNCHECKEDNORMAL) | ((bMouseOverButton) ? RBS_HOT : 0);
GetClientRect(hwnd, &bgRect);
GetThemeBackgroundContentRect(hTheme, dc, BP_RADIOBUTTON, state, &bgRect, &textRect);
DWORD dtFlags = DT_VCENTER | DT_SINGLELINE;
if (dtFlags & DT_SINGLELINE) /* Center the checkbox / radio button to the text. */
bgRect.top = bgRect.top + (textRect.bottom - textRect.top - cb_size) / 2;
/* adjust for the check/radio marker */
bgRect.bottom = bgRect.top + cb_size;
bgRect.right = bgRect.left + cb_size;
textRect.left = bgRect.right + 6;
//Uncommenting this line will fix the button corners but breaks transparency
//DrawThemeParentBackgroundEx(hwnd, dc, DTPB_USECTLCOLORSTATIC, NULL);
DrawThemeBackground(hTheme, dc, BP_RADIOBUTTON, state, &bgRect, NULL);
if (text)
{
DrawThemeText(hTheme, dc, BP_RADIOBUTTON, state, text, lstrlenW(text), dtFlags, 0, &textRect);
}
}
else
{
// Code for rendering the radio when themes are not present
}
}
The method above is called from WM_DRAWITEM as shown below:
case WM_DRAWITEM:
{
LPDRAWITEMSTRUCT pDIS = (LPDRAWITEMSTRUCT)lParam;
hTheme = OpenThemeData(hDlg, L"BUTTON");
HDC dc = pDIS->hDC;
wchar_t sCaption[100];
GetWindowText(GetDlgItem(hDlg, pDIS->CtlID), sCaption, 100);
std::wstring staticText(sCaption);
DrawRadioControl(pDIS->hwndItem, hTheme, dc, radio_group.IsButtonChecked(pDIS->CtlID), pDIS->rcItem, staticText);
SetBkMode(dc, TRANSPARENT);
SetTextColor(hdcStatic, RGB(0,0,0));
return TRUE;
}
So my question is two parts I suppose:
Have I missed some other way to achieve my desired result?
Is it possible to fix the clipped button corners issue with my code and still have a transparent background
After looking at this on and off for nearly three months I've finally found a solution that I'm pleased with. What I eventually found was that the radio button edges were for some reason not being drawn by the routine within WM_DRAWITEM but that if I invalidated the radio button control's parent in a rectangle around the control, they appeared.
Since I could not find a single good example of this I'm providing the full code (in my own solution I have encapsulated my owner drawn controls into their own class, so you will need to provide some details such as whether the button is checked or not)
This is the creation of the radiobutton (adding it to the parent window) also setting GWL_UserData and subclassing the radiobutton:
HWND hWndControl = CreateWindow( _T("BUTTON"), caption, WS_CHILD | WS_VISIBLE | BS_OWNERDRAW,
xPos, yPos, width, height, parentHwnd, (HMENU) id, NULL, NULL);
// Using SetWindowLong and GWL_USERDATA I pass in the this reference, allowing my
// window proc toknow about the control state such as if it is selected
SetWindowLong( hWndControl, GWL_USERDATA, (LONG)this);
// And subclass the control - the WndProc is shown later
SetWindowSubclass(hWndControl, OwnerDrawControl::WndProc, 0, 0);
Since it is owner draw we need to handle the WM_DRAWITEM message in the parent window proc.
case WM_DRAWITEM:
{
LPDRAWITEMSTRUCT pDIS = (LPDRAWITEMSTRUCT)lParam;
hTheme = OpenThemeData(hDlg, L"BUTTON");
HDC dc = pDIS->hDC;
wchar_t sCaption[100];
GetWindowText(GetDlgItem(hDlg, pDIS->CtlID), sCaption, 100);
std::wstring staticText(sCaption);
// Controller here passes to a class that holds a map of all controls
// which then passes on to the correct instance of my owner draw class
// which has the drawing code I show below
controller->DrawControl(pDIS->hwndItem, hTheme, dc, pDIS->rcItem,
staticText, pDIS->CtlID, pDIS->itemState, pDIS->itemAction);
SetBkMode(dc, TRANSPARENT);
SetTextColor(hdcStatic, RGB(0,0,0));
CloseThemeData(hTheme);
return TRUE;
}
Here is the DrawControl method - it has access to class level variables to allow state to be managed since with owner draw this is not handled automatically.
void OwnerDrawControl::DrawControl(HWND hwnd, HTHEME hTheme, HDC dc, bool checked, RECT rcItem, std::wstring caption, int ctrlId, UINT item_state, UINT item_action)
{
// Check if we need to draw themed data
if (hTheme)
{
HWND parent = GetParent(hwnd);
static const int cb_size = 13;
RECT bgRect, textRect;
HFONT font = (HFONT)SendMessageW(hwnd, WM_GETFONT, 0, 0);
DWORD state;
// This method handles both radio buttons and checkboxes - the enums here
// are part of my own code, not Windows enums.
// We also have hot tracking - this is shown in the window subclass later
if (Type() == RADIO_BUTTON)
state = ((checked) ? RBS_CHECKEDNORMAL : RBS_UNCHECKEDNORMAL) | ((is_hot_) ? RBS_HOT : 0);
else if (Type() == CHECK_BOX)
state = ((checked) ? CBS_CHECKEDNORMAL : CBS_UNCHECKEDNORMAL) | ((is_hot_) ? RBS_HOT : 0);
GetClientRect(hwnd, &bgRect);
// the theme type is either BP_RADIOBUTTON or BP_CHECKBOX where these are Windows enums
DWORD theme_type = ThemeType();
GetThemeBackgroundContentRect(hTheme, dc, theme_type, state, &bgRect, &textRect);
DWORD dtFlags = DT_VCENTER | DT_SINGLELINE;
if (dtFlags & DT_SINGLELINE) /* Center the checkbox / radio button to the text. */
bgRect.top = bgRect.top + (textRect.bottom - textRect.top - cb_size) / 2;
/* adjust for the check/radio marker */
// The +3 and +6 are a slight fudge to allow the focus rectangle to show correctly
bgRect.bottom = bgRect.top + cb_size;
bgRect.left += 3;
bgRect.right = bgRect.left + cb_size;
textRect.left = bgRect.right + 6;
DrawThemeBackground(hTheme, dc, theme_type, state, &bgRect, NULL);
DrawThemeText(hTheme, dc, theme_type, state, caption.c_str(), lstrlenW(caption.c_str()), dtFlags, 0, &textRect);
// Draw Focus Rectangle - I still don't really like this, it draw on the parent
// mainly to work around the way DrawFocus toggles the focus rect on and off.
// That coupled with some of my other drawing meant this was the only way I found
// to get a reliable focus effect.
BOOL bODAEntire = (item_action & ODA_DRAWENTIRE);
BOOL bIsFocused = (item_state & ODS_FOCUS);
BOOL bDrawFocusRect = !(item_state & ODS_NOFOCUSRECT);
if (bIsFocused && bDrawFocusRect)
{
if ((!bODAEntire))
{
HDC pdc = GetDC(parent);
RECT prc = GetMappedRectanglePos(hwnd, parent);
DrawFocus(pdc, prc);
}
}
}
// This handles drawing when we don't have themes
else
{
TEXTMETRIC tm;
GetTextMetrics(dc, &tm);
RECT rect = { rcItem.left ,
rcItem.top ,
rcItem.left + tm.tmHeight - 1,
rcItem.top + tm.tmHeight - 1};
DWORD state = ((checked) ? DFCS_CHECKED : 0 );
if (Type() == RADIO_BUTTON)
DrawFrameControl(dc, &rect, DFC_BUTTON, DFCS_BUTTONRADIO | state);
else if (Type() == CHECK_BOX)
DrawFrameControl(dc, &rect, DFC_BUTTON, DFCS_BUTTONCHECK | state);
RECT textRect = rcItem;
textRect.left = rcItem.left + 19;
SetTextColor(dc, ::GetSysColor(COLOR_BTNTEXT));
SetBkColor(dc, ::GetSysColor(COLOR_BTNFACE));
DrawText(dc, caption.c_str(), -1, &textRect, DT_WORDBREAK | DT_TOP);
}
}
Next is the window proc that is used to subclass the radio button control - this
is called with all windows messages and handles several before then passing unhandled
ones on to the default proc.
LRESULT OwnerDrawControl::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam,
LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
// Get the button parent window
HWND parent = GetParent(hWnd);
// The page controller and the OwnerDrawControl hold some information we need to draw
// correctly, such as if the control is already set hot.
st_mini::IPageController * controller = GetWinLong<st_mini::IPageController *> (parent);
// Get the control
OwnerDrawControl *ctrl = (OwnerDrawControl*)GetWindowLong(hWnd, GWL_USERDATA);
switch (uMsg)
{
case WM_LBUTTONDOWN:
if (controller)
{
int ctrlId = GetDlgCtrlID(hWnd);
// OnCommand is where the logic for things like selecting a radiobutton
// and deselecting the rest of the group lives.
// We also call our Invalidate method there, which redraws the radio when
// it is selected. The Invalidate method will be shown last.
controller->OnCommand(parent, ctrlId, 0);
return (0);
}
break;
case WM_LBUTTONDBLCLK:
// We just treat doubleclicks as clicks
PostMessage(hWnd, WM_LBUTTONDOWN, wParam, lParam);
break;
case WM_MOUSEMOVE:
{
if (controller)
{
// This is our hot tracking allowing us to paint the control
// correctly when the mouse is over it - it sets flags that get
// used by the above DrawControl method
if(!ctrl->IsHot())
{
ctrl->SetHot(true);
// We invalidate to repaint
ctrl->InvalidateControl();
// Track the mouse event - without this the mouse leave message is not sent
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(TRACKMOUSEEVENT);
tme.dwFlags = TME_LEAVE;
tme.hwndTrack = hWnd;
TrackMouseEvent(&tme);
}
}
return (0);
}
break;
case WM_MOUSELEAVE:
{
if (controller)
{
// Turn off the hot display on the radio
if(ctrl->IsHot())
{
ctrl->SetHot(false);
ctrl->InvalidateControl();
}
}
return (0);
}
case WM_SETFOCUS:
{
ctrl->InvalidateControl();
}
case WM_KILLFOCUS:
{
RECT rcItem;
GetClientRect(hWnd, &rcItem);
HDC dc = GetDC(parent);
RECT prc = GetMappedRectanglePos(hWnd, parent);
DrawFocus(dc, prc);
return (0);
}
case WM_ERASEBKGND:
return 1;
}
// Any messages we don't process must be passed onto the original window function
return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}
Finally the last little piece of the puzzle is that you need to invalidate the control (redraw it) at the right times. I eventually found that invalidating the parent allowed the drawing to work 100% correctly. This was causing flicker until I realised that I could get away by only invalidating a rectangle as big as the radio check, rather than as big as the whole control including text as I had been.
void InvalidateControl()
{
// GetMappedRectanglePos is my own helper that uses MapWindowPoints
// to take a child control and map it to its parent
RECT rc = GetMappedRectanglePos(ctrl_, parent_);
// This was my first go, that caused flicker
// InvalidateRect(parent_, &rc_, FALSE);
// Now I invalidate a smaller rectangle
rc.right = rc.left + 13;
InvalidateRect(parent_, &rc, FALSE);
}
A lot of code and effort for something that should be simple - drawing a themed radio button over a background image. Hopefully the answer will save someone else some pain!
* One big caveat with this is it only works 100% correctly for owner controls that are over a background (such as a fill rectangle or an image). That is ok though, since it is only needed when drawing the radio control over a background.
I've done this some time ago as well. I remember the key was to just create the (radio) buttons as usual. The parent must be the dialog or window, not a tab control. You could do it differently but I created a memory dc (m_mdc) for the dialog and painted the background on that. Then add the OnCtlColorStatic and OnCtlColorBtn for your dialog:
virtual HBRUSH OnCtlColorStatic(HDC hDC, HWND hWnd)
{
RECT rc;
GetRelativeClientRect(hWnd, m_hWnd, &rc);
BitBlt(hDC, 0, 0, rc.right - rc.left, rc.bottom - rc.top, m_mdc, rc.left, rc.top, SRCCOPY);
SetBkColor(hDC, GetSysColor(COLOR_BTNFACE));
if (IsAppThemed())
SetBkMode(hDC, TRANSPARENT);
return (HBRUSH)GetStockObject(NULL_BRUSH);
}
virtual HBRUSH OnCtlColorBtn(HDC hDC, HWND hWnd)
{
return OnCtlColorStatic(hDC, hWnd);
}
The code uses some in-house classes and functions similar to MFC, but I think you should get the idea. As you can see it draws the background of these controls from the memory dc, that's key.
Give this a try and see if it works!
EDIT: If you add a tab control to the dialog and put the controls on the tab (that was the case in my app) you must capture it's background and copy it to the memory dc of the dialog. It's a bit of an ugly hack but it works, even if the machine is running some extravagant theme that uses a gradient tab background:
// calculate tab dispay area
RECT rc;
GetClientRect(m_tabControl, &rc);
m_tabControl.AdjustRect(false, &rc);
RECT rc2;
GetRelativeClientRect(m_tabControl, m_hWnd, &rc2);
rc.left += rc2.left;
rc.right += rc2.left;
rc.top += rc2.top;
rc.bottom += rc2.top;
// copy that area to background
HRGN hRgn = CreateRectRgnIndirect(&rc);
GetRelativeClientRect(m_hWnd, m_tabControl, &rc);
SetWindowOrgEx(m_mdc, rc.left, rc.top, NULL);
SelectClipRgn(m_mdc, hRgn);
SendMessage(m_tabControl, WM_PRINTCLIENT, (WPARAM)(HDC)m_mdc, PRF_CLIENT);
SelectClipRgn(m_mdc, NULL);
SetWindowOrgEx(m_mdc, 0, 0, NULL);
DeleteObject(hRgn);
Another interesting point, while we're busy now, to get it all non-flickering create the parent and children (buttons, statics, tabs etc) with the WS_CLIPCHILDREN and WS_CLIPSIBLINGS style. The the order of creation is essential: First create the controls you put on the tabs, then create the tab control. Not the other way around (although it feels more intuitive). That because the tab control should clip the area obscured by the controls on it :)
I can't immediately try this out, but so far as I recall, you don't need owner draw. You need to do this:
Return 1 from WM_ERASEBKGND.
Call DrawThemeParentBackground from WM_CTLCOLORSTATIC to draw the background there.
Return GetStockObject(NULL_BRUSH) from WM_CTLCOLORSTATIC.
Knowing the sizes and coordinates radio button, we will copy the
image to them closed.
Then we create a brush by means of
BS_PATTERN style CreateBrushIndirect
Farther according to the
usual scheme - we return handle to this brush in reply to COLOR -
the message (WM_CTLCOLORSTATIC).
I have no idea why you are doing it so difficult, this is best solved via CustomDrawing
This is my MFC Handler to draw a Notebook on a CTabCtrl control. I'm not really sure why i need to Inflate the Rectangle, because if i don't do it a black border is drawn.
And another conceptional bug MS made is IMHO that i have to overwrite the PreErase drawing phase instead of the PostErase. But if i do the later the checkbox is gone.
afx_msg void AguiRadioButton::OnCustomDraw(NMHDR* notify, LRESULT* res) {
NMCUSTOMDRAW* cd = (NMCUSTOMDRAW*)notify;
if (cd->dwDrawStage == CDDS_PREERASE) {
HTHEME theme = OpenThemeData(m_hWnd, L"Button");
CRect r = cd->rc; r.InflateRect(1,1,1,1);
DrawThemeBackground(theme, cd->hdc, TABP_BODY, 0, &r,NULL);
CloseThemeData(theme);
*res = 0;
}
*res = 0;
}