Russian Qt Forum
Ноябрь 25, 2024, 16:54 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: 1 [2] 3   Вниз
  Печать  
Автор Тема: Специализированные шаблоны для контролов Qt  (Прочитано 19483 раз)
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #15 : Апрель 18, 2015, 08:56 »

Мне это может сэкономить день (с учетом поиска вариантов обхода, которых может быть и не существует), а отвечающему - занять несколько минут.
Так ведь и другие (включая меня) думают так же: "та оно мне надо чего-то "изыскивать", экспериментировать? Вот найти пример и сделать по образцу - то да". Qt очень поощряет такой потребительский подход, ведь практически он очень эффективен. Почему-то вспоминается "Незнайка на Луне" как они там в конце все собирались строить лодку чтобы бежать с острова  Улыбающийся

Ну ладно, не проходит так не проходит. Тогда может быть так
Код
C++ (Qt)
class MyLineEdit : public QLineEdit {
Q_OBJECT
public:
 MyLineEdit( QWidget * parent ):
 
#include MySlotSignals.h
};
Так придется написать для каждого базового контрола - ну не беда, это всего неск строк. А в MySlotSignals рисуете общие слоты-сигналы. Если надо перенаправляете их на чистые виртуалы. И тогда уже
Код
C++ (Qt)
template <class T>
class MyControl <T> : public T {
..
};
 
Но тут нет общего базового класса выше QWidget. Напр
Код
C++ (Qt)
MyControl <MyLineEdit> * cnt1 = new...
MyControl <MyTextEdit> * cnt2 = new ...
Можно пользоваться только методами QWidget - и все.
Записан
Гурман
Гуру общения
******
Offline Offline

Сообщений: 1442

Qt 2.2, 3.3, 4.5, 4,7, 4.8, 5.3, 5.6, 5.9, 5.12


Просмотр профиля
« Ответ #16 : Апрель 19, 2015, 15:59 »

Грубо, безобразно, хак - но так работает. Так я вообще с первого раза сделал, еще до своего первого поста в этой ветке. Просто не стал тут грубить. Даже шаблоны не нужны - просто в инклюд улетел добрый кусок класса контрола, вместе с методами получения событий мыши. В результате, например, объявление класса кнопки стало выглядеть вот так:

Код:
#ifndef WBUTTON_H
#define WBUTTON_H

#include "wcinculdes.h"
#include <QPushButton>

typedef QPushButton SuperClass;

class WButton : public SuperClass, public PluginInterface
{
    Q_OBJECT
    Q_INTERFACES( PluginInterface )

#include "wcontrol.h"  // всё общее для разных контролов

    ...... здесь объявления специализированных методов кнопки

};

PluginInterface тут, поскольку каждый контрол сидит в Qt-плагине
Записан

2^7-1 == 127, задумайтесь...
vregess
Гость
« Ответ #17 : Апрель 19, 2015, 18:09 »

Почему бы вместо typedef и include не обернуть общий функционал в макрос по аналогии с макросами Qt? Будет легче понять, что происходит.
Это в принципе не особо и хак, просто workaround для MOC.

Код
C++ (Qt)
#include "common_controls.h"
#include <QPushButton>
 
class WButton : public QPushButton, public PluginInterface
{
   Q_OBJECT
   Q_INTERFACES( PluginInterface )
   COMMON_CONTROL(QPushButton)
public:
   ...
}
 
// common_controls.h:
 
#define  COMMON_CONTROL(BaseClass) \
signals: \
   void mySignal(); \
\
public slots: \
   void someSlot() \
   { \
       ##BaseClass::bla(); \
   }
 
Записан
Гурман
Гуру общения
******
Offline Offline

Сообщений: 1442

Qt 2.2, 3.3, 4.5, 4,7, 4.8, 5.3, 5.6, 5.9, 5.12


Просмотр профиля
« Ответ #18 : Апрель 19, 2015, 20:13 »

Почему бы вместо typedef и include не обернуть общий функционал в макрос по аналогии с макросами Qt? Будет легче понять, что происходит.
Это в принципе не особо и хак, просто workaround для MOC.

Код
C++ (Qt)
#include "common_controls.h"
#include <QPushButton>
 
class WButton : public QPushButton, public PluginInterface
{
   Q_OBJECT
   Q_INTERFACES( PluginInterface )
   COMMON_CONTROL(QPushButton)
public:
   ...
}
 
// common_controls.h:
 
#define  COMMON_CONTROL(BaseClass) \
signals: \
   void mySignal(); \
\
public slots: \
   void someSlot() \
   { \
       ##BaseClass::bla(); \
   }
 

Потому что такие макросы практически невозможно отлаживать. GDB и QtCreator на них колдобятся. В случае инклюда и точки останова работают, и переменные можно просматривать. И не надо каждый раз при добавлении или удалении qDebig() чего-то добавлять или удалять. И вообще править такие макросы неудобно (я в других местах использовал, наплевался уже).

А функционально результат почти не отличается, даже хуже - надо в двух местах родительский класс контрола указывать, можно ошибиться.
« Последнее редактирование: Апрель 19, 2015, 20:28 от Гурман » Записан

2^7-1 == 127, задумайтесь...
vregess
Гость
« Ответ #19 : Апрель 19, 2015, 21:26 »

Потому что такие макросы практически невозможно отлаживать. GDB и QtCreator на них колдобятся. В случае инклюда и точки останова работают, и переменные можно просматривать. И не надо каждый раз при добавлении или удалении qDebig() чего-то добавлять или удалять. И вообще править такие макросы неудобно (я в других местах использовал, наплевался уже).

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

С отладкой да, есть недостаток.
Ну а что если вместо наследования использовать агрегирование (навроде pimpl)?

Код
C++ (Qt)
#define COMMON_CONTROL(BaseClass, DerivedClass) \
private:                                        \
   friend class Impl<BaseClass, DerivedClass>; \
   Impl<BaseClass, DerivedClass> *commonImpl;  \
   void initCommonImpl()                       \
   {                                           \
       commonImpl = new Impl<BaseClass, DerivedClass>(this); \
   }                                           \
signals:                                        \
   void mySignal();                            \
                                               \
public slots:                                   \
   void mySlot()                               \
   {                                           \
       commonImpl->mySlot();                   \
   }
 
 
template<typename Base, typename Derived>
class Impl
{
public:
   Impl(Derived *parent): m_parent(parent) {}
   virtual ~Impl() {}
 
   void mySlot()
   {
       reinterpret_cast<Base*>(m_parent)->mySlot();
   }
 
private:
   Derived *m_parent;
};
 
class WButton: public QPushButton, public PluginInterface
{
   Q_OBJECT
   Q_INTERFACES( PluginInterface )
   COMMON_CONTROL(QPushButton, WButton)
public:
  WButton() { initCommonImpl(); }
};
 

+ не забыть удалить commonImpl (можно обернуть в умный указатель).
Записан
Гурман
Гуру общения
******
Offline Offline

Сообщений: 1442

Qt 2.2, 3.3, 4.5, 4,7, 4.8, 5.3, 5.6, 5.9, 5.12


Просмотр профиля
« Ответ #20 : Апрель 19, 2015, 21:39 »

А это уже в гамаке и стоя, при том, что преимуществ не видно.
Записан

2^7-1 == 127, задумайтесь...
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #21 : Апрель 20, 2015, 07:53 »

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

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

Я не вижу ничего страшного в таком инклуде, но вот если они начнут "расползаться", т.е. если их появится 2 и больше - тогда хана. Это может случиться если понадобится метод(ы) базового контрола которых нет у других, или наоборот. Напр setValue для QLineEdit. Тогда все-таки придется нырять в шаблоны. Ну а если такой проблемы нет, то и слава богу, меньше template-гадости = лучше  
Записан
vregess
Гость
« Ответ #22 : Апрель 20, 2015, 08:00 »

А это уже в гамаке и стоя, при том, что преимуществ не видно.

Это смотря где ты ищешь преимущества. По мне преимущество только архитектурное: хоть какая-то инкапсуляция и возможность расширения (не факт, что ей придется воспользоваться); но писанины больше. include внутри класса - явный хак. Вообще, мне кажется, наследование здесь не лучший вариант, возможно с отдельным классом получится удачнее. Но хозяин-барин, решать все-равно тебе.

pimpl для того чтобы расписывать "для каждого", а здесь наоборот, нужно "для всех" (общая часть)

Поэтому и добавил "навроде". pimpl  упомянут только чтобы показать направление реализации.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #23 : Апрель 20, 2015, 08:42 »

Вообще, мне кажется, наследование здесь не лучший вариант, возможно с отдельным классом получится удачнее. Но хозяин-барин, решать все-равно тебе.
Поясню проблему как я ее понимаю (а ТС если надо поправит). Напрашивается так
Код
C++ (Qt)
class MyLineEdit : public QLineEdit, public Common
 
Здесь мы можем получить виджет имея Common, но "не наоборот". Пример: вызван слот QLineEdit'а, как Common может на это среагировать? Никак, потому что QLineEdit "не наш". Придется в Common делать членом указатель на QObject, мапировать сигналы QLineEdit на него и там уже вызывать обработчик Common. Ну это какая-то каракатица  Плачущий

Часто (и в этом топике) звучит, мол, "ах, вот если бы поддерживалось множественное наследование от QObject...". - тогда и проблем бы никаких не было. Не вижу что это особо меняет. Ну хорошо, допустим Common унаследован от QObject (предположим так можно). И что с того? Сигнал-то получает QLineEdit - а совсем не Common, проблемы те же
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #24 : Апрель 20, 2015, 10:02 »

Здесь мы можем получить виджет имея Common, но "не наоборот".
Не знаю о чем вы говорите, но новый виджет содержит в себе Common, а Common имеет указатель на виджет, для удобства доступа.

Пример: вызван слот QLineEdit'а, как Common может на это среагировать? Никак, потому что QLineEdit "не наш".
Опять же не знаю, кто там наш/не наш. Предлагалось вынести в common код общих методов и вызывать его из слотов самого виджета:
Код
C++ (Qt)
class MyLineEdit : public QLineEdit, public Common
{
public:
   ...
 
private slots:
   void    onTextChanged( const QString &val )
   {
       commonMethodText( val );
   }
 
   void    onReturnPressed()
   {
       commonMethodReturn();
   }
};
 

А эти слоты можно попробовать завернуть в макросы.
« Последнее редактирование: Апрель 20, 2015, 10:47 от Old » Записан
Гурман
Гуру общения
******
Offline Offline

Сообщений: 1442

Qt 2.2, 3.3, 4.5, 4,7, 4.8, 5.3, 5.6, 5.9, 5.12


Просмотр профиля
« Ответ #25 : Апрель 20, 2015, 14:57 »

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

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

Не выход, а вариант. По вопросам веры надо идти в церковь. Вариант с инклюдом я не считал, и не считаю приемлемым вариантом решения, даже при том, что он фактически наиболее простой и работающий. Во-1ых, может потребоваться наличие общих слотов/сигналов для нескольких контролов, но не для всех (хотя это тоже с помощью инклюда делается...). Во-2ых, может потребоваться наследование от имеющихся контролов.
« Последнее редактирование: Апрель 20, 2015, 15:12 от Гурман » Записан

2^7-1 == 127, задумайтесь...
Гурман
Гуру общения
******
Offline Offline

Сообщений: 1442

Qt 2.2, 3.3, 4.5, 4,7, 4.8, 5.3, 5.6, 5.9, 5.12


Просмотр профиля
« Ответ #26 : Апрель 20, 2015, 15:06 »

Опять же не знаю, кто там наш/не наш. Предлагалось вынести в common код общих методов и вызывать его из слотов самого виджета:
Код
C++ (Qt)
class MyLineEdit : public QLineEdit, public Common
{
public:
   ...
 
private slots:
   void    onTextChanged( const QString &val )
   {
       commonMethodText( val );
   }
 
   void    onReturnPressed()
   {
       commonMethodReturn();
   }
};
 

А эти слоты можно попробовать завернуть в макросы.


Делал так. Не имеет смысла, поскольку "commonMethodText( val )" и "commonMethodReturn();" сами состоят из 1-3-х строк, а весь кусок private slots всё равно надо копировать. Или заворачивать в многострочный макрос (тоже делал) - но тогда отлаживать нормально не получается.
Записан

2^7-1 == 127, задумайтесь...
Гурман
Гуру общения
******
Offline Offline

Сообщений: 1442

Qt 2.2, 3.3, 4.5, 4,7, 4.8, 5.3, 5.6, 5.9, 5.12


Просмотр профиля
« Ответ #27 : Апрель 20, 2015, 15:11 »

Это смотря где ты ищешь преимущества. По мне преимущество только архитектурное: хоть какая-то инкапсуляция и возможность расширения (не факт, что ей придется воспользоваться); но писанины больше. include внутри класса - явный хак. Вообще, мне кажется, наследование здесь не лучший вариант, возможно с отдельным классом получится удачнее. Но хозяин-барин, решать все-равно тебе.

В варианте агрегирования не удаётся избавиться от копирования одинаковых методов в реализациях. Только вместо обработки сигналов, эти методы занимаются передачей сигналов для обработки. См. выше пример от Old.

В варианте инклюда общий класс у контролов вообще исчез.

Преимущества, которые для меня важны - упрощение и уменьшение кода, упрощение его модификации, возможность отладки. С расширением пока не ясно...
Записан

2^7-1 == 127, задумайтесь...
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #28 : Апрель 20, 2015, 15:22 »

Во-1ых, может потребоваться наличие общих слотов/сигналов для нескольких контролов, но не для всех (хотя это тоже с помощью инклюда делается...
Я в этом сильно сомневаюсь
Записан
Гурман
Гуру общения
******
Offline Offline

Сообщений: 1442

Qt 2.2, 3.3, 4.5, 4,7, 4.8, 5.3, 5.6, 5.9, 5.12


Просмотр профиля
« Ответ #29 : Апрель 20, 2015, 15:57 »

Во-1ых, может потребоваться наличие общих слотов/сигналов для нескольких контролов, но не для всех (хотя это тоже с помощью инклюда делается...
Я в этом сильно сомневаюсь

В чем именно?
Записан

2^7-1 == 127, задумайтесь...
Страниц: 1 [2] 3   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.238 секунд. Запросов: 23.