Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Перерисовка Radio и Check баттонов

7.2K
09 июля 2008 года
polaroid
94 / / 05.07.2008
Нарисовал 2 bmp'хи для стейтов радио и чек баттонов (чекед, анчекед). Вот теперь не пойму, как сделать так, чтобы при чеке, ну допустим радиобаттона рисовалась первая картинка, а при анчеке вторая. Создаю окно класса "BUTTON", стиль BS_AUTORADIOBUTTON.Использую сабклассинг, перехватываю метод WM_PAINT и WM_LBUTTONDOWN, правда мало толку от этого. Кнопка рисуется, при нажатии чекается (рисуется вторая bmp), но когда окно перерисовывается, кнопка естественно рисуется анчекед. Вот, собственно как сделать чтобы это работало правильно?
3.7K
09 июля 2008 года
0nni
326 / / 24.06.2008
Используй функцию InvalidateRect, в качестве HWND укажи хендл чекбокса который необходимо перерисовать в качестве lpRect укажи nul, (или NILL смотря на чем пишешь) если хочешь перерисовать все, третий параметр указывает надо ли перерисовать окно сразу или поместить WM_PAINT в очередь (обычно ставится по вкусу, но иногда имеет смысл).
3.7K
09 июля 2008 года
0nni
326 / / 24.06.2008
Цитата: 0nni
Используй функцию InvalidateRect,


Извиняюсь, неправильно прочитал вопрос, так вот вам надо указать в качестве стиля BS_OWNERDRAW, а потом ловить у главного окна сообщение WM_DRAWITEM подробнее смотри в справке

7.2K
09 июля 2008 года
polaroid
94 / / 05.07.2008
А можно ли это реализовать через сабклассинг\суперклассинг? просто проблема в том, что мне нужно одновременно показывать не одну, а несколько таких кнопок сразу. Поэтому я хотел сделать через суперклассинг, но не смог понять какие сообщения обрабатывать внутри оконной(кнопочной) процедуры. Я так понимаю WM_DRAWITEM обрабатывается в главной оконной процедуре?
Прочитал справку, и все равно не понял как сделать нормальную радио-баттон используя OWNERDRAW. Получается придется создавать глобальные переменные для определения checked\unchecked? Хотелось бы получить полный функционал radio-button, при этом просто перерисовывая её
3.7K
09 июля 2008 года
0nni
326 / / 24.06.2008
В ней радимой :)
Читай тут :
Код:
The WM_DRAWITEM message is sent to the owner window of an
owner-drawn button, combo box, list box, or menu when a visual
aspect of the button, combo box, list box, or menu has changed.

WM_DRAWITEM  
idCtl = (UINT) wParam;             // control identifier
lpdis = (LPDRAWITEMSTRUCT) lParam; // item-drawing information


The DRAWITEMSTRUCT structure provides information the owner window
must have to determine how to paint an owner-drawn control or menu item.
The owner window of the owner-drawn control or menu item receives a
pointer to this structure as the lParam parameter of the WM_DRAWITEM
message.

typedef struct tagDRAWITEMSTRUCT {  // dis  
    [COLOR="Red"]UINT  CtlType; [/COLOR]
    UINT  CtlID;
    UINT  itemID;
    UINT  itemAction;
    UINT  itemState;
    [COLOR="Red"]HWND  hwndItem; [/COLOR]
    [COLOR="Red"]HDC   hDC;[/COLOR]
    RECT  rcItem;
    DWORD itemData;
} DRAWITEMSTRUCT;
3.7K
09 июля 2008 года
0nni
326 / / 24.06.2008
Цитата: polaroid
А можно ли это реализовать через сабклассинг\суперклассинг?


Искал что такое субклассинг, оказалось это то, что назяваю подменой оконной процедуры :D.
Попробовал, и вот что получилось:

Код:
Function cbproc(wnd, msg : cardinal; wparam, lparam : integer) : integer; stdcall;
var ps : TPaintStruct;
begin
  case msg of
    WM_DESTROY : PostQuitMessage(0);
    [COLOR="Red"]BM_GETCHECK :
      begin
        result := defProc(wnd, msg, wparam, lparam);//Вначале вызываем
                       //оригинальный обработчик
        InvalidateRect(wnd, nil, true);.//А затем перерисовываем все окно
      end;[/COLOR]
    WM_PAINT :
      begin
        //Ну рисовать вы умеете
        BeginPaint(wnd, ps);
          if SendMessage(wnd, BM_GETCHECK, 0, 0) = 0 then
            FillRect(ps.hdc, ps.rcPaint, GetSysColorBrush(COLOR_BTNSHADOW))
          else
            FillRect(ps.hdc, ps.rcPaint, GetSysColorBrush(COLOR_BTNHIGHLIGHT));
        EndPaint(wnd, ps);
      end;
    else
    result := defProc(wnd, msg, wparam, lparam);
  end
end;

Я так понял у вас была проблема с неполной перерисовкой, вот она и решена, только обязатель вызывайте InvalidateRect с параметром true - а то окно будет моргать.
7.2K
09 июля 2008 года
polaroid
94 / / 05.07.2008
Огромнейшее спасибо! Все работает:D

Хммм. Рано радовался. Вообщем суперклассирую свои радио буттоны (суперклассинг - создание класса на основе другого класса, в моем случае на основе BUTTON)
Итак, код (сорри, но данный проект пишу на асме:) )

Код:
//szButton - переменная содержит имя класса "BUTTON"
//wcRadio - переменная содержит имя нового класса "RADIOBUTTON"

WndProc proc hWnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
    LOCAL ps    :PAINTSTRUCT
    LOCAL rc    :WNDCLASSEX

    .IF uMsg == WM_DESTROY
                      ...      
    .ELSEIF uMsg == WM_CREATE
        ; Createing "RADIOBUTTON" superclass:
        mov rc.cbSize, sizeof WNDCLASSEX
        invoke GetClassInfoEx,NULL,addr szButton,addr rc
        push rc.lpfnWndProc
        pop OldRadioProc
        mov rc.lpfnWndProc, OFFSET RadioProc
        push hInstance
        pop rc.hInstance
        mov rc.lpszClassName, OFFSET wcRadio
        invoke RegisterClassEx, addr rc

        invoke CreateWindowEx, 0, addr wcRadio, NULL, WS_CHILD+WS_VISIBLE+BS_AUTORADIOBUTTON, 200, 200, 14, 14, hWnd, NULL, hInstance, NULL
        mov rb, eax
        invoke CreateWindowEx, 0, addr wcRadio, NULL, WS_CHILD+WS_VISIBLE+BS_AUTORADIOBUTTON, 200, 250, 14, 14, hWnd, NULL, hInstance, NULL
        mov rb2, eax
                      ... //обработка других сообщений


Далее, моя процедура обработки (RadioProc):
Код:
RadioProc proc hWnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
    LOCAL dc        :HDC
    LOCAL ps        :PAINTSTRUCT
   
    .IF uMsg == BM_GETCHECK
        invoke CallWindowProc, OldRadioProc, hWnd, uMsg, wParam, lParam
        push eax
        invoke InvalidateRect, hWnd, NULL, TRUE
    .ELSEIF uMsg == WM_PAINT
        invoke BeginPaint, hWnd, addr ps
        mov dc, eax
        invoke SendMessage, hWnd, BM_GETCHECK, 0, 0
        .if (eax == 0)
            invoke BitBlt, dc, 0, 0, 14, 14, r1DC, 0, 0, SRCCOPY
        .else
            invoke BitBlt, dc, 0, 0, 14, 14, r2DC, 0, 0, SRCCOPY
        .endif
        invoke EndPaint, hWnd, addr ps
    .ELSE
        invoke CallWindowProc, OldRadioProc, hWnd, uMsg, wParam, lParam
        ret
    .ENDIF
    pop eax
    ret
RadioProc endp


Вот у меня выводится две радио кнопки. Все бы ничего, но проблема в том, что первая кнопка работает нормально, а вторая хоть и рисуется, но при нажатии на неё, поверх рисуется стандартная виндосская радио кнопка. В чем может быть проблема?
3.7K
10 июля 2008 года
0nni
326 / / 24.06.2008
br />
.IF uMsg == BM_GETCHECK
[COLOR="Red"]invoke CallWindowProc, OldRadioProc, hWnd, uMsg, wParam, lParam[/COLOR]
push eax
invoke InvalidateRect, hWnd, NULL, TRUE
.ELSEIF uMsg == WM_PAINT
invoke BeginPaint, hWnd, addr ps
[COLOR="Green"]mov dc, eax
invoke SendMessage, hWnd, BM_GETCHECK, 0, 0
.if (eax == 0)
invoke BitBlt, dc, 0, 0, 14, 14, r1DC, 0, 0, SRCCOPY
.else
invoke BitBlt, dc, 0, 0, 14, 14, r2DC, 0, 0, SRCCOPY
.endif[/COLOR]
invoke EndPaint, hWnd, addr ps



Дело в том что при вызове оригинального обработчика окна винда перерисовывает окно используя GetDC() Поэтому в WM_PAINT нужно заново обрисовать окно - т.е прийдется вызывать и GetWindiwText и FillRect и еще бог знает что, а еще попробуйте в InvalidateRect пооследний параметр вызвать с false (может я что напутал?)

зы. Ассемблером нас не напугаешь ;)

7.2K
10 июля 2008 года
polaroid
94 / / 05.07.2008
Попробовал с InvalidateRect false. Разницы нет. А можно поподробнее (или хотя бы ссылки на материалы) про перерисовку в оригинальной процедуре? Что нужно сделать, чтобы это все работало?:)
Конечно извиняюсь за назойливость, но к сожалению в инете не нашел вообще ничего по этой теме.
3.7K
10 июля 2008 года
0nni
326 / / 24.06.2008
Цитата: polaroid
Попробовал с InvalidateRect false. Разницы нет. А можно поподробнее (или хотя бы ссылки на материалы) про перерисовку в оригинальной процедуре? Что нужно сделать, чтобы это все работало?:)
Конечно извиняюсь за назойливость, но к сожалению в инете не нашел вообще ничего по этой теме.



Ну вот так наверное,

Код:
var ps : TPaintStruct;
    buff : array [0..255] of char;//ну это вроде кака участок памяти на 256 байт
    Textlength : Cardinal;
begin
  BeginPaint(wnd, ps);
    //Закрашиваем всю область
    FillRect(ps.hdc, ps.rcPaint, GetSysColorBrush(COLOR_BTNFACE));
    //это ваша строчка
    BitBlt(ps.dc, 0, 0, 14, 14, r1DC, 0, 0, SRCCOPY);
    //Получаем заголовок и его длинну в символах
    Textlength := GetWindowText(wnd, buff, 256);
    //Устанавливаем шрифт
    SelectObject(ps.hdc, GetStockObject(DEFAULT_GUI_FONT));
    //И выводим
    TextOut(ps.hdc, 16, 0, buff, Textlength);
  EndPaint(wnd, ps);
end;
end;


Если это не поможет то лучше создайте свой класс а насчет хранения состоянний (чек/унчек) могу посоветовать
GetWindowLong и SetWindowLog со значением GWL_USERDATA, я вооще по каждому случаю свои классы пишу, может это и не правильно, зато детям нравится :)
7.2K
10 июля 2008 года
polaroid
94 / / 05.07.2008
Огромное спасибо за инфу! Склоняюсь к созданию собственного класса, правда хотел суперклассить радио-буттон просто из-за того, что их можно объединять в группы и при нажатии на одну, автоматически анчекаются другие.
PS: код все-таки не помог
3.7K
10 июля 2008 года
0nni
326 / / 24.06.2008
Обидно конечно, сдела все что смог :(
14
10 июля 2008 года
Phodopus
3.3K / / 19.06.2008
Цитата: polaroid
хоть и рисуется, но при нажатии на неё, поверх рисуется стандартная виндосская радио кнопка. В чем может быть проблема?



Отлавливай BM_SETCHECK, отдавай стандартной процедуре, потом рисуй свою кнопь.

ПыСы. Вообще не понимаю, зачем BM_GETCHECK обрабатывать..

7.2K
10 июля 2008 года
polaroid
94 / / 05.07.2008
Спасибо. Отловил. Все работает.
Итак, готовое решение:

Код:
RadioProc proc hWnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
    LOCAL ps        :PAINTSTRUCT
   
    .IF uMsg == BM_SETCHECK
        invoke CallWindowProc, OldRadioProc, hWnd, uMsg, wParam, lParam
        push eax
        invoke InvalidateRect, hWnd, NULL, FALSE
    .ELSEIF uMsg == WM_PAINT
        invoke BeginPaint, hWnd, addr ps
        invoke GetSysColorBrush, COLOR_BTNFACE
        invoke SendMessage, hWnd, BM_GETCHECK, 0, 0
        .if (!eax)
            invoke BitBlt, ps.hdc, 0, 0, 14, 14, r1DC, 0, 0, SRCCOPY
        .else
            invoke BitBlt, ps.hdc, 0, 0, 14, 14, r2DC, 0, 0, SRCCOPY
        .endif
        invoke EndPaint, hWnd, addr ps
    .ELSEIF (uMsg == WM_LBUTTONDOWN)||(uMsg == WM_MOUSEMOVE)||(uMsg == WM_LBUTTONDBLCLK)
        invoke CallWindowProc, OldRadioProc, hWnd, uMsg, wParam, lParam
        push eax
        invoke InvalidateRect, hWnd, NULL, FALSE       
    .ELSE
        invoke CallWindowProc, OldRadioProc, hWnd, uMsg, wParam, lParam
        ret
    .ENDIF
    pop eax
    ret
RadioProc endp


WM_LBUTTONDOWN и WM_LBUTTONDBLCLK и WM_MOUSEMOVE обрабатываются для избежания артефактов при прорисовке. Пойду-ка напишу статью, чтобы на мои грабли никто больше не наступал:D
3.7K
10 июля 2008 года
0nni
326 / / 24.06.2008
Цитата: Phodopus
Отлавливай BM_SETCHECK, отдавай стандартной процедуре, потом рисуй свою кнопь.

ПыСы. Вообще не понимаю, зачем BM_GETCHECK обрабатывать..


А вы уверены что если GETCHECK не обработается оригинальной функцией, то состояние кнопки будет меняться - чек/унчек?

А GETCHECK обрабтывается потому, что после его обработки не посылается сообщение WM_PAINT, а происходит перерисовка через GetDC()
zb). Ждем статьи

14
11 июля 2008 года
Phodopus
3.3K / / 19.06.2008
Цитата: 0nni
А вы уверены что если GETCHECK не обработается оригинальной функцией, то состояние кнопки будет меняться - чек/унчек?



Мы же и так отдаем все сообщения оригинальной фукции! Я имел ввиду зачем его в нашем обработчике обрабатывать дополнительно..

Цитата: 0nni
А GETCHECK обрабтывается потому, что после его обработки не посылается сообщение WM_PAINT, а происходит перерисовка через GetDC()


не, все-равно не понял :))

ПыСы. Статья - это самое достойное добивание решившейся проблемы! :D

7.2K
11 июля 2008 года
polaroid
94 / / 05.07.2008
Написал статью. Подготовил исходники на 3х языках (Delphi, C++, asm). Как её выложить?
3.7K
11 июля 2008 года
0nni
326 / / 24.06.2008
Цитата: Phodopus
Мы же и так отдаем все сообщения оригинальной фукции! Я имел ввиду зачем его в нашем обработчике обрабатывать дополнительно..

не, все-равно не понял :))



[COLOR="Gray"]Решил программист спрыгнуть с крыши - все посчитал, разбежался и с криком "Ой мля знак перепутал!!!" улетел в небо[/COLOR]

Это конечно мне не оправдание :(.
На самом деле надо было обрабатывать BM_SETCHECK. изменить состояние кнопки можно только послав ей это сообщение и ни как иначе. Можно конечно обрабатывать все сообщения от мыши - WM_LB* и вызывать BM_SETCHECK, но в случае с радио-кнопками если с одной из них снимается значение, то никаких сообщений от мыши не посылается, тоесть нам просто необходимо отлавливать именно момент изменения значения кнопки.
зы. Надеюсь я меня поняли. И еще раз извиняюсь за неверную информацию.

7.2K
11 июля 2008 года
polaroid
94 / / 05.07.2008
На счет сообщений мыши, это я погорячился. В итоге нужно обработать всего 3 сообщения: WM_PAINT, BM_SETCHECK, и BM_SETSTATE. Отписал на имейл [email]redaktor@codenet.ru[/email]. Скоро выложу статью
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог