Related
I have created a tab control that contains two tabs. Inside each tab there will be a container window to hold other controls (in the code example, a static control for instance). The idea is that when a new tab is selected, it will hide/show the correct container window that holds a bunch of controls. However I am struggling to get the container windows holding the static controls to show. This is the code so far:
#include <windows.h>
#include <commctrl.h>
#pragma comment(lib, "comctl32.lib")
#define ID_TABCTRL 1
#define ID_STATIC0 2
#define ID_STATIC1 3
#define ID_TAB0 4
#define ID_TAB1 5
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HWND hTab, hTab0, hTab1;
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
{
MSG msg;
WNDCLASS wc = { 0 };
wc.lpszClassName = TEXT("Tab control");
wc.hInstance = hInstance;
wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
wc.lpfnWndProc = WndProc;
wc.hCursor = LoadCursor(0, IDC_ARROW);
RegisterClass(&wc);
CreateWindow(wc.lpszClassName, TEXT("Tab control"), WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 250, 200, 0, 0, hInstance, 0);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
TCITEM tie;
INITCOMMONCONTROLSEX icex;
switch (msg)
{
case WM_CREATE:
icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
icex.dwICC = ICC_TAB_CLASSES;
InitCommonControlsEx(&icex);
tie.mask = TCIF_TEXT;
///// Create Tab Control /////
hTab = CreateWindow(WC_TABCONTROL, NULL, WS_CHILD | WS_VISIBLE, 0, 0, 200, 150, hwnd, (HMENU)ID_TABCTRL, NULL, NULL);
///// Create Individual Tabs /////
tie.pszText = TEXT("First");
SendMessage(hTab, TCM_INSERTITEM, 0, (LPARAM)(LPTCITEM)&tie);
tie.pszText = TEXT("Second");
SendMessage(hTab, TCM_INSERTITEM, 1, (LPARAM)(LPTCITEM)&tie);
///// Create Container windows for each tab /////
hTab0 = CreateWindow(0, NULL, WS_CHILD | WS_VISIBLE, 0, 0, 200, 150, hTab, (HMENU)ID_TAB0, NULL, NULL);
hTab1 = CreateWindow(0, NULL, WS_CHILD, 0, 0, 200, 150, hTab, (HMENU)ID_TAB1, NULL, NULL);
///// Add example control to one of the tab container windows /////
CreateWindow(TEXT("Static"), TEXT("Yay!"), WS_CHILD | WS_VISIBLE | SS_LEFT, 20, 30, 50, 25, hTab0, (HMENU)ID_STATIC0, NULL, NULL);
CreateWindow(TEXT("Static"), TEXT("It appears to be working"), WS_CHILD | WS_VISIBLE | SS_LEFT, 20, 30, 100, 50, hTab1, (HMENU)ID_STATIC1, NULL, NULL);
break;
case WM_NOTIFY:
switch (((LPNMHDR)lParam)->code)
{
case TCN_SELCHANGE:
switch (TabCtrl_GetCurSel(hTab))
{
///// Show or Hide the appropriate tabs /////
case 0:
ShowWindow(hTab1, SW_HIDE);
ShowWindow(hTab0, SW_SHOW);
case 1:
ShowWindow(hTab0, SW_HIDE);
ShowWindow(hTab1, SW_SHOW);
}
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return(DefWindowProc(hwnd, msg, wParam, lParam));
}
Is it just a case of the container windows hTab0 and hTab1 being stuck behind the tab window (hTab)?
First, you need to change the position of the tab and static form, otherwise it will block the generated content.
Then you can define the generated static text directly through CreateWindow, by using WC_STATIC.
#include <Windows.h>
#include <commctrl.h>
LRESULT CALLBACK WndProc(HWND, UINT,WPARAM,LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT("windows");
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;
if (!RegisterClass(&wndclass))
{
MessageBox(NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR);
}
hwnd = CreateWindow(szAppName,
TEXT("the hello program"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL);
ShowWindow(hwnd,iCmdShow);
UpdateWindow(hwnd);
while (GetMessageW(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message,WPARAM wParam,LPARAM lParam)
{
static HINSTANCE hInstance;
static HWND hwndTab = 0 , hwndStatic1,hwndStatic2;
TCITEM tie;
RECT rcClient;
INITCOMMONCONTROLSEX icex;
icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
icex.dwICC = ICC_TAB_CLASSES;
TCHAR tabLBL1[256];
GetClientRect(hwnd, &rcClient);
switch (message)
{
case WM_CREATE:
{
hInstance = ((LPCREATESTRUCT)lParam)->hInstance;
hwndTab = CreateWindow(WC_TABCONTROL, L"",
WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE,
0, 0, rcClient.right, rcClient.bottom,
hwnd, NULL, hInstance, NULL);
//Add tabs for each day of the week.
tie.mask = TCIF_TEXT | TCIF_IMAGE;
tie.iImage = -1;
wsprintf(tabLBL1, L"tab1");
tie.pszText = tabLBL1;
TabCtrl_InsertItem(hwndTab, 0, &tie);
wsprintf(tabLBL1, L"tab2");
TabCtrl_InsertItem(hwndTab, 1, &tie);
hwndStatic1 = CreateWindow(WC_STATIC, L"123",
WS_CHILD | WS_VISIBLE | WS_BORDER,
200, 200, 100, 100, // Position and dimensions; example only.
hwndTab, NULL, hInstance, // g_hInst is the global instance handle
NULL);
hwndStatic2 = CreateWindow(WC_STATIC, L"456",
WS_CHILD | WS_VISIBLE | WS_BORDER,
400, 200, 100, 100, // Position and dimensions; example only.
hwndTab, NULL, hInstance, // g_hInst is the global instance handle
NULL);
ShowWindow(hwndStatic1, TRUE);
ShowWindow(hwndStatic2, FALSE);
return 0;
}
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_NOTIFY:
if (((LPNMHDR)lParam)->code == TCN_SELCHANGE)
{
int tabID = TabCtrl_GetCurSel(hwndTab);
switch (tabID)
{
case 0:
ShowWindow(hwndStatic1, TRUE);
ShowWindow(hwndStatic2, FALSE);
break;
case 1:
ShowWindow(hwndStatic1, FALSE);
ShowWindow(hwndStatic2, TRUE);
break;
default:
break;
}
}
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
Zhu Song's answer helped solved the problem (the container windows needing to be a static control, and needing to be positioned inside the tab control's space, below the clickable tabs).
Here is the result, swapping the two container window creation lines:
hTab0 = CreateWindow(TEXT("Static"), NULL, WS_CHILD | WS_VISIBLE, 1, 25, 197, 123, hTab, (HMENU)ID_TAB0, NULL, NULL);
hTab1 = CreateWindow(TEXT("Static"), NULL, WS_CHILD, 1, 25, 197, 123, hTab, (HMENU)ID_TAB1, NULL, NULL);
Note how the container window sizes and position are small enough to just fit inside the main tab control window (you can add WS_BORDER to the style to see where exactly it fits).
So I've been trying to add images to my WinAPI TreeView Common Control items. However, I have encountered something that has really been bothering me and I have no clue why it is happening. For some reason, the Image in a TreeView has a different color than the actual bitmap does. I took a screenshot of a test program I made that paints a BMP image file along with its TreeView counterpart. (It is the exact same image yet both drawings yield different results).
As you can see the image on the left is what it should look like and the image on the right is what the TreeView is drawing. Is this just the way TreeView works or something? Or is there something in my code that I'm doing wrong? It would be much appreciated if anyone could point this out because out of personal taste, the TreeView image looks visually disgusting and I would like the TreeView Control to draw my image correctly :P
The following is the code I am using to create the Treeview:
//Load image from relative file path
g_hBmp = LoadImage(GetModuleHandle(NULL), "image.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_DEFAULTSIZE);
//Create Treeview
HWND treeview = CreateWindowEx(0, WC_TREEVIEW, NULL,
WS_VISIBLE | WS_CHILD | TVS_FULLROWSELECT,
250, 100, 500, 300,
hwnd, NULL, GetModuleHandle(NULL), NULL);
//Add single treeview item
TVITEM tvi = {0};
TVINSERTSTRUCT tvins = {0};
HIMAGELIST himl = NULL;
himl = ImageList_Create(90, 90, 0, 1, 0);
int image = ImageList_Add(himl, g_hBmp, NULL);
SendMessage(treeview, TVM_SETIMAGELIST, (WPARAM) TVSIL_NORMAL, (LPARAM) himl);
tvi.mask = TVIF_TEXT | TVIF_IMAGE;
//Set Text
tvi.pszText = "Some Item";
tvi.cchTextMax = sizeof("Some Item") - 1;
tvi.iImage = image;
tvins.item = tvi;
tvins.hInsertAfter = TVI_FIRST;
SendMessage(treeview, TVM_INSERTITEM, 0, (LPARAM)(LPTVINSERTSTRUCT) &tvins);
And here is my entire code in case you want to copy it:
#include <windows.h>
#include <commctrl.h>
HBITMAP g_hBmp = NULL;
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_CREATE: {
//Load Image
g_hBmp = LoadImage(GetModuleHandle(NULL), "image.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_DEFAULTSIZE);
//Create Treeview
HWND treeview = CreateWindowEx(0, WC_TREEVIEW, NULL,
WS_VISIBLE | WS_CHILD | TVS_FULLROWSELECT,
250, 100, 500, 300,
hwnd, NULL, GetModuleHandle(NULL), NULL);
//Add single treeview item
TVITEM tvi = {0};
TVINSERTSTRUCT tvins = {0};
HIMAGELIST himl = NULL;
himl = ImageList_Create(90, 90, 0, 1, 0);
int image = ImageList_Add(himl, g_hBmp, NULL);
SendMessage(treeview, TVM_SETIMAGELIST, (WPARAM) TVSIL_NORMAL, (LPARAM) himl);
tvi.mask = TVIF_TEXT | TVIF_IMAGE;
//Set Text
tvi.pszText = "Some Item";
tvi.cchTextMax = sizeof("Some Item") - 1;
tvi.iImage = image;
tvins.item = tvi;
tvins.hInsertAfter = TVI_FIRST;
SendMessage(treeview, TVM_INSERTITEM, 0, (LPARAM)(LPTVINSERTSTRUCT) &tvins);
break;
}
case WM_PAINT: {
PAINTSTRUCT ps = {0};
//Setup
HDC hdc = BeginPaint(hwnd, &ps);
HDC hdcPaint = CreateCompatibleDC(hdc);
HBITMAP hBmpOld = (HBITMAP) SelectObject(hdcPaint, g_hBmp);
//Painting
BitBlt(hdc, 100, 100, 90, 90, hdcPaint, 0, 0, SRCCOPY);
//Cleanup
SelectObject(hdcPaint, hBmpOld);
DeleteDC(hdcPaint);
EndPaint(hwnd, &ps);
break;
}
case WM_DESTROY: {
DeleteObject(g_hBmp);
PostQuitMessage(0);
break;
}
default: return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) {
InitCommonControls();
HWND hwnd = NULL;
WNDCLASSEX wc = {0};
wc.cbSize = sizeof(WNDCLASSEX);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
wc.hInstance = hInstance;
wc.hbrBackground = (HBRUSH) COLOR_WINDOW;
wc.lpfnWndProc = WndProc;
wc.lpszClassName = "Parent Window";
wc.style = CS_VREDRAW | CS_HREDRAW;
RegisterClassEx(&wc);
hwnd = CreateWindowEx(0, wc.lpszClassName, "Render Window",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 1000, 1000 / 16 * 9,
NULL, NULL, hInstance, NULL);
ShowWindow(hwnd, nShowCmd);
UpdateWindow(hwnd);
MSG msg = {0};
while (GetMessage(&msg, NULL, 0, 0) > 0) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
As mentioned above by 'Swordfish', what I was missing was the proper flag when calling the ImageList_Create() function. As you can see in my call to ImageList_Create(90, 90, 0, 1, 0); I specify '0' as the third parameter (which represents the Image List Creation Flag). As stated in the documentation, the ILC_COLOR flag has a value of zero; when this flag is set it uses the 'default behavior' which is often ILC_COLOR4 (i.e. 4 bits per channel).
To fix this all I needed to do was simply call the function using the ILC_COLOR24 flag, indicating that my images have a 24-bit depth.
ImageList_Create(90, 90, ILC_COLOR24, 1, 0);
I have a listview of texts and have total control over it, works like a dream.
Except I don't get any LVN_GETINFOTIP notifications by WM_NOTIFY. I get every other notifications message but not LVN_GETINFOTIP.
I have spent some time been Googling and trying whatever I can find. Some sites say that from Vista it works different but not what different. I don’t care if it works before Win10 (can live with it) and not at all if it works before Win7.
I really wonder what prevents the LVN_GETINFOTIP messages?
switch (((LPNMHDR)lParam)->code)
{
case LVN_GETINFOTIP:
CreateListView(
0,
LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP | LVS_EX_LABELTIP,
0,
3 * TAB_HIGHT,
OwnWindowWidth,
OwnWindowHight - (OBJ_WINDOW_HIGHT + (3 * TAB_HIGHT)),
hWnd,
(HMENU)IDC_MAIN_LISTVIEW,
(HINSTANCE)GetWindowLongPtr(hWnd, GWLP_HINSTANCE));
static HWND CreateListView(
DWORD dwAddStyle,
DWORD dwAddExtendedListViewStyle,
int X,
int Y,
int nWidth,
int nHeight,
HWND hWndParent,
HMENU IdListWiew,
HINSTANCE hInst)
{
HWND hWndListView;
INITCOMMONCONTROLSEX icex;
memset(&icex, 0, sizeof(INITCOMMONCONTROLSEX));
// Ensure that the common control DLL is loaded.
icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
icex.dwICC = ICC_LISTVIEW_CLASSES;
InitCommonControlsEx(&icex);
// Create the list-view window in report view with label
// editing enabled.
hWndListView = CreateWindowEx(WS_EX_ACCEPTFILES, WC_LISTVIEW, L"",
WS_CHILD | LVS_REPORT | WS_VISIBLE | WS_BORDER | WM_NOTIFY | dwAddStyle,
X, Y, nWidth, nHeight,
hWndParent, IdListWiew, hInst, NULL);
if (hWndListView == NULL)
return NULL;
ListView_SetExtendedListViewStyle(hWndListView, dwAddExtendedListViewStyle);
return hWndListView;
}
Found the error myself!
The sample code for ListViews I once used hides the first column and so I can't get any TVN_GETINFOTIP because there is nothing to hover (Width of column 0 was 0). I managed to find this by reduction of code in a test program and read it real carefully. A bit embarrassed I asked. But this is coding life.
I have now a very compact sample code 160lines of a report ListView if it comes to use. (I rather this question to be removed).
#include <windows.h>
#include <CommCtrl.h>
#include <wchar.h>
#define IDC_MAIN_LISTVIEW 100
#define MAIN_LISTFIELDS 9
#define MAIN_LISTLINES 78
int iMainFieldsWidth[MAIN_LISTFIELDS] = { 50, 60, 78, 70, 100, 50, 50, 121, 112 };
WORD wMainFieldsAlign[MAIN_LISTFIELDS] = { LVCFMT_RIGHT,LVCFMT_LEFT, LVCFMT_LEFT,LVCFMT_LEFT,LVCFMT_LEFT, LVCFMT_RIGHT, LVCFMT_RIGHT, LVCFMT_LEFT, LVCFMT_LEFT };
WCHAR *pMainFieldsHeader[MAIN_LISTFIELDS] = { L"zero",L"one",L"Two",L"Three",L"Four",L"five",L"six",L"seven",L"eight" };
LRESULT WINAPI MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow)
{
CREATESTRUCT MainWindowCreateStruct;
WNDCLASS wc;
MSG msg;
HWND hWnd;
if (!hPrevInstance)
{
wc.lpszClassName = L"AppClass";
wc.lpfnWndProc = MainWndProc;
wc.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(hInstance, L"1");
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_ACTIVEBORDER + 1);
wc.lpszMenuName = L"AppMenu";
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
RegisterClass(&wc);
}
memset(&MainWindowCreateStruct, 0, sizeof(CREATESTRUCT));
hWnd = CreateWindowEx(WS_EX_ACCEPTFILES, L"AppClass",
L"LvTest",
WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
&MainWindowCreateStruct
);
ShowWindow(hWnd, nCmdShow);
// Main message loop:
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT WINAPI MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_CREATE:
{
// Create the list-view window in report view with label
// editing enabled.
HWND hLvWnd = CreateWindowEx(WS_EX_ACCEPTFILES, WC_LISTVIEW, L"",
WS_CHILD | LVS_REPORT | WS_VISIBLE | WS_BORDER,
0, 0, 1000, 500,
hWnd, (HMENU)IDC_MAIN_LISTVIEW, (HINSTANCE)GetWindowLongPtr(hWnd, GWLP_HINSTANCE), NULL);
if (hLvWnd == NULL)
return 0;
ListView_SetExtendedListViewStyle(hLvWnd, LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP | LVS_EX_LABELTIP);
ListView_DeleteAllItems(hLvWnd);
{
LVCOLUMN lvc;
int iCol = 0;
memset(&lvc, 0, sizeof(LVCOLUMN));
while (ListView_DeleteColumn(hLvWnd, 0)); // Nonvisual left column
// Initialize the LVCOLUMN structure.
// The mask specifies that the format, width, text, and
// subitem members of the structure are valid.
lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
// Add the columns.
for (iCol = 0; iCol < MAIN_LISTFIELDS; iCol++)
{
lvc.iSubItem = iCol;
lvc.pszText = pMainFieldsHeader[iCol];
lvc.cchTextMax = MAX_PATH;
lvc.iImage = 0;
lvc.iOrder = 0;
lvc.cx = iMainFieldsWidth[iCol]; // width of column in pixels
lvc.fmt = wMainFieldsAlign[iCol]; // alignment of column
if (ListView_InsertColumn(hLvWnd, lvc.iSubItem, &lvc) == -1)
return 0;
}
}
{
LVITEM lvI;
DWORD index = 0;
memset(&lvI, 0, sizeof(LVITEM));
// Some code to create the list-view control.
// Initialize LVITEM members that are common to all
// items.
lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM | LVIF_STATE | LVIF_INDENT;
lvI.state = 0;
lvI.stateMask = 0;
// Initialize LVITEM members that are different for each item.
for (index = 0; index < MAIN_LISTLINES; index++)
{
lvI.iItem = index;
lvI.iImage = 0; // Icon
lvI.iIndent = 0;
lvI.iSubItem = 0;
// lvI.lParam = (LPARAM) &rgPetInfo[index];
lvI.pszText = LPSTR_TEXTCALLBACK; // sends an
// LVN_GETDISPINFO
// message.
if (ListView_InsertItem(hLvWnd, &lvI) == -1)
return 0;
}
}
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_NOTIFY:
switch (((LPNMHDR)lParam)->code)
{
case LVN_GETINFOTIP:
if (lParam)
{ // This is only working it looks, or actually the LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP | LVS_EX_LABELTIP of the CreateWindowEx isn't, would be nice to have
LPNMLVGETINFOTIP pGetInfoTip = (LPNMLVGETINFOTIP)lParam;
wcscpy(pGetInfoTip->pszText, L"This is an InfoTip Text\nand it takes newlines", pGetInfoTip->cchTextMax);
}
break;
case LVN_GETDISPINFO:
if (lParam)
{
NMLVDISPINFO *plvdi = ((NMLVDISPINFO *)lParam);
if ((plvdi->hdr.hwndFrom == GetDlgItem(hWnd, IDC_MAIN_LISTVIEW)) && (plvdi->item.iSubItem<MAIN_LISTFIELDS) && plvdi->item.cchTextMax)
wcsncpy(plvdi->item.pszText, pMainFieldsHeader[plvdi->item.iSubItem], plvdi->item.cchTextMax);
}
break;
default:
break;
}
break;
default:
return(DefWindowProc(hWnd, msg, wParam, lParam));
}
return 0;
}
I am attempting to get a tooltip to appear over a Static control. I've followed the MSDN example almost word for word but the tooltip doesn't appear. Maybe I need to initialise a specific common control prior to creating a tooltip? Right now I initialise ICC_STANDARD_CLASSES and ICC_COOL_CLASSES.
Any idea why the tooltip doesn't appear?
case WM_CREATE:
{
INITCOMMONCONTROLSEX iccx;
iccx.dwSize = sizeof(INITCOMMONCONTROLSEX);
iccx.dwICC = ICC_STANDARD_CLASSES | ICC_COOL_CLASSES;
InitCommonControlsEx(&iccx);
HWND hwndTool = CreateWindowEx(0, _T("Static"), _T("Abc"), WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
10, 10, 100, 100, hWnd, (HMENU)50001, hInst, NULL);
HWND hwndTip = CreateWindowEx(NULL, TOOLTIPS_CLASS, NULL,
WS_POPUP | TTS_ALWAYSTIP | TTS_BALLOON,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
hWnd, NULL,
hInst, NULL);
// Associate the tooltip with the tool.
LPTSTR pszText = _T("Def");
TOOLINFO toolInfo = { 0 };
toolInfo.cbSize = sizeof(toolInfo);
toolInfo.hwnd = hWnd;
toolInfo.uFlags = TTF_IDISHWND | TTF_SUBCLASS;
toolInfo.uId = (UINT_PTR)hwndTool;
toolInfo.lpszText = pszText;
output(_T("Is null: %d\n"), hwndTip == NULL); // output = Is null: 0
output(_T("Send res: %d\n"), SendMessage(hwndTip, TTM_ADDTOOL, 0, (LPARAM)&toolInfo)); // output = Send res: 0
}
break;
I'm trying to create a scrollable child-window within a window. The child-window is supposed to have scrollbars; the scrollbars appear but are totally unresponsive. Window creation code:
// "mainwindow" is the handle of the main application window.
HWND wnd = CreateWindow(WC_STATIC, NULL, WS_CHILD | WS_VISIBLE | WS_VSCROLL,
10, 100, 300, 300, mainwindow, NULL, GetModuleHandle(0), 0);
SCROLLINFO si = { 0 };
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_ALL;
si.nMax = 800;
SetScrollInfo(g_wnd, SB_VERT, &si, true);
I've set a custom WNDPROC for the new child-window, but no scrolling-messages arrive. I've found numerous examples on the internet, but none of them either work or are about using scrollbars in child-windows.
As Hans Passant pointed out, a scrollable child-window needs its own windows class.
Example code:
HWND create_scroll_window(HWND parent)
{
WNDCLASSEX wcex = { 0 };
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.hInstance = GetModuleHandle(0);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszClassName = TEXT("MyScrollWinClass");
if (!RegisterClassEx(&wcex)) return 0;
HWND hWnd = CreateWindow(_T("MyScrollWinClass"), _T(""), WS_CHILD | WS_BORDER | WS_VISIBLE | WS_VSCROLL, 20, 20,
300, 300, parent, NULL, wcex.hInstance, NULL);
return hWnd;
}