Trouble
Look at the picture,when I scroll the vertical scrollbar, there are some flicker. I guess there are some other messages should be handled which I missed. WM_NCPAINT has been handled by my own procedure. The flicker seems like the original scrollbar drawing has been trigger which I don't know where.
What I have done
I redraw the SysListView32 control, both client zone and the non-client zone. I redraw the scrollbar in the non-client zone as you saw in the picture. I use memory DC for the double buffer drawing , hoping no flicker problems, while not succeed.
I handle several messages as code below:
LRESULT CALLBACK LVCProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
pListViewStyle ls=ListView_GetSettings(hwnd);// this structure store some extra info. for my owner-drawing.
if(!ls) return 0;
switch(message){
case WM_NCCALCSIZE: {
return LVC_NCCalcSize(hwnd,wParam,lParam); // I adjust the scrollbar size
} break;
case WM_NCACTIVATE:
case WM_NCPAINT: {
LVC_NCDrawScrollBar(hwnd,SB_HORZ); // This function mainly implement the drawing for the scrollbar.
LVC_NCDrawScrollBar(hwnd,SB_VERT);
return 0;
} break;
case WM_NCMOUSEMOVE: return 1;
case WM_ERASEBKGND: {
return 1;
} break;
case WM_MOUSEWHEEL: {
// support the scrolling for the listview when you scrolling the mouse-wheel.
int wheel_delta=GET_WHEEL_DELTA_WPARAM(wParam);
int scroll_pixls=((double)wheel_delta/10)*5*-1;
SendMessage(hwnd,LVM_SCROLL,(WPARAM)0,(LPARAM)scroll_pixls);
return 1;
} break;
case WM_PAINT: {
// totally redraw the content of the control
LVC_Paint(hwnd,wParam,lParam);
return 0;
} break;
case WM_NCLBUTTONUP:
//WM_NCLBUTTONDON / WM_MOUSEMOVE / WM_NCLBUTTONUP ,
//these three messages are handled when you press the thumb block and scrolling the window.
ReleaseCapture();
break;
case WM_NCLBUTTONDOWN: {
return LVC_ScrollBefore(hwnd,wParam,lParam);
} break;
case WM_MOUSEMOVE: {
if(GetCapture()==hwnd) {
LVC_Scrolling(hwnd,wParam,lParam);
return 1;
}
} break;
case WM_SIZE: {
// update the nPage of SCROLLINFO for the control
LVC_Size(hwnd,wParam,lParam);
return 1;
} break;
case LVM_SCROLL: {
// scroll the content and update the invalidate rect.
LVC_Scroll(hwnd,wParam,lParam);
return 1;
} break;
case WM_NCHITTEST: {
// I change the return value for the scrollbar areas , which I abolish the two arrows area.
return LVC_HitTest(hwnd,wParam,lParam);
}
case WM_LBUTTONDOWN:
// when you click the item of the listview, you change the selected state for the item.
LVC_ModifySelState(hwnd,wParam,lParam);
return 0;
} break;
// this part has been canceled,
//I am not using the interface of owner-drawing each item provided by MS.
//I redraw directly by rewrite the WM_PAINT message.
/*
case WMYU_DRAWLISTVIEWITEM: {
LVC_DrawItem(hwnd,wParam,lParam);
return TRUE;
} break;
case WMYU_MEASURELISTVIEWITEM: {
LPMEASUREITEMSTRUCT lpmis=(LPMEASUREITEMSTRUCT)lParam;
lpmis->itemHeight=ls->content_height;
} break;
*/
case WM_NCDESTROY: {
// release the extra resources before destroy the control.
WNDPROC pre_proc=ls->pre_proc;
ListView_ClearSettings(hwnd);
if(pre_proc) return CallWindowProc(pre_proc,hwnd,message,wParam,lParam);
} break;
}
// other messages do not change.
return CallWindowProc(ls->pre_proc,hwnd,message,wParam,lParam);
}
/*WM_PAINT: redraw the whole content*/
int LVC_Paint(HWND hwnd,WPARAM wParam,LPARAM lParam)
{
int idx_item=0;
int page=0;
int x_offset=0,y_offset=0;
char item_text[256]="";//item text
//control extra info.
pListViewStyle ls=ListView_GetSettings(hwnd);
if(!ls) return -1;
//the sub-control head for the columns.
HWND head=ListView_GetHeader(hwnd);
int itm_count=ListView_GetItemCount(hwnd);
int col_count=Header_GetItemCount(head);
int col_start=0,col_stop=col_count-1;
RECT rcHead={0},rcClient;
int head_height=0;
GetWindowRect(head,&rcHead);
head_height=rcHead.bottom-rcHead.top;
GetClientRect(hwnd,&rcClient);
//axis x,y offset . calculated by the SCROLLINFO provided by the control
SCROLLINFO si={0};
si.cbSize=sizeof(si);
si.fMask=SIF_ALL;
UINT style=GetWindowLongPtr(hwnd,GWL_STYLE);
BOOL HasVScroll=((style&WS_VSCROLL)==WS_VSCROLL);
BOOL HasHScroll=((style&WS_HSCROLL)==WS_HSCROLL);
if(HasVScroll) {
GetScrollInfo(hwnd,SB_VERT,&si);
idx_item=si.nPos;
page=si.nPage;
}
else page=ListView_GetItemCount(hwnd);
if(HasHScroll) {
GetScrollInfo(hwnd,SB_HORZ,&si);
x_offset=si.nPos;
}
y_offset=head_height;
//prepare for painting
PAINTSTRUCT ps;
HDC hdc=BeginPaint(hwnd,&ps);
int cx=ps.rcPaint.right-ps.rcPaint.left;
int cy=ps.rcPaint.bottom-ps.rcPaint.top;
HDC memdc=CreateCompatibleDC(hdc);
HBITMAP bmp=CreateCompatibleBitmap(hdc,cx,cy);
HBITMAP pre_bmp=(HBITMAP)SelectObject(memdc,bmp);
HFONT pre_font=(HFONT)SelectObject(memdc,(HFONT)SendMessage(hwnd,WM_GETFONT,0,0));
SetBkMode(memdc,TRANSPARENT);
SetTextColor(memdc,RGB(255,255,255));
HPEN pen=CreatePen(PS_SOLID,1,RGB(40,46,44));
HPEN pre_pen=(HPEN)SelectObject(memdc,pen);
//memory rectangle for Mem DC
RECT rcMem;
CopyRect(&rcMem,&ps.rcPaint);
//offset the coordinate
POINT pt_org;
OffsetViewportOrgEx(memdc,-rcMem.left,-rcMem.top,&pt_org);
RECT rcItem;//item rectangle
COLORREF rgb_curr;
BOOL col_trigger=FALSE;//column painting stop flags.
int rcTop=0,rcBottom=0;
//background
HBRUSH bkbrush=CreateSolidBrush(RGB(20,20,20));
FillRect(memdc,&rcMem,bkbrush);
DeleteObject(bkbrush);
//update the rectangle specfied by the PAINTSTRUCT
for(int index=0;index<=page&&(index+idx_item<itm_count);index++) {
//calculate whether each visible item in current view is in invalid rect
rcTop=index*ls->content_height+y_offset;
rcBottom=rcTop+ls->content_height;
//Item ID
int itemID=index+idx_item;
//if this item in rectangle specified by PAINTSTRUCT, redraw it.
if(rcTop>=ps.rcPaint.top&&rcTop<=ps.rcPaint.bottom) {
//state
UINT state=ListView_GetItemState(hwnd,itemID,LVIS_SELECTED|LVIS_FOCUSED);
//even odd different color
if(itemID%2==0) rgb_curr=ls->rgb_even;
else rgb_curr=ls->rgb_odd;
if(state&LVIS_SELECTED==LVIS_SELECTED) rgb_curr=ls->rgb_sel;
if(state&LVIS_FOCUSED==LVIS_FOCUSED) rgb_curr=ls->rgb_focus;
HBRUSH brush=CreateSolidBrush(rgb_curr);
HBRUSH pre_brush=(HBRUSH)SelectObject(memdc,brush);
//draw item and subitem.
for(int idx_col=col_start;idx_col<=col_stop;idx_col++) {
ListView_GetSubItemRect(hwnd,itemID,idx_col, LVIR_LABEL,&rcItem);
//x,y axis offset
OffsetRect(&rcItem,-x_offset,-idx_item*ls->content_height);
//if current item or subitem not in update area, no need to hanle it
if(ps.rcPaint.left>rcItem.right) continue;
else if(!col_trigger){
col_start=idx_col;
col_trigger=TRUE;
}
if(ps.rcPaint.right<rcItem.left) {
col_stop=idx_col-1;
break;
}
//while painting
Rectangle(memdc,rcItem.left-1,rcItem.top-1,rcItem.right,rcItem.bottom);
memset(item_text,0x00,sizeof(item_text));
ListView_GetItemText(hwnd,itemID,idx_col,item_text,sizeof(item_text));
InflateRect(&rcItem,-5,-3);
DrawText(memdc,item_text,-1,&rcItem,DT_SINGLELINE|DT_VCENTER|DT_END_ELLIPSIS);
}
DeleteObject(brush);
}
}
//paste
BitBlt(hdc,ps.rcPaint.left,ps.rcPaint.top,cx,cy,
memdc,rcMem.left,rcMem.top,SRCCOPY);
//reset
SetViewportOrgEx(memdc,pt_org.x,pt_org.y,NULL);
//resource reset and release
SelectObject(memdc,pre_font);
DeleteObject(SelectObject(memdc,pre_pen));
DeleteObject(SelectObject(memdc,pre_bmp));
DeleteDC(memdc);
//paint finished
EndPaint(hwnd,&ps);
return 0;
}
/*Paint the scrollbar*/
int LVC_NCDrawScrollBar(HWND hwnd,UINT scrolltype)
{
RECT rc;
RECT rcThumb;
HDC hdc=GetWindowDC(hwnd);
UINT style=(UINT)GetWindowLongPtr(hwnd,GWL_STYLE);
//use memdc , double buffering. still flicker
if(scrolltype==SB_VERT) {
if(LVC_GetZoneRect(hwnd,ZVSCROLL,&rc,TRUE)==0&&
LVC_GetZoneRect(hwnd,ZVSTHUMB,&rcThumb,TRUE)==0) {
int cx=rc.right-rc.left,cy=rc.bottom-rc.top;
if((style&WS_HSCROLL)) cy+=SCROLLBAR_PIXLS;
HDC memdc=CreateCompatibleDC(hdc);
HBITMAP bmp=CreateCompatibleBitmap(hdc,cx,cy);
HBITMAP pre_bmp=(HBITMAP)SelectObject(memdc,bmp);
RECT rcMem;
CopyRect(&rcMem,&rc);
OffsetRect(&rcMem,-rcMem.left,-rcMem.top);
HBRUSH brush=CreateSolidBrush(RGB(15,15,15));
FillRect(memdc,&rcMem,brush);
DeleteObject(brush);
OffsetRect(&rcThumb,-rc.left-1,-rc.top);
InflateRect(&rcThumb,-1,0);
Graphics graphic(memdc);
GraphicsPath path;
LinearGradientBrush pbrush(Rect(rcThumb.left,rcThumb.top,rcThumb.right-rcThumb.left,rcThumb.bottom-rcThumb.top),
Color(255,50,50,50),
Color(255,20,20,20),
LinearGradientModeHorizontal);
graphic.SetSmoothingMode(SmoothingModeHighQuality);
path.AddArc(rcThumb.left,rcThumb.top,SCROLLBAR_PIXLS,SCROLLBAR_PIXLS,180,180);
path.AddArc(rcThumb.left,rcThumb.bottom-SCROLLBAR_PIXLS,SCROLLBAR_PIXLS,SCROLLBAR_PIXLS,0,180);
graphic.FillPath(&pbrush,&path);
BitBlt(hdc,rc.left,rc.top,cx,cy,memdc,0,0,SRCCOPY);
DeleteObject(SelectObject(memdc,pre_bmp));
DeleteDC(memdc);
}
}
else if(scrolltype==SB_HORZ) {
if(LVC_GetZoneRect(hwnd,ZHSCROLL,&rc,TRUE)==0&&
LVC_GetZoneRect(hwnd,ZHSTHUMB,&rcThumb,TRUE)==0) {
int cx=rc.right-rc.left,cy=rc.bottom-rc.top;
HDC memdc=CreateCompatibleDC(hdc);
HBITMAP bmp=CreateCompatibleBitmap(hdc,cx,cy);
HBITMAP pre_bmp=(HBITMAP)SelectObject(memdc,bmp);
RECT rcMem;
CopyRect(&rcMem,&rc);
OffsetRect(&rcMem,-rcMem.left,-rcMem.top);
HBRUSH brush=CreateSolidBrush(RGB(15,15,15));
FillRect(memdc,&rcMem,brush);
DeleteObject(brush);
OffsetRect(&rcThumb,-rc.left,-rc.top-1);
InflateRect(&rcThumb,0,-1);
Graphics graphic(memdc);
GraphicsPath path;
LinearGradientBrush pbrush(Rect(rcThumb.left,rcThumb.top,rcThumb.right-rcThumb.left,rcThumb.bottom-rcThumb.top),
Color(255,50,50,50),
Color(255,20,20,20),
LinearGradientModeVertical);
graphic.SetSmoothingMode(SmoothingModeHighQuality);
path.AddArc(rcThumb.left,rcThumb.top,SCROLLBAR_PIXLS,SCROLLBAR_PIXLS,90,180);
path.AddArc(rcThumb.right-SCROLLBAR_PIXLS,rcThumb.top,SCROLLBAR_PIXLS,SCROLLBAR_PIXLS,-90,180);
graphic.FillPath(&pbrush,&path);
BitBlt(hdc,rc.left,rc.top,cx,cy,memdc,0,0,SRCCOPY);
DeleteObject(SelectObject(memdc,pre_bmp));
DeleteDC(memdc);
}
}
ReleaseDC(hwnd,hdc);
return 0;
}
/* LVM_SCROLL*/
int LVC_Scroll(HWND hwnd,WPARAM wParam,LPARAM lParam)
{
HWND head=ListView_GetHeader(hwnd);
if(!head) return 0;
pListViewStyle ls=ListView_GetSettings(hwnd);
if(!ls) return 0;
int hscroll_pixls=(int)wParam;
int vscroll_pixls=(int)lParam;
RECT rc,rcScroll,rcHead,rcInvalid;
GetClientRect(hwnd,&rc);
CopyRect(&rcScroll,&rc);
GetWindowRect(head,&rcHead);
rcScroll.top=rcHead.bottom-rcHead.top;
CopyRect(&rcInvalid,&rcScroll);
SCROLLINFO si={0};
si.cbSize=sizeof(SCROLLINFO);
si.fMask=SIF_ALL;
if(hscroll_pixls!=0) {
GetScrollInfo(hwnd,SB_HORZ,&si);
int pre_pos=si.nPos;
si.fMask=SIF_POS;
si.nPos=pre_pos+hscroll_pixls;
if(si.nPos+si.nPage>=si.nMax) si.nPos=si.nMax-si.nPage+1;
else if(si.nPos<=si.nMin) si.nPos=si.nMin;
SetScrollInfo(hwnd,SB_HORZ,&si,TRUE);
InvalidateRect(head,NULL,TRUE);
if(hscroll_pixls>0) rcInvalid.left=rcInvalid.right-hscroll_pixls-1;
else rcInvalid.right=rcInvalid.left-hscroll_pixls+1;
ScrollWindow(hwnd,-hscroll_pixls,0,NULL,&rcScroll);
LVC_NCDrawScrollBar(hwnd,SB_HORZ);
InvalidateRect(hwnd,&rcInvalid,TRUE);
}
if(vscroll_pixls!=0) {
GetScrollInfo(hwnd,SB_VERT,&si);
int pre_pos=si.nPos;
int page=si.nPage;
si.fMask=SIF_POS;
int scroll_pos=vscroll_pixls/ls->content_height;
//recalculate the nPos.
si.nPos=pre_pos+scroll_pos;
if(si.nPos+si.nPage>=si.nMax) si.nPos=si.nMax-si.nPage+1;
else if(si.nPos<=si.nMin) si.nPos=si.nMin;
vscroll_pixls=(si.nPos-pre_pos)*ls->content_height;
SetScrollInfo(hwnd,SB_VERT,&si,TRUE);
if(vscroll_pixls>0)
rcInvalid.bottom=rcInvalid.top+vscroll_pixls;
else
rcInvalid.top=rcInvalid.top+(page+scroll_pos)*ls->content_height-1;
if(rcInvalid.top<rcScroll.top) rcInvalid.top=rcScroll.top;
if(rcInvalid.bottom>rcScroll.bottom) rcInvalid.bottom=rcScroll.bottom;
ScrollWindow(hwnd,0,-vscroll_pixls,NULL,&rcScroll);
InvalidateRect(hwnd,&rcInvalid,TRUE);
LVC_NCDrawScrollBar(hwnd,SB_VERT);
}
return 0;
}
int LVC_ScrollBefore(HWND hwnd,WPARAM wParam,LPARAM lParam)
{
UINT hit=wParam;
POINT pt={GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam)};
pListViewStyle ls=ListView_GetSettings(hwnd);
if(!ls) return -1;
if(hit==HTHSCROLL) {
RECT rc_hs;
if(LVC_GetZoneRect(hwnd,ZHSTHUMB,&rc_hs,FALSE)!=0) return -1;
if(!PtInRect(&rc_hs,pt)) return -1;
ScreenToClient(hwnd,&pt);
ls->drag_pt.x=pt.x;
ls->drag_pt.y=-1;
SCROLLINFO si={0};
si.cbSize=sizeof(si);
si.fMask=SIF_POS;
GetScrollInfo(hwnd,SB_HORZ,&si);
ls->drag_pos.x=si.nPos;
ls->drag_pos.y=-1;
SetCapture(hwnd);
return 0;
}
else if(hit==HTVSCROLL) {
RECT rc_vs;
if(LVC_GetZoneRect(hwnd,ZVSTHUMB,&rc_vs,FALSE)!=0) return -1;
if(!PtInRect(&rc_vs,pt)) return -1;
ScreenToClient(hwnd,&pt);
ls->drag_pt.y=pt.y;
ls->drag_pt.x=-1;
SCROLLINFO si={0};
si.cbSize=sizeof(si);
si.fMask=SIF_POS;
GetScrollInfo(hwnd,SB_VERT,&si);
ls->drag_pos.y=si.nPos;
ls->drag_pos.x=-1;
SetCapture(hwnd);
return 0;
}
else {
return CallWindowProc(ls->pre_proc,hwnd,WM_NCLBUTTONDOWN,wParam,lParam);
}
}
int LVC_Scrolling(HWND hwnd,WPARAM wParam,LPARAM lParam)
{
POINT pt={GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam)};
pListViewStyle ls=ListView_GetSettings(hwnd);
if(!ls) return -1;
if(GetCapture()!=hwnd) return -1;
if(ls->drag_pos.x!=-1) { // HORZ
RECT rc_hs,rc_thumb;
if(LVC_GetZoneRect(hwnd,ZHSCROLL,&rc_hs,TRUE)!=0) return -1;
if(LVC_GetZoneRect(hwnd,ZHSTHUMB,&rc_thumb,TRUE)!=0) return -1;
SCROLLINFO si;
si.cbSize=sizeof(si);
si.fMask=SIF_ALL;
GetScrollInfo(hwnd,SB_HORZ,&si);
int pre_pos=si.nPos;
si.nPos=(int)ls->drag_pos.x+(int)(si.nMax-si.nMin+1-si.nPage)*1.0*(int)(pt.x-ls->drag_pt.x)/((rc_hs.right-rc_hs.left)-(rc_thumb.right-rc_thumb.left));
if(si.nPos==ls->drag_pos.x) return -1;
if((int)si.nPos>(int)(si.nMax-si.nPage+1)) si.nPos=si.nMax-si.nPage+1;
else if(si.nPos<si.nMin) si.nPos=si.nMin;
ListView_Scroll(hwnd,si.nPos-pre_pos,0);
LVC_NCDrawScrollBar(hwnd,SB_HORZ);
}
else if(ls->drag_pos.y!=-1) {
RECT rc_vs,rc_thumb;
if(LVC_GetZoneRect(hwnd,ZVSCROLL,&rc_vs,TRUE)!=0) return -1;
if(LVC_GetZoneRect(hwnd,ZVSTHUMB,&rc_thumb,TRUE)!=0) return -1;
SCROLLINFO si;
si.cbSize=sizeof(si);
si.fMask=SIF_ALL;
GetScrollInfo(hwnd,SB_VERT,&si);
int pre_pos=si.nPos;
si.nPos=(int)ls->drag_pos.y+((int)(si.nMax-si.nMin+1-si.nPage))*1.0*((int)(pt.y-ls->drag_pt.y))/((rc_vs.bottom-rc_vs.top)-(rc_thumb.bottom-rc_thumb.top));
if(si.nPos==ls->drag_pos.y) return -1;
if((int)si.nPos>(int)(si.nMax-si.nPage+1)) si.nPos=si.nMax-si.nPage+1;
else if(si.nPos<si.nMin) si.nPos=si.nMin;
ListView_Scroll(hwnd,0,(si.nPos-pre_pos)*ls->content_height);
LVC_NCDrawScrollBar(hwnd,SB_VERT);
}
return 0;
}
int LVC_ScrollDone(HWND hwnd,WPARAM wParam,LPARAM lParam)
{
pListViewStyle ls=ListView_GetSettings(hwnd);
if(!ls) return -1;
if(GetCapture()==hwnd) {
ReleaseCapture();
if(ls->drag_pos.y!=-1) LVC_NCDrawScrollBar(hwnd,SB_VERT);
if(ls->drag_pos.x!=-1) LVC_NCDrawScrollBar(hwnd,SB_HORZ);
ls->drag_pt.x=ls->drag_pt.y=ls->drag_pos.x=ls->drag_pos.y=-1;
}
return 0;
}
I have a set of labels [8][8] each with it's own Id, from a routine I call to change label color giving the hWnd, but then nothing happens, but if i don't specify an Id on case WM_CTLCOLORSTATIC: all labels change color
DWORD WINAPI changecolor(LPVOID lpParameter){
clrLabelBkGnd = RGB(255, 255, 0x00);
InvalidateRect(hWndLabel[0][0], NULL, TRUE);
return 0;
}
CALL back function
case WM_CTLCOLORSTATIC:
ctrlID = GetDlgCtrlID((HWND)lParam);
if (ctrlID == 1000) {
hdc = reinterpret_cast<HDC>(wParam);
SetBkColor(hdc, clrLabelBkGnd);
return reinterpret_cast<LRESULT>(hBrushLabel);
}
else break;
main program
/* fill the labels IDs*/
for (int i = 0; i < 8; i++){
for (int j = 0; j < 8; j++){
labelId[i][j] = (i * 8 + j)+1000;
}
}
In this example when I specify id 1000 which exist hWndLabel[0][0] nothing is colored, but if I don't specify id or if i put id > 1000 in case WM_CTLCOLORSTATIC: all labels are colored even by calling only hWndLabel[0][0]
This part is wrong:
case WM_CTLCOLORSTATIC:
if (LOWORD(wParam) == 1000) {
hdc = reinterpret_cast<HDC>(wParam);
Since wParam is the handle to the device context, why are you using it's low word as the ID of the control?
Take a look at WM_CTLCOLORSTATIC:
wParam
Handle to the device context for the static control window.
lParam
Handle to the static control.
What you need to use is lParam.
DWORD ctrlID = GetDlgCtrlID((HWND)lParam));
if (ctrlID == 1000)
{
}
UPDATE: Based on the comments you provided, you need to have a mechanism to retain the ID of the label that has been invalidated.
DWORD WINAPI changecolor(LPVOID lpParameter)
{
clrLabelBkGnd = RGB(255, 255, 0x00);
someVariableToHoldLabelIdWithRightScope = labelId[0][0]; // Or GetDlgCtrlID(hWndLabel[0][0]);
InvalidateRect(hWndLabel[0][0], NULL, TRUE);
return 0;
}
Then, when you handle the color:
case WM_CTLCOLORSTATIC:
ctrlID = GetDlgCtrlID((HWND)lParam);
if (ctrlID == someVariableToHoldLabelIdWithRightScope)
{
hdc = reinterpret_cast<HDC>(wParam);
SetBkColor(hdc, clrLabelBkGnd);
return reinterpret_cast<LRESULT>(hBrushLabel);
}
else break;
If you invalidate more than one label at a time, then one variable like this is not enough. You need to have a list/array/queue of IDs.
Marius answered your question - you are misusing the parameters of WM_CTLCOLORSTATIC, which is why your painting is not working correctly.
I would suggest a different solution to your problem. Have a list of colors, one set of Text/BkGnd colors for each label. Make changecolor() update the color entries for just the specified label as needed and then invalidate that label to trigger a repaint. WM_CTLCOLORSTATIC can then use the current colors of whichever label is currently being painted. No need to keep track of the changed Control ID between the call to changecolor() and the triggering of WM_CTLCOLORSTATIC (doing so is error prone anyway - think of what would happen if you wanted to change another label's coloring before WM_CTLCOLORSTATIC of a previous change is processed).
I would suggest a std::map to associate each label HWND to a struct holding that label's colors, eg:
#include <map>
struct sLabelColors
{
COLORREF clrText;
COLORREF clrBkGnd;
HBRUSH hBrushBkGnd;
};
std::map<HWND, sLabelColors> labelColors;
hWndLabel[0][0] = CreateWindowEx(...);
if (hWndLabel[0][0] != NULL)
{
sLabelColors &colors = labelColors[hWndLabel[0][0]];
colors.clrText = GetSysColor(COLOR_WINDOWTEXT);
colors.clrBkGnd = GetSysColor(COLOR_WINDOW);
colors.hBrushBkGnd = NULL;
}
case WM_CTLCOLORSTATIC:
{
HDC hdc = reinterpret_cast<HDC>(wParam);
sLabelColors &colors = labelColors[(HWND)lParam];
SetTextColor(hdc, colors.clrText);
SetBkColor(hdc, colors.clrBkGnd);
if (!colors.hBrushBkGnd) colors.hBrushBkGnd = CreateSolidBrush(colors.clrBkGnd);
return reinterpret_cast<LRESULT>(colors.hBrushBkGnd);
}
case WM_PARENTNOTIFY:
{
if (LOWORD(wParam) == WM_DESTROY)
{
HWND hWnd = (HWND)lParam;
std::map<HWND, sLabelColors>::iterator iter = labelColors.find((HWND)lParam);
if (iter != labelColors.end())
{
if (iter->hBrushBkGnd) DeleteObject(iter->hBrushBkGnd);
labelColors.erase(iter);
}
}
break;
}
DWORD WINAPI changecolor(LPVOID lpParameter)
{
sLabelColors &colors = labelColors[hWndLabel[0][0]];
if (colors.hBrushBkGnd) {
DeleteObject(colors.hBrushBkGnd);
colors.hBrushBkGnd = NULL;
}
colors.clrBkGnd = RGB(255, 255, 0x00);
InvalidateRect(hWndLabel[0][0], NULL, TRUE);
return 0;
}
I am creating a button application using resource editor. After creating button I try to do like this-
m_hwndPreview = CreateDialogParam( g_hInst,MAKEINTRESOURCE(IDD_MAINDIALOG), m_hwndParent,(DLGPROC)DialogProc, (LPARAM)this);
if (m_hwndPreview == NULL)
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
MSG msg;
BOOL bRet;
while ( (bRet=GetMessage (& msg,0, 0,0)) != 0)
{// this msg always contains the data like -msg = {msg=0x0000c03e wp=0x0000000000000012//always 12 I don't know why ?? lp=0x0000000000000000}
if (bRet == -1)
{
bRet = HRESULT_FROM_WIN32(GetLastError());
MessageBox(NULL, L"Hurr i am the error",L"Error",MB_ICONERROR | MB_OK);
}
else if (!IsDialogMessage (m_hwndPreview, & msg))
{
TranslateMessage (&msg); //on debugging TranslateMessage = 0x000007feee615480 TranslateMessage
DispatchMessage(& msg ); //but show nothing when I put cursor on this method to know the value that means it's not called
MessageBox(NULL, L"there is no error in receiving before dispatch the message",L"Error",
MB_ICONERROR | MB_OK);//this messagebox repeats again and again after the call to DialogProc function and I am not able to come out of the loop and here I need to restart my PC
at some other place I define createdialog function like this-
//this function is called just on createDialogParam() function.after it the controls go to getmessage where everything loops.
BOOL CALLBACK AMEPreviewHandler::DialogProc(HWND m_hwndPreview, UINT Umsg, WPARAM wParam, LPARAM lParam)
{ //this dialogProc function is declares Static some where in the code otherwise the createdialogparam will give error DLGPROC is invalid conversion
//this Umsg alays creates strange value like 48 and 32 etc.. and Wparam contains a very big value like 12335423526 (I mean big and strange) and lparam contains 0.
switch(Umsg)
{
case WM_INITDIALOG:
{
MessageBox(NULL, L"Inside the WM_INITDIALOG function",L"Error",
MB_ICONERROR | MB_OK);
return TRUE;
}
break;
case WM_CREATE:
{
/////////////////
MessageBox(NULL, L"Inside the WM_CREATE",L"Error",
MB_ICONERROR | MB_OK);
/////////////////////////////////
}
break;
case WM_COMMAND:
{ //here are my two buttons created by me which should show messagebox on click
int ctl = LOWORD(wParam);
int event = HIWORD(wParam);//I don't know why this event is in blue colour .. but its not the pqrt of problem right now.
if (ctl == IDC_PREVIOUS && event == BN_CLICKED )
{
MessageBox(m_hwndPreview,L"Button Clicked is next inside WM_COMMAND ",L"BTN WND",MB_ICONINFORMATION);
return 0;
}
if (ctl == IDC_NEXT && event == BN_CLICKED )
{
MessageBox(m_hwndPreview,L"Button Clicked is previous inside WM_COMMAND",L"BTN WND",MB_ICONINFORMATION);
return 0;
}
return FALSE;
}break;
case WM_DESTROY:
{
////////////////::
MessageBox(NULL, L"Inside the WM_DESTROY",L"Error",
MB_ICONERROR | MB_OK);
//////////////////
PostQuitMessage(0);
return 0;
}
break;
case WM_CLOSE:
{
MessageBox(NULL, L"Inside the WM_CLOSE",L"Error",
MB_ICONERROR | MB_OK);
DestroyWindow (m_hwndPreview);
return TRUE;
}
break;
}
MessageBox(NULL, L"outside the DefWindowProc function",L"Error",
MB_ICONERROR | MB_OK);
return 0;
}
The problem occurring is that when I debut it the control first go to CreateDialogParam and then it go to getmessage where the control don't come out of the loop causing restart problem. And I have no display of button and image at preview pane. What I expect if everything go fine is after debugging it should show picture on preview pane and I have 2 buttons "Next" and "Previous" but it show just a blank window (the buttons and photo I have already created using Resource editor... That's correct I am sure about that) .. but I don't know why I am not coming out getmessage function and dispatchmessage is not called (because I saw on debugging).
so now you can try to comment the getmessage part code that will probably out if the problem because you are creating button using IDD_MAINDIALOG and your createdialogparam directly calls your dailogproc function where you receive WM_COMMAND and that you handle by your code behind.
you should write
return true;
just after the DispatchMessage(msg);
and tehn debug it and inform me about t he result on debugging.
quick question...
I am working with treeview in win32 (VC++).
I want to remove selection facility provided for treeview. Can anyone tell what window message is posted onAfterSelect Event of tree view.
TV also has checkboxes. So disabling mouse click isn't an option...
Thanks in advance...
-
Varun
More Info
I am stuck at another point. My win32 application is essentially a modeless dialog - using CreateDialog & ShowWindow. After getting TVN_SELCHANGING, when I am returning 1, it isn't working. I think the default wndproc is getting called before I bypass the windows message. What should I do now?
I had this problem and just reversed the selection once it had already taken place. If you're not responding to it, anyway, then there shouldn't be any side effects.
case WM_NOTIFY:
{
if(wParam == IDC_TREE_MC)
{
LPNMHDR lpnmh = (LPNMHDR) lParam;
TVHITTESTINFO ht = {0};
if ((lpnmh->code == NM_CLICK) && (lpnmh->idFrom == IDC_TREE_MC)) // For Treeview Check Box Check Event
{
DWORD dwpos = GetMessagePos();
ht.pt.x = GET_X_LPARAM(dwpos);
ht.pt.y = GET_Y_LPARAM(dwpos);
MapWindowPoints(HWND_DESKTOP, lpnmh->hwndFrom, &ht.pt, 1);
TreeView_HitTest(lpnmh->hwndFrom, &ht);
if(TVHT_ONITEMSTATEICON & ht.flags)
PostMessage(hDlg, UM_CHECKSTATECHANGE, (WPARAM)lpnmh->hwndFrom, (LPARAM)ht.hItem);
else
TreeView_SelectItem(lpnmh->hwndFrom, NULL);
}
else if ((lpnmh->code == TVN_SELCHANGED ) && (lpnmh->idFrom == IDC_TREE_MC))
TreeView_SelectNode(lpnmh->hwndFrom, NULL);
}
break;
}
to remove selection facility provided for treeview
Could you please clarify this?
Do you want to prevent user from changing selection?
If you really want to do it, insert WM_NOTIFY case handler in the parent window, check for NMTREEVIEW code member (lParam is a pointer to NMTREEVIEW).
If code is TVN_SELCHANGING return 1 if you want to prevent selection change.
Returning 0 will alow selection change.
int CALLBACK WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
hWndDialog = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_MAIN), NULL, WndProc);
if (hWndDialog != NULL)
{
ShowWindow(hWndDialog, SW_SHOW);
}
while(GetMessage(&Msg, NULL, 0, 0))
{
if(!IsDialogMessage(hWndDialog, &Msg))
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
}
return 0;
}
INT_PTR CALLBACK WndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDC_BTN_REFRESH:
RefreshButtonHandler();
break;
case IDC_BTN_ADD_INSTALL:
AddInstallBtnHandler();
break;
case IDOK:
case IDCANCEL:
DestroyWindow(hDlg);
PostQuitMessage(0);
return (INT_PTR)TRUE;
break;
}
case WM_NOTIFY:
{
if(wParam == IDC_TREE_MC)
{
LPNMHDR lpnmh = (LPNMHDR) lParam;
TVHITTESTINFO ht = {0};
if ((lpnmh->code == NM_CLICK) && (lpnmh->idFrom == IDC_TREE_MC)) // For Treeview Check Box Check Event
{
DWORD dwpos = GetMessagePos();
ht.pt.x = GET_X_LPARAM(dwpos);
ht.pt.y = GET_Y_LPARAM(dwpos);
MapWindowPoints(HWND_DESKTOP, lpnmh->hwndFrom, &ht.pt, 1);
TreeView_HitTest(lpnmh->hwndFrom, &ht);
if(TVHT_ONITEMSTATEICON & ht.flags)
PostMessage(hDlg, UM_CHECKSTATECHANGE, (WPARAM)lpnmh->hwndFrom, (LPARAM)ht.hItem);
else
TreeView_SelectItem(lpnmh->hwndFrom, NULL);
}
else if ((lpnmh->code == TVN_SELCHANGING ) && (lpnmh->idFrom == IDC_TREE_MC))
return (INT_PTR)TRUE;
}
break;
}
case UM_CHECKSTATECHANGE:
{
//Handle TreeView Check State Event
}
break;
}
return (INT_PTR)FALSE;
}
Sorry for the bad formatting... I am sleep deprived :-)