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

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

Страниц: [1]   Вниз
  Печать  
Автор Тема: унаследовать QListView/QTableView от своего класса  (Прочитано 4844 раз)
kambala
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4746



Просмотр профиля WWW
« : Сентябрь 03, 2011, 14:35 »

Здравствуйте. Появилась необходимость использовать некоторый набор своей логики в двух разных классах-наследниках QListView и QTableView. Эту логику вынес в отдельный класс:
Код
C++ (Qt)
class ItemView : public QAbstractItemView // тут по идее нужен virtual
{
   Q_OBJECT
 
public:
   ItemView(QWidget *parent) : QAbstractItemView(parent) { connect(this, SIGNAL(clicked(const QModelIndex &)), SIGNAL(currentItemChanged(const QModelIndex &))); }
 
signals:
   void currentItemChanged(const QModelIndex &newIndex);
 
protected:
virtual void keyPressEvent(QKeyEvent *event)
{
   QModelIndex oldIndex = currentIndex();
   QAbstractItemView::keyPressEvent(event); // раньше, когда метод находился в классе-наследнике QListView, то вызывался просто для QListView
   int key = event->key();
   if (key == Qt::Key_Up || key == Qt::Key_Down || key == Qt::Key_PageUp || key == Qt::Key_PageDown || key == Qt::Key_Home || key == Qt::Key_End)
       if (oldIndex != currentIndex())
           emit currentItemChanged(currentIndex());
}
};

Но как теперь сделать так, чтоб наследники QListView и QTableView использовали этот класс в качестве "базового" вместо обычного QAbstractItemView? Почитал про виртуальное наследование (раньше никогда с ним не сталкивался), но, похоже, не слишком разобрался в нем.
Код
C++ (Qt)
class MyListView : public ItemView, public QListView
{
   Q_OBJECT
public:
   explicit MyListView(QWidget *parent = 0) : ItemView(parent), QListView(parent) {}
...
};
Записан

Изучением C++ вымощена дорога в Qt.

UTF-8 has been around since 1993 and Unicode 2.0 since 1996; if you have created any 8-bit character content since 1996 in anything other than UTF-8, then I hate you. © Matt Gallagher
twp
Гость
« Ответ #1 : Сентябрь 03, 2011, 15:17 »

вообще то, насколько мне известно, наследоваться от двух классов, которые являются предками QObject нельзя. И вообще к чему такой наворот? Нельзя что ли кинуть фильтр событий или кастомизировать QListView и QTableView?
Записан
kambala
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4746



Просмотр профиля WWW
« Ответ #2 : Сентябрь 03, 2011, 15:34 »

Нельзя что ли кинуть фильтр событий или кастомизировать QListView и QTableView?
точно, а я и забыл про фильтр. спасибо!

а кастомизация напрямую не подходит т.к. это будет copy-paste программирование Улыбающийся
Записан

Изучением C++ вымощена дорога в Qt.

UTF-8 has been around since 1993 and Unicode 2.0 since 1996; if you have created any 8-bit character content since 1996 in anything other than UTF-8, then I hate you. © Matt Gallagher
kambala
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4746



Просмотр профиля WWW
« Ответ #3 : Сентябрь 03, 2011, 16:31 »

а через фильтр не получается так просто сделать. мне нужно (см. код выше), чтобы событие нажатия клавиши сначала отправилось виджету (чтобы текущий элемент изменился), затем сравнить новый текущий элемент со старым (чтобы предотвратить лишний вызов функции) и только если элемент другой - вызвать нужный метод. попытался сделать вот так:
Код
C++ (Qt)
ui.gearListView->installEventFilter(this);
...
bool ItemsViewerDialog::eventFilter(QObject *obj, QEvent *event)
{
   if (event->type() == QEvent::KeyPress /*|| event->type() == QEvent::MouseButtonPress*/)
   {
       QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
       QAbstractItemView *itemView = static_cast<QAbstractItemView *>(obj);
       QModelIndex oldIndex = itemView->currentIndex();
       qApp->sendEvent(obj, event); // send keyPressEvent immediately
 
       int key = keyEvent->key();
       if (key == Qt::Key_Up || key == Qt::Key_Down || key == Qt::Key_PageUp || key == Qt::Key_PageDown || key == Qt::Key_Home || key == Qt::Key_End)
           if (oldIndex != itemView->currentIndex())
               itemSelected(itemView->currentIndex());
       return true;
   }
   return QDialog::eventFilter(obj, event);
}
но это мало того, что выглядит как чистой воды хак, так еще и крашится (postEvent тоже) Улыбающийся а еще надо обрабатывать клик мышкой по элементу.

теперь думаю возвращать false из фильтра и использовать какой-то способ отложенного вызова метода, в который надо запихнуть все, что идет после получения oldIndex, типа QTimer::singleShot() вкупе с QMetaObject::invokeMethod() (не знаю как, но надо), но почему-то у меня такое ощущение, будто я изобретаю синхрофазотрон для езды по улицам Веселый
Записан

Изучением C++ вымощена дорога в Qt.

UTF-8 has been around since 1993 and Unicode 2.0 since 1996; if you have created any 8-bit character content since 1996 in anything other than UTF-8, then I hate you. © Matt Gallagher
twp
Гость
« Ответ #4 : Сентябрь 03, 2011, 16:52 »

да, было бы классно сделать что-то типа такого
Код:
template <class T>
class ItemView : public T
{
    Q_OBJECT
 
public:
    ItemView(QWidget *parent) : T(parent) { connect(this, SIGNAL(clicked(const QModelIndex &)), SIGNAL(currentItemChanged(const QModelIndex &))); }
 
signals:
    void currentItemChanged(const QModelIndex &newIndex);
 
protected:
    virtual void keyPressEvent(QKeyEvent *event)
    {
        QModelIndex oldIndex = currentIndex();
        T::keyPressEvent(event);
        int key = event->key();
        if (key == Qt::Key_Up || key == Qt::Key_Down || key == Qt::Key_PageUp || key == Qt::Key_PageDown || key == Qt::Key_Home || key == Qt::Key_End)
            if (oldIndex != currentIndex())
                emit currentItemChanged(currentIndex());
    }
};
а потом просто
Код:
    ...
    ItemView<QListView> *view = new ItemView<QListView>(parentWidget);
    ItemView<QTableView> *table = new ItemView<QTableView>(parentWidget);
Но moc не пропустит  Грустный
А вот
qApp->sendEvent(obj, event);
лучше не делать, может просто дать отработать
QDialog::eventFilter(obj, event);

Код:
bool ItemsViewerDialog::eventFilter(QObject *obj, QEvent *event)
{
    if (event->type() == QEvent::KeyPress /*|| event->type() == QEvent::MouseButtonPress*/)
    {
        QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
        QAbstractItemView *itemView = static_cast<QAbstractItemView *>(obj);
        QModelIndex oldIndex = itemView->currentIndex();
        QDialog::eventFilter(obj, event);
 
        int key = keyEvent->key();
        if (key == Qt::Key_Up || key == Qt::Key_Down || key == Qt::Key_PageUp || key == Qt::Key_PageDown || key == Qt::Key_Home || key == Qt::Key_End)
            if (oldIndex != itemView->currentIndex())
                itemSelected(itemView->currentIndex());
        return true;
    }
     return QDialog::eventFilter(obj, event);
}
Записан
kambala
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4746



Просмотр профиля WWW
« Ответ #5 : Сентябрь 03, 2011, 17:30 »

может просто дать отработать
QDialog::eventFilter(obj, event);
нет, не помогает Грустный как будто этого вызова и нету

добавлено: в общем, вот так (через задницу) работает, но мышиные события не ловятся (хотелось бы конечно, но тут можно сигналом clicked() обойтись) - в момент нажатия мышкой в фильтр приходит только paintEvent и timerEvent (в гугле нашел, что мышиные события могут идти в widget->viewport(), но это уж совсем хаком будет):
Код
C++ (Qt)
class ItemsViewerDialog : public QDialog
{
   Q_OBJECT
   ...
protected:
   bool eventFilter(QObject *obj, QEvent *event);
 
private slots:
   void itemSelected(const QModelIndex &index) { ... }
   void selectItem();
 
private:
   Ui::ItemsViewerWidget ui;
 
   QModelIndex _oldIndex;
   bool _wasAllowedKeyPressed;
   QAbstractItemView *_itemView;
};
Код
C++ (Qt)
bool ItemsViewerDialog::eventFilter(QObject *obj, QEvent *event)
{
   if (event->type() == QEvent::KeyPress || event->type() == QEvent::MouseButtonPress)
   {
       _itemView = static_cast<QAbstractItemView *>(obj);
       _oldIndex = _itemView->currentIndex();
 
       if (event->type() == QEvent::KeyPress)
       {
           int key = static_cast<QKeyEvent *>(event)->key();
           _wasAllowedKeyPressed = key == Qt::Key_Up || key == Qt::Key_Down || key == Qt::Key_PageUp || key == Qt::Key_PageDown || key == Qt::Key_Home || key == Qt::Key_End;
       }
       else
           _wasAllowedKeyPressed = true;
 
       QTimer::singleShot(0, this, SLOT(selectItem()));
       return false;
   }
   return QDialog::eventFilter(obj, event);
}
 
void ItemsViewerDialog::selectItem()
{
   if (_wasAllowedKeyPressed && _oldIndex != _itemView->currentIndex())
       itemSelected(_itemView->currentIndex());
}
« Последнее редактирование: Сентябрь 03, 2011, 18:04 от kambala » Записан

Изучением C++ вымощена дорога в Qt.

UTF-8 has been around since 1993 and Unicode 2.0 since 1996; if you have created any 8-bit character content since 1996 in anything other than UTF-8, then I hate you. © Matt Gallagher
kambala
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4746



Просмотр профиля WWW
« Ответ #6 : Сентябрь 03, 2011, 19:48 »

решил все-таки вернуться к китайскому стилю, и оказалось, что для QTableView все не так просто из-за span'ов, так что хотя бы полностью дублируемого кода не будет Улыбающийся но все равно хотелось бы иметь возможность вносить свои "расширения" (категории Улыбающийся ) в существующие классы...
Записан

Изучением C++ вымощена дорога в Qt.

UTF-8 has been around since 1993 and Unicode 2.0 since 1996; if you have created any 8-bit character content since 1996 in anything other than UTF-8, then I hate you. © Matt Gallagher
Akon
Гость
« Ответ #7 : Сентябрь 04, 2011, 01:29 »

Цитировать
да, было бы классно сделать что-то типа такого
Код:
template <class T>
class ItemView : public T
{
    Q_OBJECT
 
public:
    ItemView(QWidget *parent) : T(parent) { connect(this, SIGNAL(clicked(const QModelIndex &)), SIGNAL(currentItemChanged(const QModelIndex &))); }
 
signals:
    void currentItemChanged(const QModelIndex &newIndex);
 
protected:
    virtual void keyPressEvent(QKeyEvent *event)
    {
        QModelIndex oldIndex = currentIndex();
        T::keyPressEvent(event);
        int key = event->key();
        if (key == Qt::Key_Up || key == Qt::Key_Down || key == Qt::Key_PageUp || key == Qt::Key_PageDown || key == Qt::Key_Home || key == Qt::Key_End)
            if (oldIndex != currentIndex())
                emit currentItemChanged(currentIndex());
    }
};
а потом просто
Код:
    ...
    ItemView<QListView> *view = new ItemView<QListView>(parentWidget);
    ItemView<QTableView> *table = new ItemView<QTableView>(parentWidget);
Но moc не пропустит

Миксин можно навернуть, если уберете Q_OBJECT, но сами понимаете - поддержки метасистемы вам не видать.

Множественное наследование можно заменить вложением.
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


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