![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Ownerdraw Button Control и region'ы
Nick Denry © (2005-09-09 15:56:00)Народ подскажите , плиз, почему кнопка (обычный 'Button' class) не изменяет свою форму, если установить ей регион? Может имеет смысл ее сабклассировать, чтобы перехватывать какие то ее собщения?
Nick Denry (2005-09-14 20:04:00) [1]Во-вторых, вызывается ли UnregisterClass в библиотеке при ее освобождении
да на dll_process_detach
Во-первых, зачем библиотеку освобождать ?
ну я загружаю ее динамически, поэтому по хорошему, ее надо освобождать...
но впринципе, никакой необходимости загружать динамически нет, я просто сделал "по инерции", попробую статическую загрузку.
ПОЧЕМУ ЛЮДИ НИКОГДА НЕ ПИШУТ ДЕТАЛЬНОЕ ОПИСАНИЕ ПРОБЛЕМЫ
(ничего страшного :)
(а может и очень страшно, но я не специально и уж тем более не партизан :)
Я лично предположил, что такая проблема должна быть достаточно известна
или имеет известное логическое объяснение и
выгрузка библиотеки (после оконного цикла):
While GetMessage(Mesg,0,0,0) do
begin
TranslateMessage(Mesg);
DispatchMessage(Mesg);
end;
FreeLibrary(stdCtrlsLib);
end.
дало отсутвие появления исключения.
Если освобождать на WM_DESROY:
то получаю следующее исключение:
---------------------------
Dialog: test.exe - Ошибка приложения
---------------------------
Инструкция по адресу "0x00793db0" обратилась к памяти по адресу "0x00793db0". Память не может быть "read".
"ОК" -- завершение приложения
"Отмена" -- отладка приложения
---------------------------
OK Отмена
---------------------------
Игорь Шевченко (2005-09-14 10:11:00) [2]
> А вот когда я на
> WM_DESTROY:
> begin
> { Освобождаю библиотеку}
> FreeLibrary (controlDll); - то прога вызывает
> исключение, т.к. я так понимаю еще обращается к процедуре
> окна самого контрола, а тут библиотека как бы убирается.
> ..
>
> end;
Во-первых, зачем библиотеку освобождать ?
Во-вторых, вызывается ли UnregisterClass в библиотеке при ее освобождении
В-третьих, и самое главное:
ПОЧЕМУ ЛЮДИ НИКОГДА НЕ ПИШУТ ДЕТАЛЬНОЕ ОПИСАНИЕ ПРОБЛЕМЫ, НАПРИМЕР, КАКОЕ ИСКЛЮЧЕНИЕ У НИХ ВОЗНИКАЕТ ? У ОТВЕЧАЮЩИХ ЧАЩЕ ВСЕГО НЕТ ПЕРЕД ГЛАЗАМИ ЭКРАНА АВТОРА ВОПРОСА.
ЕСЛИ КТО ИЗ АВТОРОВ ВОПРОСОВ СЧИТАЕТ СЕБЯ ПАРТИЗАНОМ, ПОПАВШИМ В ГЕСТАПО И БУДЕТ ТЕРПЕТЬ ПЫТКИ, НО НЕ ВЫДАСТ ВОЕННУЮ ТАЙНУ, ЭТО ЕГО, АВТОРА ВОПРОСА, ЛИЧНЫЕ ПРОБЛЕМЫ И ШАНСЫ ЕГО ПОЛУЧИТЬ ПОМОЩЬ РЕЗКО УМЕНЬШАЮТСЯ.
Извиняюсь за крик, наболело.
Nick Denry (2005-09-13 19:01:00) [3]на этапе инициализации DLL класс регистрируется
Т.е. мне надо сделать что-то типа функции initCommonControls?
Или достаточно при DLL_PROCESS_ATTACH зарегистрировать этот класс?
И еще, для назначения контролу индивидуальных параметров я использую SetProp/GetProp,
потому что глобальные переменные принимают одинаковые значения для всех контролов (т.е. для последнего, их использующего), а локольные (в процедуре обработки сообщений окна) почему-то не инициализируются - это правильно (а контролов должно быть рпоизвольное количество, само собой разумеется)?
и вот еще вопрос, когда я могу выгрузить такую библиотеку безопасно?
У меня сначала было так:
{код приложения (примерно, пишу не из дома), использующего длл, функция WndProc}
...(Глобальные переенные)
var
controlDll: THandle;
graphButton : HWND;
WM_CREATE:
begin
controlDll := LoadLibrary('libname.dll');
graphButton := CreateWindow('antGraphBtnClass', ...);
SetProp(graphButton, 'image_up', hBitmap_handle);
{ну и т.д.}
end;
А вот когда я на
WM_DESTROY:
begin
{ Освобождаю библиотеку}
FreeLibrary (controlDll); - то прога вызывает исключение, т.к. я так понимаю еще обращается к процедуре окна самого контрола, а тут библиотека как бы убирается...
end;
так вот когда ее можно нормально освободить - после цикла
while GetMessage ???
Игорь Шевченко (2005-09-13 14:37:00) [4]Nick Denry © (13.09.05 13:42) [21]
> Требуется компонент (не в дельфийском понятии этого слова
> :),
Это называется Control. Делай и воздастся тебе.
> Я не знаю, насколько использовние контролов (о, слово наконец-то
> вспомнил!) со стилем CS_GLOBALCLASS оправданно и безопасно....
И оправдано и безопасно. Располагается он в DLL, также, как и Common Controls, на этапе инициализации DLL класс регистрируется.
Nick Denry © (13.09.05 13:53) [22]
> Win32Check((FButtonRgn <> 0) and (SetWindowRgn (FButton,
> FButtonRgn, true) <> 0));
if not ((FButtonRgn <> 0) and (SetWindowRgn (FButton,
> FButtonRgn, true) <> 0)) then
raise Exception.Create (SysErrorMessage(GetLastError));
одно и то же.
Nick Denry (2005-09-13 13:53:00) [5]Игорь, а что такое
Win32Check((FButtonRgn <> 0) and (SetWindowRgn (FButton, FButtonRgn, true) <> 0));
Я первый раз такую конструкцию вижу...
Nick Denry (2005-09-13 13:42:00) [6]Требуется компонент (не в дельфийском понятии этого слова :),
кнопка, имеющая след. параметры:
Графическа кнопка произвольной формы (задется маской), имеет четыре (т.е. три состояния, на каждое из которых отрисовывается своя картинка) -
1. Кнопка отжата (1ая картинка)
2. Кнопка нажата (2ая картика)
3. Мышь над (сотсюда суперклассинг, сообщние WM_MOUSEOVER, 3я картинка)
Так же при нажатии/отжатии/наведении кнопка менят цвет надписи, на 3 заданных.
+ Возможность назначить Шрифт, которым будет отрисовывться текст на кнопке.
Кнопка должна быть расположенна в множстве диалогов программы (в ресурсах, отсюда и CS_GLOBALclASS) и не должн быть размазанна по всму коду (т.е. код кнопки в проекте должен встречаться один раз (т.е. вроде как Dll)- в остльных модулях только создание, уничтожение и назначение свойств (я сделал через SetProp/GeProp).
Вопрос один и то наверное не существенный - сделать это а базе виндовой кнопки или как я - на баз обычного окна - имитирующего поведение кнопки.
Я не знаю, насколько использовние контролов (о, слово наконец-то вспомнил!) со стилем CS_GLOBALCLASS оправданно и безопасно....
Игорь Шевченко (2005-09-13 13:20:00) [7]Nick Denry © (13.09.05 13:03) [19]
> Я вот только теперь чего думаю, обратно на кнопки перейти
>
А я не знаю, что тебе требуется. Как назначить регион окну кнопки, вроде разобрались, причем тут саб/суперклассинг, я не совсем понимаю.
Nick Denry (2005-09-13 13:03:00) [8]2Игорь Шевченко © (13.09.05 10:13) [17]
Ага, вот теперь можно кричать, размахивать руками и говорить, я так и знал, я так и думал... :)
Я вот только теперь чего думаю, обратно на кнопки перейти и свой контрол выкинуть нафиг или не мучаться с суперклассированием?
Игорь Шевченко (2005-09-13 10:14:00) [9]Удалено модератором
Примечание: Дубль
Игорь Шевченко (2005-09-13 10:13:00) [10]Nick Denry © (13.09.05 00:21) [15]
> Ну теперь собственно говоря между WS_POPUP + Windows.SetParent(Button,
> Handle); и WS_CHILD;
Все решается очень просто, при создании окна кнопки добавь ей стиль WS_CLIPSIBLINGS.
Вот такой пример работает:
procedure TForm1.Button1Click(Sender: TObject);
var
ButtonRect: TRect;
begin
FButton := CreateWindowEx(0, 'BUTTON','_OK_',
WS_CHILD or WS_VISIBLE or WS_CLIPSIBLINGSor BS_PUSHBUTTON,
10, 10, 70, 25, Handle, 0, HInstance, nil);
Windows.GetWindowRect(FButton, ButtonRect);
OffsetRect(ButtonRect, -ButtonRect.Left, -ButtonRect.Top);
FButtonRgn := CreateEllipticRgnIndirect (ButtonRect);
Win32Check((FButtonRgn <> 0) and (SetWindowRgn (FButton, FButtonRgn, true) <> 0));
end;
Без этого стиля придется каждый раз при перерисовке вызывать функции InvalidateRect у родительского окна и UpdateWindow у дочернего.
А ларчик открывается просто: создаешь обычную кнопку и winapi'шную кнопку, смотришь Spy++, чем окна отличаются.
Nick Denry (2005-09-13 00:23:00) [11]правда я с испугу свой контрол реализовал в Dll и CS_GLOBALCLASS :)
Впринципе, получилось даже интереснесней - поддержка 4 состояний и PNG :)
Nick Denry (2005-09-13 00:21:00) [12]Ну теперь собственно говоря между WS_POPUP + Windows.SetParent(Button, Handle); и WS_CHILD;
Турист (2005-09-10 12:37:00) [13]>Nick Denry © (10.09.05 12:01) [13]
>интресно, в чем все-таки разница? :)
Между чем ?
Nick Denry (2005-09-10 12:01:00) [14]Да, последний вариант действительно работает...
интресно, в чем все-таки разница? :)
Турист (2005-09-09 23:59:00) [15]Наверно, это все-таки неправильно
procedure TForm1.Button2Click(Sender: TObject);
var
Button: Hwnd;
begin
Button := CreateWindow('BUTTON','_OK_', WS_POPUP,
10, 10, 70, 25, 0, 0, HInstance, nil);
SetWindowRgn(Button, CreateEllipticRgn(0, 0, 70, 25), False);
Windows.SetParent(Button, Handle);
ShowWindow(Button, SW_SHOW)
end;
Nick Denry (2005-09-09 22:09:00) [16]Да , но с виндовой кнопкой почему-то не работает
y-soft (2005-09-09 20:08:00) [17]>Nick Denry © (09.09.05 19:22) [9]
Все рисуется и обрабатывается (пример из книги Марко Канту, Тим Гуч с Джоном Ф. Лэм "Delphi. Руководство разработчика"):
http://y-soft.comsignal.ru/Delphi/DDHROUND_PAS.HTM
Nick Denry (2005-09-09 19:22:00) [18]Отсечения воспроизведения все равно не происходит.
Мне кажется, что
===
int SetWindowRgn(
HWND hWnd,
HRGN hRgn,
BOOL bRedraw // window redraw flag
);
----
Remarks
If the bRedraw parameter is TRUE, the system sends the WM_WINDOWPOSCHANGING and WM_WINDOWPOSCHANGED messages to the window.
====
у кнопок на 2 этих сообщения какая-то нестандартная обработка...
Игорь Шевченко (2005-09-09 18:32:00) [19]Nick Denry © (09.09.05 18:30) [7]
> Т.е. ты хочешь сказать, что регион должен создаваться как
>
Вообще-то да :)
Nick Denry (2005-09-09 18:30:00) [20]Т.е. ты хочешь сказать, что регион должен создаваться как
btnRgn := CreateEllipticRgn(0,0,20,15);
?