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

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

Страниц: [1]   Вниз
  Печать  
Автор Тема: QTableView + контекстное меню  (Прочитано 13089 раз)
silart
Гость
« : Ноябрь 07, 2010, 17:52 »

Добрый день!

У меня возник такой вопрос.
Есть модель QSqlTableModel. Есть представление QTableView. QTableView находится на своей форме, есть еще кнопки Insert, Delete, Submit, которые воздействуют на модель. Получается такой диалог, который может оперировать с данными модели: (добавлять строки, удалять строки, изменять строки) независимо от самой модели (то есть ему безразлично какие есть столбцы, сколько строк). Это универсальный диалог для заполнения справочников базы данных.
Так вот!
Каким образом, и возможно ли это, прикрутить к этому диалогу контекстное меню? Чтобы его пункты дублировали кнопки и чтобы действия меню применялись именно к выделенному элементу представления?

Кто-нибудь подобное делал?
Записан
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #1 : Ноябрь 07, 2010, 18:01 »

Легко. QAction тебе в помощь.
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
silart
Гость
« Ответ #2 : Ноябрь 07, 2010, 18:19 »

Легко. QAction тебе в помощь.

Да это понятно все, что QAction. Меня интересует как прикрутить меню к QTableView. Как сделать так, чтобы меню органично сочиталось с QTableView? То есть если ничего не выделить, пункт Delete зачернялся бы.
Записан
asvil
Гость
« Ответ #3 : Ноябрь 07, 2010, 20:09 »

Легко делать в Qt front-end'ы к базам данных будет тогда, когда компания Nokia прекратит заниматься ерундой, свернет проекты QtDeclarative, JavaScript и перейдет на cmake.
Автор будущей программы, рассмотрите пожалуйста другие инструменты для создания интерфейса. А если у Вас нет другого варианта, то ознакомтесь с содержанием, предоставляемым программой assistent. Просмотрите внимательно все сигналы и события, существуемые в Qt Framework. Затем попробуйте себя в фильтрации сообщений. Тем самым Вы получите доступ к действиям пользователя. В ответ на какое либо действие пользователя вы должны как-то изменить интерфейс (зачернить пункт delete в частности).
Давайте рассмотрим такое простое действие, как удаление строки в sql модели. Я бы рекомендовал предоставлять данное действие пользователю только после того, как последний выделит нужную(ые) строку(и) целиком. Отображать это действие будем в двух местах. Первое - QToolBar или QToolButton, второе - это всплывающее окно для вертикального заголовока QTableView.
Ниже я предоставляю псевдо-код с комментариями.
Код:
// инициализация
QAction *removeLinesAction = new QAction(QIcon(":/images/table/table_row_delete.png"), tr("Remove lines"), this);
removeLinesAction->setEnabled(false);
// Соединяем QAction со слотом удаления строк
connect(removeLinesAction, SIGNAL(triggered())
          , this, SLOT(removeLines()));
// соединяемся с сигналом, рассказывающем все о том, что выделил пользователь в QTableView
QTableView *itemView = new QTableView(this);
connect(itemView->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection))
  , this, SLOT(selectionChanged(QItemSelection, QItemSelection)));
QToolButton *removeLinesButton = new QToolButton(this);
removeLinesButton->setDefaultAction(removeLinesAction);

// Слот обрабатывающий изменение выделения
void selectionChanged(QItemSelection, QItemSelection)
{
  QAbstractItemModel* model;
  removeLinesAction->setEnabled(itemView->selectionModel()->selectedRows().count());
}

// Слот удаляющий строки
void removeLines()
{
  QAbstractItemModel* model;
  if ((model = itemView->model())) {
    QItemSelectionModel* selectionModel = itemView->selectionModel();
    QModelIndexList indexes = selectionModel->selectedRows();

    if (indexes.isEmpty())
      return;

    int messageBoxResult;
    messageBoxResult = QMessageBox::question(QApplication::activeWindow()
                       , tr("Removing data")
                       , tr("Data will be removed permanently. Continue?"),
                       QMessageBox::Yes, QMessageBox::No);

    if (messageBoxResult == QMessageBox::No)
      return;

    int count = 1;
    int startRow = indexes.at(0).row();
    QModelIndex rootIndex = indexes.at(0).parent();

    // delete only first continuous selection
    for (int i = 1; i < indexes.count(); ++i) {
      if (indexes.at(i - 1).row() != indexes.at(i).row() - 1)
        break;
      else
        ++count;
    }
    model->removeRows(startRow, count, rootIndex);

// Под вопросом нужен ли вызов данных функций здесь
    if (!model->submit())
      model->revert();

    return;
  }
}

// Переопределяем фильтр сообщений. В нашем случае фильтруем QTableView::verticalHeader()
bool eventFilter(QObject* object, QEvent* event)
{
  if (event->type() == QEvent::ContextMenu) {
    QContextMenuEvent* menuEvent = static_cast<QContextMenuEvent*>(event);
    QHeaderView* headerView = qobject_cast<QHeaderView*>(object);
    if (headerView) {
      if (headerView->orientation() == Qt::Vertical) {
        QList<QAction*> actions;
        actions.append(removeLinesAction);
        QMenu::exec(actions, menuEvent->globalPos(), 0, headerView);
        // отфильтровали
        return true;
      }
    }
  }
  return QObject::eventFilter(object, event);
}
Записан
xokc
Птица говорун
*****
Offline Offline

Сообщений: 976



Просмотр профиля
« Ответ #4 : Ноябрь 07, 2010, 20:21 »

Легко делать в Qt front-end'ы к базам данных будет тогда, когда компания Nokia прекратит заниматься ерундой, свернет проекты QtDeclarative, JavaScript и перейдет на cmake.
Боюсь, что сама Nokia этого делать не будет никогда - нафига оно ей? Ей надо мобильный бизнес спасать от Андроидов и  iOS. Остаётся только надеяться на достаточно серьезного стороннего девелопера (типа DevExpress), который прикрутит нормальный DB фронтенд к Qt.
Записан
silart
Гость
« Ответ #5 : Ноябрь 10, 2010, 12:49 »

Филоненко Михаил, спасибо! Я воспользовался вашем советом.

QAction + eventFilter сделали свое дело. Контекстное меню хорошо интегрировалось в форму.
Записан
Sahab
Гость
« Ответ #6 : Ноябрь 10, 2010, 13:57 »

Цитировать
Остаётся только надеяться на достаточно серьезного стороннего девелопера (типа DevExpress)
Смеющийся Смеющийся Смеющийся
и молиццо
Записан
xokc
Птица говорун
*****
Offline Offline

Сообщений: 976



Просмотр профиля
« Ответ #7 : Ноябрь 10, 2010, 21:47 »

Цитировать
Остаётся только надеяться на достаточно серьезного стороннего девелопера (типа DevExpress)
Смеющийся Смеющийся Смеющийся
и молиццо
А вот тут вряд ли поможет
Записан
Андрей
Гость
« Ответ #8 : Январь 15, 2012, 20:05 »

Создал класс class MyTableView : public QTableView. В остальном сделал аналогично  приведённому примеру.  
Почему-то преобразования не происходит
QHeaderView* headerView = qobject_cast<QHeaderView*>(object);
Меняю на
QWidget *Widget = qobject_cast<QWidget*>(object);
всё работает нормально, но менюшка, соответственно, вылазит на каждом виджете MyTableView.
« Последнее редактирование: Январь 15, 2012, 20:28 от Андрей » Записан
Андрей
Гость
« Ответ #9 : Январь 20, 2012, 19:17 »

Нашёл ошибку.
Теперь другая проблема...
Запускается C:\Trainer\Ver1\Trainer-build-desktop-Qt_4_7_4_for_Desktop_-_MinGW_4_4__Qt_SDK_________\debug\Trainer.exe...
QObject::connect: Cannot connect (null)::selectionChanged(QItemSelection, QItemSelection) to MyTableView::selectionChanged(QItemSelection, QItemSelection)

Соответствующая строчка в MyTableView::MyTableView(QWidget *parent)

connect(this->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection))
      , this, SLOT(selectionChanged(QItemSelection, QItemSelection)));

Также хотелось бы, чтобы строка выделялась по нажатию на ней правой кнопки мыши, если она не была выделена.
Записан
BRE
Гость
« Ответ #10 : Январь 20, 2012, 19:21 »

Соответствующая строчка в MyTableView::MyTableView(QWidget *parent)

connect(this->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection))
      , this, SLOT(selectionChanged(QItemSelection, QItemSelection)));
Этот коннект должен быть уже после установки модели (setModel), потому что селектион модель создается после этого или создавай и устанавливай ее сам.

Записан
Андрей
Гость
« Ответ #11 : Январь 20, 2012, 19:38 »

Спасибо. Вставил в  MyTableView::setModel(...). Не ругается больше.
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


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