Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.119.133.228] |
|
Сообщ.
#1
,
|
|
|
Диалоговое окно создано с помощью DialogBoxParam, в нём имеется Static-контрол, на котором происходит рисование.
Вернее, рисование происходит на совместимом DC (назовём его Draw), но потом нужно туда (в Static) этот рисунок копировать. В данный момент у меня сделано так: • Static имеет опцию стиля SS_OWNERDRAW • В оконной функции DialogProc я ловлю WM_DRAWITEM (wParam = ID контрола из ресурсов). Тут я тупо делаю BitBlt (переношу из совместимого DC Draw в DC Static-контрола). Без BeginPaint/EndPaint, потому как если я использую их (с hwnd = хендлу контрола), то почему-то ничего не рисуется. А если я использую hwnd = хендлу диалога, то рисуется, но само собой, на всём окне, а не на контроле. Меня гложет мысль, что это неправильно: перерисовывать весь контрол при каждом WM_DRAWITEM. Как сделать грамотно? p.s. BeginPaint/EndPaint (с hwnd = хендлу контрола) рисуется нормально при ловле WM_PAINT, а не WM_DRAWITEM, но там возникают другие глюки... |
Сообщ.
#2
,
|
|
|
Цитата Jin X @ Как сделать грамотно? Знать бы что такое "Грамотно".. 1. Можно делать так, как сейчас. 2. Можно не объявлять стиль SS_OWNERDRAW. Делать сабклассинг, перехватить оконную процедуру и самому обрабатывать сообщение WM_PAINT с использованием BeginPaint/EndPaint. 3. Можно после перехвата оконной процедуры разрешить стандартную прорисовку контрола. После её завершения ещё самому пытаться что-нибудь дорисовать на его поверхности. Из того же WM_PAINT. --- Выбирай что удобнее и лучше подходит именно для твоей задачи. |
Сообщ.
#3
,
|
|
|
Цитата Jin X @ • В оконной функции DialogProc я ловлю WM_DRAWITEM (wParam = ID контрола из ресурсов). Тут я тупо делаю BitBlt (переношу из совместимого DC Draw в DC Static-контрола). Без BeginPaint/EndPaint, потому как если я использую их (с hwnd = хендлу контрола), то почему-то ничего не рисуется. А если я использую hwnd = хендлу диалога, то рисуется, но само собой, на всём окне, а не на контроле. Покажи, как ты обрабатываешь WM_DRAWITEM |
Сообщ.
#4
,
|
|
|
Цитата ЫукпШ @ Надо изучить этот вопрос. Как это должно выглядеть...Делать сабклассинг, перехватить оконную процедуру и самому обрабатывать сообщение WM_PAINT с использованием BeginPaint/EndPaint. В общем-то, нашёл статьи даже нужные Цитата Олег М @ У меня на асме Покажи, как ты обрабатываешь WM_DRAWITEM .elseif edx == WM_DRAWITEM && r8d == IDC_GRAPHIC ; отрисовка содержимого окна mov r10d,rect.right sub r10d,rect.left ; R10 = ширина клиентской части графика mov r11d,rect.bottom sub r11d,rect.top ; R11 = высота клиентской части графика invoke BitBlt, hGraphicDC, 0, 0, r10, r11, hDrawDC, 0, 0, SRCCOPY ; выводим изображение на график mov eax,TRUE .if edx == WM_INITDIALOG ; инициализация диалога invoke GetDlgItem, rcx, IDC_GRAPHIC ; получаем хендл графика (контрола) invoke GetClientRect, rax, &rect ; получаем размер клиентской части графика . . . Попутно вопрос: rect.left и rect.top всегда будут = 0 ? Т.е. можно ли безболезненно убрать sub r10d,rect.left и sub r11d,rect.top? |
Сообщ.
#5
,
|
|
|
Цитата Jin X @ invoke BitBlt, hGraphicDC, 0, 0, r10, r11, hDrawDC, 0, 0, SRCCOPY ; выводим изображение на график Ты бы вместо BitBlt попробовал сначала что-нибудь типа FillRect, чтоб убедится, чтo всё правильно. И откуда ты берёшь hGraphicDC, точно из DRAWITEMSTRUCT? Цитата Jin X @ Меня гложет мысль, что это неправильно: перерисовывать весь контрол при каждом WM_DRAWITEM. Как сделать грамотно? Перерисовывать только прямоугольник, который изменился - GetClipBox, вроде. |
Сообщ.
#6
,
|
|
|
Цитата Jin X @ Цитата ЫукпШ @ Надо изучить этот вопрос. Как это должно выглядеть...Делать сабклассинг, перехватить оконную процедуру и самому обрабатывать сообщение WM_PAINT с использованием BeginPaint/EndPaint. В общем-то, нашёл статьи даже нужные Можно сделать класс-сабклассинг. Унаследоваться от него.. В результате получим контрол с возможностью сабклассинга и со всем необходимым хозяйством "внутри". |
Сообщ.
#7
,
|
|
|
Цитата Олег М @ А зачем мне в этом убеждаться, если всё работает? Вопрос в оптимизации, а не работоспособности Ты бы вместо BitBlt попробовал сначала что-нибудь типа FillRect, чтоб убедится, чтo всё правильно. И откуда ты берёшь hGraphicDC, точно из DRAWITEMSTRUCT? |
Сообщ.
#8
,
|
|
|
Цитата Jin X @ Цитата Олег М @ А зачем мне в этом убеждаться, если всё работает? Вопрос в оптимизации, а не работоспособности Ты бы вместо BitBlt попробовал сначала что-нибудь типа FillRect, чтоб убедится, чтo всё правильно. И откуда ты берёшь hGraphicDC, точно из DRAWITEMSTRUCT? Вопрос заключается не в первом предложении, а во втором. По хорошему/правильному, для рисования нужно использовать hDC и rcItem из DRAWITEMSTRUCT. Хоть в мсдн практически ничего не говорится об особенностях WM_DRAWITEM для статик-контрола, но наверняка в случае, если нужно перерисовывать не всё окно, а его часть, то rcItem должно соответствовать GetClipBox. PS: Еще к вопросу об "оптимизации". Не знаю как насчет твоего статика, но, например, в случае кнопки, WM_DRAWITEM может вызываться при установке или потере фокуса кнопки. В этом случае можно\нужно анализировать поля itemAction и itemState и при необходимости рисовать не всю кнопку, а только рамку фокуса. Кто знает, если твой статик не заблокирован от получения фокуса, может для него WM_DRAWITEM также вызывается при установке\потере фокуса, когда не обязательно перерисовывать всё изображение? |
Сообщ.
#9
,
|
|
|
Цитата leo @ Вопрос заключается не в первом предложении, а во втором. По хорошему/правильному, для рисования нужно использовать hDC и rcItem из DRAWITEMSTRUCT. Я что-то типа того делал. Обрабатываешь WM_DRAWIETM для HWND своего статика Дальше LPDRAWITEMSTRUCT dis = (LPDRAWITEMSTRUCT)lParam; RECT rect = dis->rcItem; HGDIOBJ hbrush = ::CreateSolidBrush(RGB(0,0,255)); ::SelectObject(dis->hDC,hbrush); ::SetBkColor(dis->hDC,RGB(0,0,255)); Добавлено Жень, на асме это "назло врагам"? |
Сообщ.
#10
,
|
|
|
Цитата ter_nk_ @ Дальше LPDRAWITEMSTRUCT dis = (LPDRAWITEMSTRUCT)lParam; RECT rect = dis->rcItem; HGDIOBJ hbrush = ::CreateSolidBrush(RGB(0,0,255)); ::SelectObject(dis->hDC,hbrush); ::SetBkColor(dis->hDC,RGB(0,0,255)); А "DeleteObject" ? Не оптимально при каждом вызове обработчика создавать кисть. Она же с постоянным цветом - лучше создать заранее. |
Сообщ.
#11
,
|
|
|
Цитата ЫукпШ @ А "DeleteObject" ? Не оптимально при каждом вызове обработчика создавать кисть. Она же с постоянным цветом - лучше создать заранее. До таких-то вещей уж как-то сам, это же подразумевается, что такие ресурсы типа GDI создать при загрузке где-то, а когда не надо выгрузить. |
Сообщ.
#12
,
|
|
|
В целом ясно. Всем спасибо. Надо использовать rcItem. Static фокус не получает (WS_TABSTOP отсутствует).
Вопрос только в том, что если itemAction имеет флаг ODA_DRAWENTIRE, то rcItem всё равно будет корректно заполнен? По логике должен и об обратно ничего не сказано, но мало ли... Цитата ter_nk_ @ Нет, просто так нужно в данном случае Жень, на асме это "назло врагам"? |
Сообщ.
#13
,
|
|
|
Цитата В каком таком default state? А в каком ещё он может быть? И как его привести в это состояние?Before returning from processing this message, an application should ensure that the device context identified by the hDC member of the DRAWITEMSTRUCT structure is in the default state. Ещё такой момент... Структура имеет вид: typedef struct tagDRAWITEMSTRUCT { UINT CtlType; UINT CtlID; UINT itemID; UINT itemAction; UINT itemState; HWND hwndItem; HDC hDC; RECT rcItem; ULONG_PTR itemData; } DRAWITEMSTRUCT; Поэтому смещение rcItem будет = 10*4 (а не 9*4). По факту так и получается, rcItem.left имеет смещение 10*4 = 40 = 28h. |
Сообщ.
#14
,
|
|
|
Цитата Jin X @ В каком таком default state? А в каком ещё он может быть? И как его привести в это состояние? Это значит, что если ты делаешь какие-то SelectObject для изменения pen, brush, font, то по окончании своих художеств должен вернуть их все в дефолтное состояние. См. ремарки к SelectObject Цитата An application should always replace a new object with the original, default object after it has finished drawing with the new object. PS: Но к твоей задаче это не имеет отношения, т.к. ты рисуешь не непосредственно на оконном hDC, а в отдельном битмапе, и затем просто копируешь картинку в hDC, не изменяя его дефолтных свойств. Добавлено Цитата Jin X @ правильно ли я понимаю, что тут идёт выравнивание каждого элемента по размеру типа? Да |
Сообщ.
#15
,
|
|
|
Цитата leo @ Почему не имеет? Это относится только к оконным hdc? Если да, то где об этом сказано?PS: Но к твоей задаче это не имеет отношения, т.к. ты рисуешь не непосредственно на оконном hDC, а в отдельном битмапе, и затем просто копируешь картинку в hDC, не изменяя его дефолтных свойств. По идее как-то так должно быть: originalPen = SelectObject(hdc, GreatePen(PS_DASH, 3, 0x80)); ... DeleteObject(SelectObject(hdc, originalPen)); |