LINUX.ORG.RU

В оффтопике — сабклассинг, а в Qt/GTK/etc... что?


0

0

Собственно, интересует, какие механизмы используются в широко распространённых графических библиотеках для изменения поведения контролов? Если не трудно, опишите, pls, их вкратце, что там, да как.

Если сабклассинг — это то, о чём я думаю, то, не поверишь, такие же (даже в Gtk+).

Sphinx ★★☆☆
()

Рискну предположить что имеется ввиду наследование

imp ★★
()

Ну, сабклассинг для окна в общем -- это подмена функции, разгребающей приходяшие события, на свою.

one_more_hokum ★★★
() автор топика
Ответ на: комментарий от anonymous

То-есть, я наследуюсь от виджета, перенастраиваю сигнал, например, его отрисовки, на свою функцию, и в этой функции руками рисую то, что хочу?

one_more_hokum ★★★
() автор топика
Ответ на: комментарий от one_more_hokum

для Qt
------

void QObject::installEventFilter ( QObject * filterObj )

Installs an event filter filterObj on this object. For example:

 monitoredObj->installEventFilter(filterObj);

An event filter is an object that receives all events that are sent 
to this object. The filter can either stop the event or forward it to 
this object. The event filter filterObj receives events via its 
eventFilter() function. The eventFilter() function must return true 
if the event should be filtered, (i.e. stopped); otherwise it must 
return false.
If multiple event filters are installed on a single object, the 
filter that was installed last is activated first.

Here's a KeyPressEater class that eats the key presses of its 
monitored objects:

     class KeyPressEater : public QObject
     {
         Q_OBJECT
         ...

     protected:
         bool eventFilter(QObject *obj, QEvent *event);
     };

     bool KeyPressEater::eventFilter(QObject *obj, QEvent *event)
     {
         if (event->type() == QEvent::KeyPress) {
             QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
             qDebug("Ate key press %d", keyEvent->key());
             return true;
         } else {
             // standard event processing
             return QObject::eventFilter(obj, event);
         }
     }

And here's how to install it on two widgets:

     KeyPressEater *keyPressEater = new KeyPressEater(this);
     QPushButton *pushButton = new QPushButton(this);
     QListView *listView = new QListView(this);

     pushButton->installEventFilter(keyPressEater);
     listView->installEventFilter(keyPressEater);

alex_custov ★★★★★
()
Ответ на: комментарий от alex_custov

То-есть, "отобрать сигнал" у окна, и обработать его самостоятельно -- обычная практика у графических тулкитов?

one_more_hokum ★★★
() автор топика
Ответ на: комментарий от one_more_hokum

> То-есть, "отобрать сигнал" у окна, и обработать его самостоятельно -- обычная практика у графических тулкитов?

Нет. Приведенный alex_custov (06.06.2008 18:45:16) пример не имеет отношения к отрисовке, там именно "перехват" функции, "разгребающей события".

Обычный путь в любой ООПшной ГУЙне -- наследоваться и перекрыть соответствующий каллбэк.

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

Обычный путь в Qt -- наследоваться от виджета и перекрыть "слот", ответственный за обработку соответствующего "сигнала". Можно также перекрывать "события" типа отрисовки, получения фокуса, итп.

Die-Hard ★★★★★
()
Ответ на: комментарий от one_more_hokum

Интересно стало, нагуглил про сабклассинг:

http://www.silicontaiga.ru/home.asp?artId=6476

Да, пример alex_custov (06.06.2008 18:45:16) примерно соответствует частному случаю "сабклассинга", но такое годится только для тех систем, где все управление построенно на событиях, т.е. ниже обычных виджетных библиотек, которые системные события обычно скрывают (иначе портабильность потеряется).

Как правило, все библиотеки виджетов (не только ООПшные) напрямую дергают виджетные каллбэки, это гораздо быстрее и проще, чем пользоваться только своей системой событий (хотя и свою систему событий они тоже обычно строят).

Die-Hard ★★★★★
()
Ответ на: комментарий от one_more_hokum

> ...callback-функции есть зло. Только обоснования не помню.

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

Поэтому Тролли в Qt их завернули в "сигнал-слот" механизм, который не даст "забыть" про каллбэк: хоть упишись каллбэками, пока "слот" с "сигналом" не "соединен", выплеск сигнала просто "растворится в киберпространстве" (Троллтеховское выражение).

Кроме того, если (как в Виндовсе) всем доступна очередь событий, каллбэки разрушают этот самый "сабклассинг".

Die-Hard ★★★★★
()
Ответ на: комментарий от one_more_hokum

>>То-есть, "отобрать сигнал" у окна, и обработать его самостоятельно -- обычная практика у графических тулкитов?

не сигнал, а событие (в терминах Qt). Не знаю по поводу обычности, но если тулкит предоставляет такие возможности, они рано или поздно будут использованы.

alex_custov ★★★★★
()
Ответ на: комментарий от Die-Hard

>>Обычный путь в Qt -- наследоваться от виджета и перекрыть "слот", ответственный за обработку соответствующего "сигнала". Можно также перекрывать "события" типа отрисовки, получения фокуса, итп.

опять же не слот а обработчик события, который всегда виртуальный. В отличие от слота, который почти всегда не виртуальный. К тому же именно отрисовка распространяется как событие, сигналами распространяются обычно высокоуровневые события, относящиеся к конкретному классу (смена активной вкладки, запрос контекстного меню и т.д.).

alex_custov ★★★★★
()
Ответ на: комментарий от Die-Hard

>>Обоснование простое: каллбэки не вписываются в ООП инкапсуляцию

кстати вы слышали последние новости, что в C++ нет инкапсуляции ? :D

alex_custov ★★★★★
()
Ответ на: комментарий от alex_custov

> перекрыть "слот", ответственный за обработку соответствующего "сигнала".

Да, тут я чушь написал, слоты не перекрывают. Давно с Кутями дела не имел...

> В отличие от слота, который почти всегда не виртуальный. К тому же именно отрисовка распространяется как событие, сигналами распространяются обычно высокоуровневые события, относящиеся к конкретному классу (смена активной вкладки, запрос контекстного меню и т.д.).

Верно все, согласен. Именно "сабклассинг" в чистом виде.

Die-Hard ★★★★★
()
Ответ на: комментарий от alex_custov

> Обычный путь в Qt -- наследоваться от виджета и перекрыть "слот", > ответственный за обработку соответствующего "сигнала". Можно также > перекрывать "события" типа отрисовки, получения фокуса, итп.

Чёт Вы не так пишете. Хоть и поправились, но как-то всё равно туманно осталось. Для перекрытия слота НЕ НУЖНО наследоваться. Нужно всего лишь создать экземпляр класса и ПОДКЛЮЧИТЬ к нему сигнал, вызвав connect,

http://doc.trolltech.com/3.0/qobject.html#connect-2

Причём, отношение "сигнал-слот" - это отношение "много ко многим".

Но (плюс к тому), есть и виртуальные функции. Если нужно поменять их функционал, то не обойтись без наследования. Не знаю, зачем это, но предполагаю, что это из-за того, что сигналы работают медленнее виртуальных функций. А может быть, для того, чтобы был какой-то функционал "по умолчанию", без всяких вызовов connect.

den73 ★★★★★
()
Ответ на: комментарий от den73

>>Но (плюс к тому), есть и виртуальные функции. Если нужно поменять их функционал, то не обойтись без наследования. Не знаю, зачем это, но предполагаю, что это из-за того, что сигналы работают медленнее виртуальных функций.

Потому что сигналы и события разные вещи, правильно сделали что их разделили. Для удобства все стандартрные события разбрасываются сначала по фильтрам, потом по виртуальным методам. Так что, чтобы словить событие нужно просто переопределить метод.

Сигналы как я уже писал, это совсем другой уровень не только абстракции, но и реализации.

Нет, сигналы работают быстрее событий, даже если последние посылаются с максимальным приоритетом. По моим замерам, суммарное время получения одного сигнала подключённого к восьми слотам приблизительно одинаково с приходом ОДНОГО своего события (QEvent::User+N) в один обработчик. Очереди событий не самый лучший способ посылать уведомления, т.к. время прохождения события по очереди зависит от тысячи и одного фактора.

alex_custov ★★★★★
()
Ответ на: комментарий от den73

> Чёт Вы не так пишете.

Я вообще чушь написАл -- просто забыл, несколько лет с Qt не работал.

> Для перекрытия слота НЕ НУЖНО наследоваться. Нужно всего лишь создать экземпляр класса и ПОДКЛЮЧИТЬ к нему сигнал, вызвав connect,

Во-первых, связь сигнала со слотом никоим образом не "перекрытие", это всего лишь "использование". Кстати, связать сигнал можно не только со слотами, но и с другими сигналами.

Во-вторых, никто не мешает перекрывать слоты при наследовании и никто не мешает делать их виртуальными, так что вся та чушь, что что я написал выше, в принципе правильная и работоспособная, просто так обычно не делают.

> Но (плюс к тому), есть и виртуальные функции. Если нужно поменять их функционал, то не обойтись без наследования. Не знаю, зачем это, но предполагаю, что это из-за того, что сигналы работают медленнее виртуальных функций.

Виртуальные функции и слот-сигналы -- понятия совершенно независимые. Как я уже писАл, слот может быть виртуальным. А нужны виртуальные функции для реализации полиморфизма.

Die-Hard ★★★★★
()
Ответ на: комментарий от alex_custov

> Нет, сигналы работают быстрее событий, даже если последние посылаются с максимальным приоритетом.

den73 писАл не про очереди, а о том, что "...сигналы работают медленнее виртуальных функций", и в этом свысле он прав: по утверждению троллей, время вызова слота при генерации сигнала в среднем раз в 10 дольше, чем непосредственный вызов _не_виртуального метода. Поскольку вызов виртуального метода дольше прямого вызова раза в полтора, получается, что вызов слота дольше вызова виртуальной фуккции раз в 6-8. Но к очередям событий это отношения не имеет.

Die-Hard ★★★★★
()
Ответ на: комментарий от alex_custov

> я так понял он имел ввиду вирт.функции-обработчики событий

Ну, может, и так -- действительно, разговор про это шел... Только как-то странно обзывать "обработчик событий" термином "виртуальная функция". Кстати, для кастомного рисования виджетов иногда перекрываются различные виртуальные рисовалки, не являющиеся обработчиками событий, а такие звери, как show() и hide() в Qt -- вообще виртуальные слоты. И даже иногда перекрываются в самом Qt!

Die-Hard ★★★★★
()
Ответ на: комментарий от Die-Hard

>>Только как-то странно обзывать "обработчик событий" термином "виртуальная функция"

потому что обработчик события, если он существует, всегда виртуален. Я кажется уже говорил ;)

>>а такие звери, как show() и hide() в Qt -- вообще виртуальные слоты

неверно. Невиртуальные. Я кажется это тоже говорил ;)

>>И даже иногда перекрываются в самом Qt!

show() и hide() нигде не перекрываются ;)

alex_custov ★★★★★
()
Ответ на: комментарий от alex_custov

>>Только как-то странно обзывать "обработчик событий" термином "виртуальная функция"

>потому что обработчик события, если он существует, всегда виртуален. Я кажется уже говорил ;)

"Виртуальная функция" _значительно_ шире, нежели "обработчик событий".

>>а такие звери, как show() и hide() в Qt -- вообще виртуальные слоты

>неверно. Невиртуальные. Я кажется это тоже говорил ;)

Ну, это не вопрос для дискуссии... Обратимся к первоисточникам:

http://doc.trolltech.com/3.0/qwidget.html

Public Slots

virtual void show ()

virtual void hide ()

> show() и hide() нигде не перекрываются ;)

И вновь бесспорные авторитеты ставят в дискуссии точку:

http://doc.trolltech.com/3.0/qwidget.html#show

void QWidget::show () [virtual slot]

. . .

Reimplemented in QDialog and QMenuBar.

Да, в четвертых Qt они от этого отказались, видимо, дабы не вводить во искушение -- тем самым похерив всю совместимость -- но в первых, вторых и третьих Qt Тролли сами вовсю следовали этой практике. И даже в четверке они оставили в qWidget один виртуальный слот, virtual void setVisible( bool ); (наверное, чтобы при переходе к пятерке добавить геммороя разработчикам). Более того, этот текст: http://doc.trolltech.com/4.4/signalsandslots.html остался: "You can also define slots to be virtual, which we have found quite useful in practice."

Die-Hard ★★★★★
()
Ответ на: комментарий от Die-Hard

>>"Виртуальная функция" _значительно_ шире, нежели "обработчик событий"

ну это понятно, просто дискуссия велась как раз про события, вот я и решил..

>>3.0

Эээээ... :) Уже как бы 4.4 вышла, я думал мы Qt4 обсуждаем by default ;)

>>"You can also define slots to be virtual, which we have found quite useful in practice."

Ну да, это понятно. Я говорил про стандартные слоты из Qt-шных классов, которые делать виртуальными особого смысла нет.

alex_custov ★★★★★
()
Ответ на: комментарий от alex_custov

> Эээээ... :) Уже как бы 4.4 вышла, я думал мы Qt4 обсуждаем by default ;)

Ну, мое последнее столкновение с Qt было в инкарнации 2.0 -- после этого я понял, что в жизни есть более интересные дела, нежели погоня за их паровозом: меня вполне устраивает Qt 1.44, и я не понимаю причин, по которым я должен раз в 2 года переписывать свои программы с нуля... Нынешнее бедственное положение четвертой КДЕ ИМХО этот тезис подтверждает.

>>>"Виртуальная функция" _значительно_ шире, нежели "обработчик событий"

>ну это понятно, просто дискуссия велась как раз про события, вот я и решил..

Кстати, подумалось вдруг: а с чего обработчики событий _всегда_ должны быть виртуальными? С этой точки зрения они ничем от слотов не отличаются. Даже более того, Тролли практически не предоставляют возможности вмешиваться в их очереди, поэтому логично было бы сделать обработчики _не_виртуальными, но дергающими, скажем, три "стандартных" виртуальных кирпича ("префикс", "обработка", "суффикс"). Чисто теоретически, именно такая модель обычно часто рассказывалась студентам при объяснении полиморфизма: например, обработчик события move для "саморисующегося" полиморфика выглядит как

(virtual) hide();

(virtual) recalculatePosition(event *);

(virtual) show();

Теперь объявляем этот обработчик приватным, и получаем реализованную мечту апологета ООП: никто не сможет унаследоваться от класса "неправильно".

Die-Hard ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.