I am using NM_CUSTOMDRAW for changing the color of Tree View item & its child on some conditions.I want to get subitems control individually but dwDrawStage never get this case CDDS_ITEMPREPAINT| CDDS_SUBITEM my code snippet is here:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
int j;
HWND hwndTree;
TVITEM tv;
TVHITTESTINFO hti;
char achBuf[100];
switch (message)
{
case WM_CREATE:
RECT rcClient; // dimensions of client area
// handle to tree-view control
// Ensure that the common control DLL is loaded.
InitCommonControls();
// Get the dimensions of the parent window's client area, and create
// the tree-view control.
GetClientRect(hWnd, &rcClient);
hwndTV = CreateWindowEx(0,
WC_TREEVIEW,
TEXT("Tree View"),
WS_VISIBLE | WS_CHILD | WS_BORDER | TVS_HASLINES,
0,
0,
rcClient.right,
rcClient.bottom,
hWnd,
(HMENU)ID_TREEVIEW,
hInst,
NULL);
// Initialize the image list, and add items to the control.
// InitTreeViewImageLists and InitTreeViewItems are application-
// defined functions, shown later.
if (!InitTreeViewItems(hwndTV))
{
DestroyWindow(hwndTV);
return FALSE;
}
break;
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
case IDC_MAIN_BUTTON:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
//TreeView_EnsureVisible(hwndTV,hti);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code here...
EndPaint(hWnd, &ps);
break;
case WM_NOTIFY:
{
LPNMTREEVIEW pnm = (LPNMTREEVIEW)lParam;
if (pnm->hdr.code == NM_CUSTOMDRAW)
{
//LPNMLVCUSTOMDRAW lplvcd = (LPNMLVCUSTOMDRAW)lParam;
//TreeView_GetItem(
//pnm->iItem
LPNMTVCUSTOMDRAW lplvcd = (LPNMTVCUSTOMDRAW)lParam;
//pnm->iItem
//TreeView_GetItem(hWnd,pnm->iItem);
switch (lplvcd->nmcd.dwDrawStage)
{
case CDDS_PREPAINT :
return CDRF_NOTIFYITEMDRAW;
break;
case CDDS_ITEMPREPAINT:
if(found_unMatched(lplvcd->nmcd.lItemlParam))
{
hwndTree = GetDlgItem(hWnd,ID_TREEVIEW);
lplvcd->clrText = RGB(0, 255,0);
ZeroMemory(&tv, sizeof(TVITEM));
tv.hItem=(HTREEITEM)lplvcd->nmcd.dwItemSpec;
tv.mask=TVIF_TEXT|TVIF_HANDLE;
tv.cchTextMax=100;
tv.pszText=(LPWSTR)achBuf;
if(TreeView_GetItem(hwndTree,&tv))
{
achBuf;
}
hChild =(HTREEITEM)TreeView_GetChild(hwndTree,(HTREEITEM)lplvcd->nmcd.dwItemSpec);
hSibling=(HTREEITEM)TreeView_GetNextSibling(hwndTree,hChild);
}
return CDRF_NOTIFYSUBITEMDRAW;
break;
case CDDS_POSTPAINT:
return CDRF_DODEFAULT;
break;
case CDDS_ITEMPOSTPAINT| CDDS_SUBITEM :
hwndTree = GetDlgItem(hWnd,ID_TREEVIEW);
ZeroMemory(&tv, sizeof(TVITEM));
tv.hItem=(HTREEITEM)lplvcd->nmcd.dwItemSpec;
tv.mask=TVIF_TEXT|TVIF_HANDLE;
tv.cchTextMax=100;
tv.pszText=(LPWSTR)achBuf;
if(TreeView_GetItem(hwndTree,&tv))
{
achBuf;
}
if((HTREEITEM)lplvcd->nmcd.dwItemSpec==hSibling)
{
lplvcd->clrText = RGB(176, 0,0);
}
return CDRF_NEWFONT;
break;
case CDDS_ITEMPOSTPAINT:
double_click=1;
break;
}
}}break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
this will color my parent node but child nodes(subitem) remained default(black) and return CDRF_NOTIFYSUBITEMDRAW didnt work. Please help!!!
Related
I've created a basic GUI using the windows library and I've come across a problem. The GUI builds and performs great but the issue is the button functions execute before the actual window loads. I wanted the button to execute the desired function on press rather than on load. Below is the code where I think the problem lies.
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;
TCHAR greeting[] = _T("T3chSpl01ts Version - 1.0");
switch (message)
{
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
TextOut(hdc,
5, 5,
greeting, _tcslen(greeting));
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
break;
case WM_CREATE:
{
Button = CreateWindow("Button", "Inject",
WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, 20, 20, 100, 30,
hWnd, (HMENU)ID_INJECT, GetModuleHandle(NULL), NULL);
}
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case ID_INJECT:
{
::test();
break;
}
}
}
}
return 0;
}
Your WM_CREATE handler is missing a break statement, so code flow "falls through" into your WM_COMMAND handler when the window is created.
I try to change the default color of the button in my UI.
Here is my CallBacl function
LRESULT CALLBACK WindowProcedure(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{
switch (msg)
{
case WM_COMMAND:
switch (wp)
{
case FILE_MENU_NEW:
MessageBeep(MB_ICONINFORMATION);
break;
}
break;
case WM_CREATE:
AddMenus(hWnd);
AddControls(hWnd);
break;
case WM_CTLCOLOREDIT:
{
if (hEdit == (HWND)lp)
{
HDC hdcEdit = (HDC)wp;
SetTextColor(hdcEdit, RGB(255, 255, 255));
SetBkColor(hdcEdit, RGB(48, 56, 66));
return (INT_PTR)hBrush1;
}
}
case WM_CTLCOLORBTN:
{
if (hButton_ok == (HWND)lp)
{
HDC hdcButton_ok = (HDC)wp;
SetTextColor(hdcButton_ok, RGB(255, 255, 255));
SetBkColor(hdcButton_ok, RGB(87, 102, 110));
return (INT_PTR)hBrush;
}
}
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProcW(hWnd, msg, wp, lp);
}
}
Now case WM_CTLCOLOREDIT changes the background color of my text input dialog correctly,
Why is then WM_CTLCOLORBTN fails?
How can I handle individual items being clicked in a MS Windows treeview ?
My windows proc has :
LRESULT CALLBACK WndProcTreeView(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
PAINTSTRUCT paintStruct;
HDC hDC;
switch (message)
{
case WM_PAINT:
{
hDC = BeginPaint(hwnd, &paintStruct);
EndPaint(hwnd, &paintStruct);
break;
}
case WM_NOTIFY:
{
switch (reinterpret_cast<LPNMHDR>(lParam)->code) {
case NM_CLICK:
MessageBox(nullptr, "click", "click", MB_OK);
}
}
default:
{
return DefWindowProc(hwnd, message, wParam, lParam);
break;
}
}
Which outputs a message box when I click on the treeview control. How can I handle individual elements ?
Example of a treeview item being added to the list :
std::string vTxt = std::string("Vertex count : ") + std::to_string(mesh.v.size());
tvinsert.hInsertAfter = mesh_items[mesh_items.size() - 1];
tvinsert.hParent = mesh_items[mesh_items.size() - 1];
tvinsert.item.mask = TVIF_TEXT;
tvinsert.item.pszText = (LPSTR)vTxt.c_str();
mesh_items_sub.push_back((HTREEITEM)SendMessage(hwnd, TVM_INSERTITEM, 0, (LPARAM)&tvinsert));
I have seen using SendDlgItemMessage instead (which gives an ID as LOWORD(wParam) inside the windows proc) but it requires IDs set in a resource file - which I don't know how to create.
Two things I needed for my code to work : first give each item a lparam value and changing TVIF_TEXT as item's mask to TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM (TVIF_PARAM allowing for an lparam to be passed to the window proc thus identifying the controller).
Working code excerpt :
TV_INSERTSTRUCT tvinsert;
// ...
tvinsert.hInsertAfter = Root;
tvinsert.hParent = Root;
tvinsert.item.pszText = std::string("some text...").c_str();
tvinsert.item.lParam = ID_SOME_ID; // << #defined constant or plain int
tvinsert.item.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM;
root_sub.push_back((HTREEITEM)SendMessage(hwnd, TVM_INSERTITEM, 0, (LPARAM)&tvinsert));
// window proc code below
LRESULT CALLBACK WndProcTreeView(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
PAINTSTRUCT paintStruct;
HDC hDC;
switch (message)
{
case WM_PAINT:
{
hDC = BeginPaint(hwnd, &paintStruct);
EndPaint(hwnd, &paintStruct);
break;
}
case WM_NOTIFY:
{
LPNM_TREEVIEW pntv = (LPNM_TREEVIEW)lParam;
if (pntv->hdr.code == TVN_SELCHANGED) {
switch (pntv->itemNew.lParam) {
case ID_SOME_ID:
std::cout << "ID_SOME_ID selected caught here..." << std::endl;
break;
}
}
}
default:
{
return DefWindowProc(hwnd, message, wParam, lParam);
break;
}
}
return 0;
}
Good explanation/example here (in french) http://chgi.developpez.com/windows/treeview/
I want to change label background color within a function, I tried this code but nothing changed after calling changecolor function
HWND hWndLabel;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
hWndLabel = CreateWindowEx(WS_EX_TRANSPARENT,
L"STATIC", L"", WS_CHILD | WS_VISIBLE | SS_LEFT | WS_SYSMENU,
75, 75, 70, 70, hWnd, (HMENU)labelId, hInst, NULL);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_COMMAND: // all events are handled here
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
break;
}
return 0;
}
DWORD WINAPI changecolor(){
HDC hdc = GetDC(hWndLabel); // get context
SetBkColor(hdc, RGB(0, 0, 230)); // Code Copied from the above answer by cpx.
return 0;
}
I read that Static controls send their parent a WM_CTLCOLORSTATIC message just before they paint themselves. code is implemented within CALLBACK function, but where this code is called (changing color)?, how can I call SetTextColor within a function
code example :
case WM_CTLCOLORSTATIC:
if (the_button_was_clicked) {
HDC hdc = reinterpret_cast<HDC>(wParam);
SetTextColor(hdc, COLORREF(0xFF, 0x00, 0x00));
}
return ::GetSysColorBrush(COLOR_WINDOW); // example color, adjust for your circumstance
Try something more like this:
HWND hWndLabel;
HBRUSH hBrushLabel;
COLORREF clrLabelText;
COLORREF clrLabelBkGnd;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
hWndLabel = CreateWindowEx(0, L"STATIC", L"", WS_CHILD | WS_VISIBLE | SS_LEFT,
75, 75, 70, 70, hWnd, (HMENU)labelId, hInst, NULL);
hBrushLabel = NULL;
clrLabelText = GetSysColor(COLOR_WINDOWTEXT);
clrLabelBkGnd = GetSysColor(COLOR_WINDOW);
break;
case WM_DESTROY:
if (hBrushLabel) DeleteObject(hBrushLabel);
PostQuitMessage(0);
break;
case WM_CTLCOLORSTATIC: {
HDC hdc = reinterpret_cast<HDC>(wParam);
SetTextColor(hdc, clrLabelText);
SetBkColor(hdc, clrLabelBkGnd);
if (!hBrushLabel) hBrushLabel = CreateSolidBrush(clrLabelBkGnd);
return reinterpret_cast<LRESULT>(hBrushLabel);
}
case WM_COMMAND: // all events are handled here
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
break;
}
return 0;
}
DWORD WINAPI changecolor()
{
if (hBrushLabel) {
DeleteObject(hBrushLabel);
hBrushLabel = NULL;
}
clrLabelText = RGB(0xFF, 0x00, 0x00);
clrLabelBkGnd = RGB(0, 0, 230);
InvalidateRect(hWndLabel, NULL, TRUE);
return 0;
}
There is a similar example in the WM_CTLCOLORSTATIC documentation.
The following C++ example shows how to set the text foreground and background colors of a static control in response to the WM_CTLCOLORSTATIC message. The hbrBkgnd variable is a static HBRUSH variable that is initialized to NULL, and stores the background brush between calls to WM_CTLCOLORSTATIC. The brush must be destroyed by a call to the DeleteObject function when it is no longer needed, typically when the associated dialog box is destroyed.
case WM_CTLCOLORSTATIC:
{
HDC hdcStatic = (HDC) wParam;
SetTextColor(hdcStatic, RGB(255,255,255));
SetBkColor(hdcStatic, RGB(0,0,0));
if (hbrBkgnd == NULL)
{
hbrBkgnd = CreateSolidBrush(RGB(0,0,0));
}
return (INT_PTR)hbrBkgnd;
}
I'm trying to print a text in the WM_COMMAND case, because I need a text to be printed after a button was pushed.
Here's the code I have:
switch(msg)
{
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
case WM_COMMAND:
switch (LOWORD(wParam))
{
case 1:
PAINTSTRUCT ps;
HDC hDC;
hDC = BeginPaint(hwnd, &ps);
{
TextOut(hDC, 10, 50, "hello", 5);
}
EndPaint(hwnd, &ps);
UpdateWindow(hwnd);
break;
}
break;
}
Sadly it doesn't print anything.
edit:
I can use TextOut() during WM_COMMAND that way:
HDC hDC;
hDC = GetDC(hwnd);
TextOut(hDC, 10, ypos, "Warnings: ", 10);
UpdateWindow(hwnd);
It's best to structure your program so that all painting is performed in WM_PAINT.
so you could change it to be something like:
LRESULT CALLBACK WndProc(/*blah blah blah*/)
{
static wchar_t my_text[] = L"hello";
static BOOL show_btn_text = FALSE;
HDC dc;
PAINTSTRUCT ps;
switch (msg) {
case WM_COMMAND:
switch (LOWORD(wParam)) {
case 1:
show_btn_text = !show_btn_text;
InvalidateRect(hwnd, NULL, TRUE); //tells windows that the whole client area needs to be repainted
break;
}
return 0;
case WM_PAINT:
dc = BeginPaint(hwnd, &ps);
if (show_btn_text) {
TextOut(dc, 0, 0, my_text, wcslen(my_text));
}
EndPaint(hwnd, &ps);
return 0;
/*the rest of the window procedure
}
}
For painting inside of WM_PAINT: BeginPaint/EndPaint.
For painting outside of WM_PAINT: GetDC/ReleaseDC.