Модераторы: feodorv, GremlinProg, xvr, Fixin
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Вопрос про субклассинг 
:(
    Опции темы
yngwie19
Дата 20.5.2009, 00:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 829
Регистрация: 15.6.2008
Где: Новгород

Репутация: нет
Всего: нет



Здравствуйте! В книге Петзольда описывается субклассинг вот на каком примере:
Есть главное окно, в нем создано дочернее окно с классом "scrollbar". У каждого окна есть оконная процедура (я так полагаю что и у окна класса scrollbar тоже). В книге описывается механизм замены оконной процедуры класса scrollbar на свою, для этого делают слежующее:
Код

WNDPROC MyProc;
LRESULT CALLBACK MyProc(HWND,UINT,WPARAM,LPARAM)
int WINAPI WinMain(........)
{
.................
HWND hwndScroll = CreateWindow("scrollbar",NULL,WS_CHILD............);
SetWindowLong(hwndScroll,GWL_WNDPROC,(LONG)MyProc);
.......
return 0;

LRESULT CALLBACK MyProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
      switch(msg)
      {
           case WM_....
                 return 0;
           case ...........
      }
      return CallWindowProc(hwnd,msg,wParam,lParam);
}

}

вот как-то так. У меня вопрос вот в чем, правильно ли Я понимаю, что без субклассинга окно scrollbar обрабатывается в оконной процедуре родительского окна через сообщение WM_VSROLL или WM_HSCROLL соответсвенно, т.е по умолчанию заложего так. А если мы меняем адрес этой процедуры на свою, то она обрабатывается той оконной процедурой, которую мы для нее описали. А если необходимо чтобы какие-то сообщения посылаемые этому окну (scrollbar- у ) обрабатывались процедурой "по-умолчанию", то мы вызываем CallWindowProc() и передаем ей все необходимые параметры. Правильно ли Я понял суть?
PM MAIL   Вверх
mes
Дата 20.5.2009, 00:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 1
Всего: 250



Цитата(yngwie19 @  19.5.2009,  23:06 Найти цитируемый пост)
если мы меняем адрес этой процедуры на свою, то она обрабатывается той оконной процедурой, которую мы для нее описали. А если необходимо чтобы какие-то сообщения посылаемые этому окну (scrollbar- у ) обрабатывались процедурой "по-умолчанию", то мы вызываем CallWindowProc() и передаем ей все необходимые параметры.

Вобще то правильней не "процедурой по умолчанию", а предыдущей оконой функцией и  в примере Вы забыли запомнить эту предыдущую функцию (через GetWindowLong)  и в дальнейшем вызвать ее в CallWindowProc :
Цитата(yngwie19 @  19.5.2009,  23:06 Найти цитируемый пост)
      return CallWindowProc(hwnd,msg,wParam,lParam);

обратите внимание на первый параметр : http://msdn.microsoft.com/en-us/library/ms633571.aspx

Это сообщение отредактировал(а) mes - 20.5.2009, 00:18


--------------------
PM MAIL WWW   Вверх
yngwie19
Дата 20.5.2009, 07:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 829
Регистрация: 15.6.2008
Где: Новгород

Репутация: нет
Всего: нет



mes, ну да точно совсем забыл, ну а вообще правильно ли Я все понял?
меня вот что интересует, любое дочернее  окно по умолчанию обрабатывается оконной процедурой окна родителя так? а если этот контрол у нас создан в диалоговом окне, то тут можно также менять адрес процедуры на другой?
PM MAIL   Вверх
Cheloveck
Дата 20.5.2009, 07:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1578
Регистрация: 26.7.2008
Где: Тула

Репутация: 1
Всего: 32



Цитата(yngwie19 @  20.5.2009,  08:20 Найти цитируемый пост)
любое дочернее  окно по умолчанию обрабатывается оконной процедурой окна родителя так?

нет, не так. У любого окна, дочернего или главного... есть своя процедура обработки. Разница лишь в том, что дочерние окна извещают своих родителей о своих изменениях и статусах...

Добавлено через 2 минуты и 52 секунды
Цитата(mes @  20.5.2009,  01:17 Найти цитируемый пост)
Вы забыли запомнить эту предыдущую функцию (через GetWindowLong)

Более правильно запомнить результат функции SetWindowLong - она вернёт предыдущую процедуру.



--------------------
user posted image
PM Jabber   Вверх
Earnest
Дата 20.5.2009, 07:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 33
Всего: 183



Цитата(yngwie19 @  20.5.2009,  08:20 Найти цитируемый пост)
любое дочернее  окно по умолчанию обрабатывается оконной процедурой окна родителя так?

Совсем нет. У каждого окна своя процедура. 
В родительское окно дочернее посылает различные уведомления (такие как WM_COMMAND, WM_NOTIFY, WM_DRAWITEM, ..., скролл-бары посылают WM_SCROLL). А обрабатываемых сообщений сотни.

Кроме того, скролл-бары не обязательно являются окнами. Иногда - это просто часть неклиентской области. Например у окон со стилем WS_SCROLL.



--------------------
...
PM   Вверх
yngwie19
Дата 20.5.2009, 08:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 829
Регистрация: 15.6.2008
Где: Новгород

Репутация: нет
Всего: нет



Earnest
Цитата(Earnest @  20.5.2009,  07:40 Найти цитируемый пост)
Совсем нет. У каждого окна своя процедура. 

ну т.е у всех окон своя оконная процедура,  которая по умолчанию описана так (например для ScrollBar - a  ):
Код

LRESULT CALLBACK ScrollBar(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
      return CallWindowProc('адрес процедуры окна родителя',hwnd,msg,wParam,lParam)
}


Правильно Я понял, т.е она ничего не делает кроме как вызывает оконную функцию окна родителя и передает ей параметры?
PM MAIL   Вверх
mes
Дата 20.5.2009, 09:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 1
Всего: 250



Цитата(Cheloveck @  20.5.2009,  06:36 Найти цитируемый пост)
Более правильно запомнить результат функции SetWindowLong - она вернёт предыдущую процедуру.

точно, подзабыл.. 100 лет не программил на WinApi.

Цитата(yngwie19 @  20.5.2009,  07:33 Найти цитируемый пост)
'адрес процедуры окна родителя'

нет, процедура родителя (а в WinApi  этому званию соответствует окно, на котором создали дочернее) не вызывается. 

Цитата(Cheloveck @  20.5.2009,  06:36 Найти цитируемый пост)
Разница лишь в том, что дочерние окна извещают своих родителей о своих изменениях и статусах...

Т.е родитель "насладжается" лишь получаемыми сообщениями и никакого другого контакта.

Каждое окно вызывает оконную процедуру предка по наследованию т.е есть главная процедура всех окон DefWindowProc ()
от нее (не важна на прямую или через посредников) отнаследованы:
 DefDialogWindowProc - которую в конечном итоге должен вызвать контрол желающий быть диалогом
 DefScrollBarProc () - которую вызывают скролы,
 DefTextCtrlProc () - ..
и так далее.
(названия даны условны, и с истинами именами могут не совпадать)

При создании нового типа окна, в оконной процедуре мы вызываем DefWindowProc, a при субклассировании фактически создается стек окон процедур, обеспечивающий наследованное поведение,
условно такоe :
MyWindowProc -> SavedWindowProc () -> ScrolledWindowProcEx () -> ScrolledWindowProc() -> DefScrollWindowProc ();

Цитата(yngwie19 @  20.5.2009,  06:20 Найти цитируемый пост)
а если этот контрол у нас создан в диалоговом окне, то тут можно также менять адрес процедуры на другой? 

Разницы нет кто впоследствии будет родителем, важно от кого отнаследовано.



P.S. в winApi получается игра слов, упомяннутая выше, поэтому еще раз уточню.
грубо:
предок при субклассировании -  окно (его процедура), от которого мы перенимаем поведение - наследуемся.
родитель - окно на котором мы расположим дочернее.
эти два понятия не смотря на родственное созвучие и в некоторых случаях могут называться одним и тем же словом, но обозначают совершенно разные (по отношению к рассматриваемому) окна. 





Это сообщение отредактировал(а) mes - 20.5.2009, 09:16


--------------------
PM MAIL WWW   Вверх
yngwie19
Дата 20.5.2009, 10:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 829
Регистрация: 15.6.2008
Где: Новгород

Репутация: нет
Всего: нет



mes, да что-то не очень понятно, запутано очень или надо кертинку рисовать. Можно где-нибудь на русском про это почитать?
PM MAIL   Вверх
GremlinProg
Дата 20.5.2009, 11:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2706
Регистрация: 9.8.2005
Где: Тюмень

Репутация: 99
Всего: 106



все будет гораздо проще, если представить оконную процедуру как полиморфное перекрытие класса:
Код

class CScrollBar{
  virtual LRESULT WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){
    ...
  }
};

тогда субклассинг - это наследование нового класса CMyScrollBar от CScrollBar, с перекрытием главного метода класса:
Код

class CMyScrollBar: public CScrollBar{
  virtual LRESULT WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){
    return CScrollBar::WndProc(...);
  }
};

я уже приводил похожий пример,
return CScrollBar::WndProc(...) - равнозначно CallWindowProc('адрес процедуры окна предка',...)
слово родитель тут совсем не к месту, это предок, т.е. класс окна от которого производится субклассинг
здесь можно вполне легально использовать термины ООП: инкапсуляция, наследование, полиморфизм

хотя полновестное значение тут имеет только термин полиморфизм, т.е. перекрытие WndProc в потомке (CMyScrollBar)
чтобы было еще и наследование, субклассинг должен осуществляться еще при регистрации класса окна, т.е. до создания окна (но такой способ перекрытия процедуры окна обычно так и называют: наследование, т.е., помимо доступа к процедуре предка, мы имеем инкапсулированные данные окна и/или класса предка)

yngwie19, если понимаешь смысл основных инструментов ООП (инкапсуляция, наследование, полиморфизм), то и с субклассингом все должно быть понятно
если нет, то можешь найти достаточно информации на эту тему в других разделах C/C++


--------------------
"Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины."
PM WWW ICQ   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Системное программирование и WinAPI"
Fixin
GremlinProg
xvr
feodorv
  • Большое количество информации и примеров с использованием функций WinAPI можно найти в MSDN
  • Описание сообщений, уведомлений и примеров с использованием компонент WinAPI (BUTTON, EDIT, STATIC, и т.п.), можно найти в MSDN Control Library
  • Непосредственно, перед созданием новой темы, проверьте заголовок и удостоверьтесь, что он отражает суть обсуждения.
  • После заполнения поля "Название темы", обратите внимание на наличие и содержание панели "А здесь смотрели?", возможно Ваш вопрос уже был решен.
  • Приводите часть кода, в которой предположительно находится проблема или ошибка.
  • Если указываете код, пользуйтесь тегами [code][/code], или их кнопочными аналогами.
  • Если вопрос решен, воспользуйтесь соответствующей ссылкой, расположенной напротив названия темы.
  • Один топик - один вопрос!
  • Перед тем как создать тему - прочтите это .

На данный раздел распространяются Правила форума и Правила раздела С++:Общие вопросы .


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Chipset, Step, Fixin, GremlinProg, xvr. feodorv.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Системное программирование и WinAPI | Следующая тема »


 




[ Время генерации скрипта: 0.0826 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.