#windows
Вопрос:
прежде всего
Я не являюсь носителем английского языка. В предложениях может быть много грамматических ошибок. Я постараюсь, насколько смогу, выразить результат, которого я пытаюсь достичь, и проблемы, с которыми я сталкиваюсь. Это на какое-то время заблокировало меня,угнетало. Мне действительно нужна помощь, чтобы указать, где я был неправ и что мне следует делать. Спасибо вам за ваше внимание.
ЧТО Я ДЕЛАЮ
Я пытаюсь перерисовать стандартный элемент управления win32 WC_LISTBOX. Согласно MSDN, вы можете изменить цвет фона , шрифт текста , цвет текста , размер границы, сделать свой собственный рисунок каждого элемента списка. Интерфейс элемента управления WC_LISTBOX, предоставляемого Microsoft, работает очень хорошо, за исключением встроенной полосы прокрутки .
Полоса прокрутки по умолчанию для этого элемента управления-это какая-то белая или серая часть, две стрелки, прокрутка chanel, блок большого пальца.
Я хочу сделать свою собственную картину для полосы прокрутки элемента управления. Я выбрал темный цвет для элемента управления. Цвет шрифта, цвет фона, цвет текста и так далее, как указано выше, можно настроить с помощью предоставленного интерфейса. Но для полосы прокрутки практически нет интерфейса. Кажется, единственный выбор-переписать NCPaint.
После долгих поисков и тестовых кодировок несколько сообщений нужно обработать самостоятельно. Я думаю о том, что я делаю : если пользователь нажмет левую кнопку мыши на прямой линии большого пальца полосы прокрутки, это вызовет действие перетаскивания. Когда пользователь перетаскивает зону большого пальца, я фиксирую сообщение о перемещении мыши , обновляю информацию о прокрутке на полосе прокрутки и рисую полосу прокрутки в соответствии с обновленной информацией о прокрутке.
WM_NCCALCSIZE
: Мне нужно вычислить и установить зону прямой кишки Не-клиента и клиента.
int ListBox_NCCalcSize(HWND hwnd,LPNCCALCSIZE_PARAMS calc)
{
RECT rect_new;
RECT rect_old;
RECT client_rect_new;
RECT client_rect_old;
pLBStyle ls=ListBox_GetSettings(hwnd);
BOOL IsVScroll=(((UINT)GetWindowLongPtr(hwnd,GWL_STYLE)amp;WS_VSCROLL)==WS_VSCROLL);
CopyRect(amp;rect_new,amp;(calc->rgrc[0]));
CopyRect(amp;rect_old,amp;(calc->rgrc[1]));
CopyRect(amp;client_rect_old,amp;(calc->rgrc[2]));
//set new rect for listbox control.
client_rect_new = {rect_new.left ls->margin_border,
rect_new.top ls->margin_border,
rect_new.right-ls->margin_border-(IsVScroll?SCROLLBAR_PIXLS:0),
rect_new.bottom-ls->margin_border};
CopyRect(amp;(calc->rgrc[0]),amp;client_rect_new);
CopyRect(amp;(calc->rgrc[1]),amp;rect_new);
CopyRect(amp;(calc->rgrc[2]),amp;rect_old);
return WVR_VALIDRECTS;
}
WM_NCACTIVATE
/WM_NCPAINT
: Repaint the border and the scrollbar of the control.
int ListBox_NCPaint(HWND hwnd)
{
pLBStyle ls=ListBox_GetSettings(hwnd);
if(!ls) return -1;
HDC hdc=GetWindowDC(hwnd);
UINT style=GetWindowLongPtr(hwnd,GWL_STYLE);
RECT rc={0},rc_mem;
GetWindowRect(hwnd,amp;rc);
CopyRect(amp;rc_mem,amp;rc);
OffsetRect(amp;rc_mem,-rc_mem.left,-rc_mem.top);
//memory device context
HDC memdc=CreateCompatibleDC(hdc);
HBITMAP bmp=CreateCompatibleBitmap(hdc,rc_mem.right,rc_mem.bottom);
HBITMAP pre_bmp=(HBITMAP)SelectObject(memdc,bmp);
//reflesh the background
COLORREF color_trans=RGB(0,0,1);
HBRUSH brush=CreateSolidBrush(color_trans);
FillRect(memdc,amp;rc_mem,brush);
//border
if((styleamp;WS_BORDER)==WS_BORDER) {
RECT rc_tmp;
CopyRect(amp;rc_tmp,amp;rc_mem);
for(int index=0;index<ls->margin_border;index ) {
FrameRect(memdc,amp;rc_tmp,ls->brush_border);
InflateRect(amp;rc_tmp,-1,-1);
}
}
//Blt
TransparentBlt(hdc,0,0,(rc.right-rc.left),(rc.bottom-rc.top),
memdc,0,0,rc_mem.right,rc_mem.bottom,color_trans);
DeleteObject(brush);
DeleteObject(SelectObject(memdc,pre_bmp));
DeleteDC(memdc);
ReleaseDC(hwnd,hdc);
return 0;
}
int ListBox_DrawScrollBar(HWND hwnd)
{
pLBStyle ls=ListBox_GetSettings(hwnd);
if(!ls) return -1;
RECT rc_mem,rc_vs,rc_thumb;
if(ListBox_GetZoneRect(hwnd,ZVSCROLL,amp;rc_vs,TRUE)!=0) return -1;
CopyRect(amp;rc_mem,amp;rc_vs);
OffsetRect(amp;rc_mem,-rc_vs.left,-rc_vs.top);
//initial gdi resource
HDC hdc=GetWindowDC(hwnd);
HDC memdc=CreateCompatibleDC(hdc);
HBITMAP bmp=CreateCompatibleBitmap(hdc,rc_mem.right-rc_mem.left,rc_mem.bottom-rc_mem.top);
HBITMAP pre_bmp=(HBITMAP)SelectObject(memdc,bmp);
//background of the scrollbar
FillRect(memdc,amp;rc_mem,ls->brush);
if(ListBox_GetZoneRect(hwnd,ZVSTHUMB,amp;rc_thumb,TRUE)!=0) return -1;
OffsetRect(amp;rc_thumb,-rc_vs.left,-rc_vs.top);
//thumb rect
Graphics graphic(memdc);
graphic.SetSmoothingMode(SmoothingModeHighQuality);
GraphicsPath path;
LinearGradientBrush pbrush(Rect(rc_thumb.left,rc_thumb.top,SCROLLBAR_PIXLS,SCROLLBAR_PIXLS),
Color(255,10,10,10),Color(255,90,90,90),LinearGradientModeHorizontal);
path.AddArc(rc_thumb.left,rc_thumb.top,SCROLLBAR_PIXLS,SCROLLBAR_PIXLS,180,180);
path.AddArc(rc_thumb.left,rc_thumb.bottom-SCROLLBAR_PIXLS,SCROLLBAR_PIXLS,SCROLLBAR_PIXLS,0,180);
graphic.FillPath(amp;pbrush,amp;path);
//blt
BitBlt(hdc,rc_vs.left,rc_vs.top,rc_vs.right-rc_vs.left,rc_vs.bottom-rc_vs.top,
memdc,0,0,SRCCOPY);
//release gdi resource
DeleteObject(SelectObject(memdc,pre_bmp));
DeleteDC(memdc);
ReleaseDC(hwnd,hdc);
return 0;
}
WM_NCHITTEST
: Recognize the scrollbar zone hit.WM_NCLBUTTONDOWN
: Recognize if the hit on the scrollbar zone, if is, determining it is a dragging action of thumb rect. Howerver, acccording some source code , people don’t do this inWM_NCLBUTTONDOWN
procedure, they usually do this inWM_SETCURSOR
. I don’t know why.WM_SETCURSOR
: If NC_HitTest was in scrollbar rect, and the WM_SETCURSOR was triggered by WM_NCLUBTTONDOWN, that means user trying to scroll the control, now user doing dragging actions.
case WM_SETCURSOR: {
UINT hit_pos=LOWORD(lParam);
UINT trigger_msg=HIWORD(lParam);
if(hit_pos!=HTVSCROLL) return CallWindowProc(ls->pre_proc,hwnd,msg,wParam,lParam);
if(trigger_msg==WM_LBUTTONDOWN||trigger_msg==WM_NCLBUTTONDOWN) {
POINT pt={0};
RECT rc;
GetCursorPos(amp;pt);
//ScreenToClient(hwnd,amp;pt);
ListBox_GetZoneRect(hwnd,ZVSTHUMB,amp;rc,FALSE);
if(PtInRect(amp;rc,pt)) {
SetCapture(hwnd);
ls->scroll_state=THUMB_VCLICK;
}
}
} break;
WHAT IS THE TROUBLE
WM_MOUSEMOVE
: Update the scrollbar info , repaint the scrollbar according the scrollinfo updated.
case WM_MOUSEMOVE: {
if(GetCapture()!=hwnd) break;
if(ls->scroll_state!=THUMB_VCLICK) break;
//...
} break;
However, I can’t get any WM_MOUSEMOVE message when dragging the thumb rect. Why ?
THE REST PART
Those messages down below are irrelevant for the problem yet. But I will still write the purpose of each.
WM_NCLBUTTONUP
/WM_LBUTTONUP
: Release the capture of the control, and it is a signal for stopping thumb dragging action.WM_PAINT
: Repaint the scrollbar.
PS: Я понял это и записываю здесь.
Почему не удается получить сообщение WM_MOUSEMOVE при вызове SetCapture для элемента управления списком? Есть очень небольшое изменение для моего кода.
Проблема заключается в дескрипторе WM_SETCURSOR или WM_NCLBUTTONDOWN.
case WM_SETCURSOR: {
UINT hit_pos=LOWORD(lParam);
UINT trigger_msg=HIWORD(lParam);
if(hit_pos!=HTVSCROLL) return CallWindowProc(ls->pre_proc,hwnd,msg,wParam,lParam);
if(trigger_msg==WM_LBUTTONDOWN||trigger_msg==WM_NCLBUTTONDOWN) {
POINT pt={0};
RECT rc;
GetCursorPos(amp;pt);
//ScreenToClient(hwnd,amp;pt);
ListBox_GetZoneRect(hwnd,ZVSTHUMB,amp;rc,FALSE);
if(PtInRect(amp;rc,pt)) {
SetCapture(hwnd);
ls->scroll_state=THUMB_VCLICK;
return 0;// here it is.
}
}
} break;
Когда вы SetCapture(hwnd)
, вы должны вернуть 0 и завершить обработку сообщения, если break;
здесь , процедура контроля по умолчанию возьмет верх и разрушит все, что вы сделали.
Каждый раз , когда я чувствую себя в ловушке, это всегда оказывается чем-то слишком крошечным, чтобы меня это волновало. Хм, каждый раз.
Комментарии:
1. Не меняйте состояние внутри
WM_SETCURSOR
. Просто установите курсор. Изменится ли состояниеWM_NCLBUTTONDOWN
.2. @Raymond, Ты прав. Это работает только внутри
WM_NCLBUTTONDOWN
. Я не знаю, почему. Кроме того, эти трюки, похоже, НЕ работают с управлением WC_EDIT. Если я применилWS_VSCROLL
WC_EDIT
элемент управления, начальный графический интерфейс по умолчанию имеет полосу прокрутки, даже если в поле редактирования нет содержимого. Это отличается отWC_LISTBOX
контроля. Это почему?