Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "WinAPI";
Текущий архив: 2005.11.13;
Скачать: [xml.tar.bz2];

Вниз

Ownerdraw Button Control и region ы   Найти похожие ветки 

 
Nick Denry ©   (2005-09-09 15:56) [0]

Народ подскажите , плиз, почему кнопка  (обычный "Button" class) не  изменяет  свою форму, если установить ей регион? Может имеет смысл ее сабклассировать, чтобы перехватывать какие то ее собщения?


 
Игорь Шевченко ©   (2005-09-09 16:29) [1]


> Народ подскажите , плиз, почему кнопка  (обычный "Button"
> class) не  изменяет  свою форму, если установить ей регион?


Изменяет


 
Nick Denry ©   (2005-09-09 16:46) [2]

Мой код:


Button1 := CreateWindow("BUTTON","_OK_", WS_CHILD or WS_VISIBLE, 10, 10, 70, 25, MainWnd, 0, HInstance, nil);

btnRgn := CreateEllipticRgn(10,10,30,25);

SetWindowRgn(Button1 ,  btnRgn, true);



Да, я согласен - регион изменяется (т.е. нельзя мышкой ткнуть в какой либо угол кнопки, чтобы пришло WM_COMMAND), но ее внешний вид остается неизменным, и даже если она OWNERDRAW  - то область осечения - не становится прозрачной - а выводится белым.

Игорь, я знаю что я туплю порой, неужели и в этот раз? :)


 
Nick Denry ©   (2005-09-09 16:49) [3]

Я думал - может Parent - окно не перерисовывается, но оно вроде как перерисовывается...

прочем чего мелочиться - вот весь код:

Program test;

uses
 windows,
 messages;

var
 wc : TWndClassEx;  //Переменная шаблона класса окна
 MainWnd : HWND;   //Описатель главного окна
 Mesg : TMsg;          //Переменная для цикла сбора сообщений

 Button1 : HWND;

 btnRgn : HRGN;

 bmpUp, bmpDwn : HBITMAP;

function GetRootDir : String;
var
  i : Integer;
  lpszExeDirPath : string;
begin
lpszExeDirPath := ParamStr(0);
for i := Length(lpszExeDirPath) downto 0 do
   begin
     if lpszExeDirPath[i] = "\" then begin
      SetLength(lpszExeDirPath,i);
      break;
     end;
   end;
   Result := lpszExeDirPath;
end;

function WindowProc(wnd:HWND; Msg : Integer; Wparam:Wparam; Lparam:Lparam):Lresult;stdcall;
var
   KS : TKeyboardState;
   TDC : HDC;

Begin
 {Далее происходит цикл обработки сообщений}
 case msg of
 WM_CREATE:
           begin
             bmpUp := LoadImage(0, PChar(GetRootDir+"ups.bmp"),IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
           end;
 WM_KEYDOWN:
            begin
                 if wParam = VK_SHIFT
                 then begin
                      if (GetKeyState(VK_TAB)=1) then
                      mEssageBox(0,0,0,MB_OK);
                 end;
            end;

 WM_DRAWITEM:
             begin
               TDC := CreateCompatibleDC(0);
               SelectObject(TDC, bmpUp);
               SetBkMode(PDRAWITEMSTRUCT(Lparam)^.hDC, TRANSPARENT);
               BitBlt(PDRAWITEMSTRUCT(Lparam)^.hDC,0,0,70,25,TDC, 0,0,SRCCOPY);
               DeleteDC(TDC)
             end;
 WM_LBUTTONDOWN:
                 begin
                   Rectangle(GetWindowDC(wnd),80,80, 120,120);
                 end;    
 WM_DESTROY:
            begin
              DeleteObject(bmpUp);
              PostQuitMessage(0);
              Result:=0;
              Exit;
            end;
  else Result:=DefWindowProc(wnd,msg,wparam,lparam);
 end;
End;

{Переменные xPos,yPos,nWidth,nHeight в принципе не нужны, однако я их завел
(и вам рекомендую) для лучшей читабельности программы}

var
 xPos,yPos,nWidth,nHeight : Integer;

begin //Тело программы
{  Далее идет заполнение шаблона класса окна}

wc.cbSize:=sizeof(wc);
wc.style:=cs_hredraw or cs_vredraw;
wc.lpfnWndProc:=@WindowProc;
wc.cbClsExtra:=0;

wc.cbWndExtra:=0;
wc.hInstance:=HInstance;
wc.hIcon:=LoadIcon(0,idi_application);
wc.hCursor:=LoadCursor(0,idc_arrow);
wc.hbrBackground:=COLOR_BTNFACE+1;
wc.lpszMenuName:=nil;
wc.lpszClassName:="WinMin : Main";
RegisterClassEx(wc); //Регистрация нового класса в системе

{"заполнение переменных xPos,yPos,nWidth,nHeight}

xPos:=100;
yPos:=150;
nWidth:=400;

nHeight:=250;

{ Создание главного окна}
MainWnd:=CreateWindowEx (
0,                    //флаги расширенных стилей
"WinMin : Main",    //имя класса окна, данное при заполнении структуры wc
"Win Min",          //заголовок окна
ws_overlappedwindow, //флаги стилей окна
{подробнdее о стилях см. после текста программы}
xPos,               //горизонтальная позиция окна
yPos,               //вертикальная позиция окна

nWidth,             //ширина окна
nHeight,            //высота окна
0,                  //описатель родительского окна (parent) или окна-владельца (owner)
0,                  //описатель меню окна (меню нет, нет и описателя)
Hinstance,          //описатель приложения
nil                 //address of window-creation data
);

Button1 := CreateWindow("BUTTON","_OK_", WS_CHILD or WS_VISIBLE or BS_OWNERDRAW, 10, 10, 70, 25, MainWnd, 0, HInstance, nil);

btnRgn := CreateEllipticRgn(10,10,30,25);

SetWindowRgn(Button1 ,  btnRgn, true);

ShowWindow(MainWnd,CmdShow); //Отображаем окно

While GetMessage(Mesg,0,0,0) do
begin
 TranslateMessage(Mesg);
 DispatchMessage(Mesg);
end;
end.


 
Игорь Шевченко ©   (2005-09-09 17:07) [4]

"The coordinates of a window"s window region are relative to the upper-left corner of the window, not the client area of the window. "


 
Nick Denry ©   (2005-09-09 17:15) [5]

Button1 := CreateWindow("BUTTON","_OK_", WS_CHILD or WS_VISIBLE or BS_OWNERDRAW, 10, 10, 70, 25, MainWnd, 0, HInstance, nil);

btnRgn := CreateEllipticRgn(10,10,30,25);

??

Игорь, объясни плиз в чем тут клиентские и оконные координаты?

имхо же все в оконных идет?


 
Игорь Шевченко ©   (2005-09-09 17:26) [6]

Nick Denry ©   (09.09.05 17:15) [5]


> Игорь, объясни плиз в чем тут клиентские и оконные координаты?


Вообще-то оконная координата левого верхнего угла окна равна нулю.


 
Nick Denry ©   (2005-09-09 18:30) [7]

Т.е. ты хочешь сказать, что регион должен создаваться как

btnRgn := CreateEllipticRgn(0,0,20,15);

?


 
Игорь Шевченко ©   (2005-09-09 18:32) [8]

Nick Denry ©   (09.09.05 18:30) [7]


> Т.е. ты хочешь сказать, что регион должен создаваться как
>


Вообще-то да :)


 
Nick Denry ©   (2005-09-09 19:22) [9]

Отсечения воспроизведения все равно не происходит.

Мне кажется, что

===
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 этих сообщения какая-то нестандартная обработка...


 
y-soft ©   (2005-09-09 20:08) [10]

>Nick Denry ©   (09.09.05 19:22) [9]

Все рисуется и обрабатывается (пример из книги Марко Канту, Тим Гуч с Джоном Ф. Лэм "Delphi. Руководство разработчика"):

http://y-soft.comsignal.ru/Delphi/DDHROUND_PAS.HTM


 
Nick Denry ©   (2005-09-09 22:09) [11]

Да , но с виндовой кнопкой почему-то не работает


 
Турист   (2005-09-09 23:59) [12]

Наверно, это все-таки неправильно


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-10 12:01) [13]

Да, последний вариант действительно работает...

интресно, в чем все-таки разница? :)


 
Турист   (2005-09-10 12:37) [14]

>Nick Denry ©   (10.09.05 12:01) [13]
>интресно, в чем все-таки разница? :)
Между чем ?


 
Nick Denry ©   (2005-09-13 00:21) [15]

Ну теперь собственно говоря между WS_POPUP +   Windows.SetParent(Button, Handle); и WS_CHILD;


 
Nick Denry ©   (2005-09-13 00:23) [16]

правда я с испугу свой контрол реализовал в Dll и CS_GLOBALCLASS :)

Впринципе, получилось даже интереснесней - поддержка 4 состояний и PNG :)


 
Игорь Шевченко ©   (2005-09-13 10:13) [17]

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_CLIPSIBLINGS or 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++, чем окна отличаются.


 
Игорь Шевченко ©   (2005-09-13 10:14) [18]

Удалено модератором
Примечание: Дубль


 
Nick Denry ©   (2005-09-13 13:03) [19]

2Игорь Шевченко ©   (13.09.05 10:13) [17]

Ага, вот теперь можно кричать, размахивать руками и говорить, я так и знал, я так и думал... :)

Я вот только теперь чего думаю, обратно на кнопки перейти и свой контрол выкинуть нафиг или не мучаться с суперклассированием?


 
Игорь Шевченко ©   (2005-09-13 13:20) [20]

Nick Denry ©   (13.09.05 13:03) [19]


> Я вот только теперь чего думаю, обратно на кнопки перейти
>


А я не знаю, что тебе требуется. Как назначить регион окну кнопки, вроде разобрались, причем тут саб/суперклассинг, я не совсем понимаю.


 
Nick Denry ©   (2005-09-13 13:42) [21]

Требуется компонент (не в дельфийском понятии этого слова :),

кнопка, имеющая след. параметры:

Графическа кнопка произвольной формы (задется маской), имеет четыре (т.е. три состояния, на каждое из которых отрисовывается своя картинка) -

1. Кнопка отжата (1ая картинка)
2. Кнопка нажата (2ая картика)
3. Мышь над (сотсюда суперклассинг, сообщние WM_MOUSEOVER, 3я картинка)

Так же при нажатии/отжатии/наведении кнопка менят цвет надписи, на 3 заданных.

+ Возможность назначить Шрифт, которым будет отрисовывться текст на кнопке.

Кнопка должна быть расположенна в множстве диалогов программы (в ресурсах, отсюда и CS_GLOBALclASS) и не должн быть размазанна по всму коду (т.е. код кнопки в проекте должен встречаться один раз (т.е. вроде как Dll)- в остльных модулях только создание, уничтожение и назначение свойств (я сделал через SetProp/GeProp).

Вопрос один и то наверное не существенный - сделать это а базе виндовой кнопки или как я - на баз обычного окна - имитирующего поведение кнопки.

Я не знаю, насколько использовние контролов (о, слово наконец-то вспомнил!) со стилем CS_GLOBALCLASS оправданно и безопасно....


 
Nick Denry ©   (2005-09-13 13:53) [22]

Игорь, а что такое
Win32Check((FButtonRgn <> 0) and (SetWindowRgn (FButton, FButtonRgn, true) <> 0));

Я первый раз такую конструкцию вижу...


 
Игорь Шевченко ©   (2005-09-13 14:37) [23]

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 19:01) [24]

на этапе инициализации 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-14 10:11) [25]


> А вот когда я на
> WM_DESTROY:
>           begin
> {             Освобождаю библиотеку}
>             FreeLibrary (controlDll); - то прога вызывает
> исключение, т.к. я так понимаю еще обращается к процедуре
> окна самого контрола, а тут библиотека как бы убирается.
> ..
>
>           end;


Во-первых, зачем библиотеку освобождать ?
Во-вторых, вызывается ли UnregisterClass в библиотеке при ее освобождении
В-третьих,  и самое главное:

ПОЧЕМУ ЛЮДИ НИКОГДА НЕ ПИШУТ ДЕТАЛЬНОЕ ОПИСАНИЕ ПРОБЛЕМЫ, НАПРИМЕР, КАКОЕ ИСКЛЮЧЕНИЕ У НИХ ВОЗНИКАЕТ ? У ОТВЕЧАЮЩИХ ЧАЩЕ ВСЕГО НЕТ ПЕРЕД ГЛАЗАМИ ЭКРАНА АВТОРА ВОПРОСА.

ЕСЛИ КТО ИЗ АВТОРОВ ВОПРОСОВ СЧИТАЕТ СЕБЯ ПАРТИЗАНОМ, ПОПАВШИМ В ГЕСТАПО И БУДЕТ ТЕРПЕТЬ ПЫТКИ, НО НЕ ВЫДАСТ ВОЕННУЮ ТАЙНУ, ЭТО ЕГО, АВТОРА ВОПРОСА, ЛИЧНЫЕ ПРОБЛЕМЫ И ШАНСЫ ЕГО ПОЛУЧИТЬ ПОМОЩЬ РЕЗКО УМЕНЬШАЮТСЯ.

Извиняюсь за крик, наболело.


 
Nick Denry ©   (2005-09-14 20:04) [26]

Во-вторых, вызывается ли 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   Отмена  
---------------------------



Страницы: 1 вся ветка

Форум: "WinAPI";
Текущий архив: 2005.11.13;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.55 MB
Время: 0.042 c
2-1130050454
beglec
2005-10-23 10:54
2005.11.13
Можно ли узнать имя процедуры.


2-1129229041
illy
2005-10-13 22:44
2005.11.13
Реестр


3-1127824564
Andy_new
2005-09-27 16:36
2005.11.13
Возможен ли Sum по условию


14-1129729150
lightix
2005-10-19 17:39
2005.11.13
QuickReport у не нравится лазерный принтер samsung


4-1126694897
Донской
2005-09-14 14:48
2005.11.13
ЗАпуск приложения от имени...





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский