Qt/C++ - Урок 013. QMenu - контекстное меню в QTableView

РуководствоQtQMenu, QMenu example, QMenu Qt, Qt, контекстное меню, меню1925

Для работы с контекстным меню в Qt используется класс QMenu . При совершении действий, которые должны вызвать меню, вызывается обработчик, который создаёт меню и привязывает обработчики к действиям в данном меню.

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

Программный код был написан в QtCreator 3.3.1 на основе Qt 5.4.1.

Структура проекта для QMenu

Структура проекта остается неизменной, как и в уроке, на котором основывается данный урок. Изменениям в программном коде будут подвергнуты лишь два файла:

  • mainwindow.h
  • mainwindow.cpp

mainwindow.h

Объявляем дополнительные СЛОТы в заголовочном файле. Это СЛОТы для вызова контекстного меню, и удаления записи. Также необходимо переписать сигнатуру СЛОТа для редактирования записи, поскольку будет использоваться иной способ определения выбранной записи.

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QSqlTableModel>

#include <database.h>
#include <dialogadddevice.h>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:
    void on_addDeviceButton_clicked();
    void slotUpdateModels();
    /* К СЛОТу по редактировнию записи
     * добавляем СЛОТ по удалению записи.
     * Также добавляем СЛОТ для обработки вызова контекстного меню
     * */
    void slotEditRecord();
    void slotRemoveRecord();
    void slotCustomMenuRequested(QPoint pos);

private:
    Ui::MainWindow              *ui;
    DataBase                    *db;
    QSqlTableModel              *modelDevice;

private:
    void setupModel(const QString &tableName, const QStringList &headers);
    void createUI();
};

#endif // MAINWINDOW_H

mainwindow.cpp

В данном файле необходимо будет добавить включение контекстного меню для tableView. А также написать метод для обработки вызова контекстного меню и удаления записи из таблицы и соответственно из базы данных. Попутно переписываем и метод для редактирования записи.

В результате у Вас должно получиться приложение, которое по нажатию правой кнопкой мышки по записи в таблице вызывает контекстное меню с двумя пунктами: Редактировать и Удалить . По нажатию пункта Редактировать будет вызвано диалоговое окно, как в случае с действием double-click из предыдущего урока. А по нажатию пункта Удалить будет вызван MessageBox с вопросом о подтверждении удаления, и в случае утвердительного результата будет произведено удаление записи в таблице.

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    /* Программный код без изменения, как в уроке по QDataWidgetMapper */
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::setupModel(const QString &tableName, const QStringList &headers)
{
    /* Программный код без изменения, как в уроке по QDataWidgetMapper */
}

void MainWindow::createUI() 
{
    ui->deviceTableView->setModel(modelDevice);
    ui->deviceTableView->setColumnHidden(0, true);
    ui->deviceTableView->setSelectionBehavior(QAbstractItemView::SelectRows);
    ui->deviceTableView->setSelectionMode(QAbstractItemView::SingleSelection);
    ui->deviceTableView->resizeColumnsToContents();
    ui->deviceTableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
    ui->deviceTableView->horizontalHeader()->setStretchLastSection(true);

    // Устанавливаем Контекстное Меню
    ui->deviceTableView->setContextMenuPolicy(Qt::CustomContextMenu);

    connect(ui->deviceTableView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(slotEditRecord()));
    // Подключаем СЛОТ вызова контекстного меню
    connect(ui->deviceTableView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(slotCustomMenuRequested(QPoint)));
}

/* Метод для активации диалога добавления записей
 * */
void MainWindow::on_addDeviceButton_clicked()
{
    /* Программный код без изменения, как в уроке по QDataWidgetMapper */
}

void MainWindow::slotCustomMenuRequested(QPoint pos)
{
    /* Создаем объект контекстного меню */
    QMenu * menu = new QMenu(this);
    /* Создаём действия для контекстного меню */
    QAction * editDevice = new QAction(trUtf8("Редактировать"), this);
    QAction * deleteDevice = new QAction(trUtf8("Удалить"), this);
    /* Подключаем СЛОТы обработчики для действий контекстного меню */
    connect(editDevice, SIGNAL(triggered()), this, SLOT(slotEditRecord()));     // Обработчик вызова диалога редактирования
    connect(deleteDevice, SIGNAL(triggered()), this, SLOT(slotRemoveRecord())); // Обработчик удаления записи
    /* Устанавливаем действия в меню */
    menu->addAction(editDevice);
    menu->addAction(deleteDevice);
    /* Вызываем контекстное меню */
    menu->popup(ui->deviceTableView->viewport()->mapToGlobal(pos));
}

/* Слот для удаления записи из таблицы
 * */
void MainWindow::slotRemoveRecord()
{
    /* Выясняем, какая из строк была выбрана
     * */
    int row = ui->deviceTableView->selectionModel()->currentIndex().row();
    /* Проверяем, что строка была действительно выбрана
     * */
    if(row >= 0){
        /* Задаём вопрос, стоит ли действительно удалять запись.
         * При положительном ответе удаляем запись
         * */
        if (QMessageBox::warning(this,
                                 trUtf8("Удаление записи"),
                                 trUtf8("Вы уверены, что хотите удалить эту запись?"),
                                 QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
        {
            /* При отрицательном ответе делаем откат действий
             * и закрываем диалог без удаления записи
             * */
            QSqlDatabase::database().rollback();
            return;
        } else {
            /* В противном случае производим удаление записи.
             * При успешном удалении обновляем таблицу.
             * */
            if(!modelDevice->removeRow(row)){
                QMessageBox::warning(this,trUtf8("Уведомление"),
                                     trUtf8("Не удалось удалить запись\n"
                                            "Возможно она используется другими таблицами\n"
                                            "Проверьте все зависимости и повторите попытку"));
            }
            modelDevice->select();
            ui->deviceTableView->setCurrentIndex(modelDevice->index(-1, -1));
        }
    }
}

/* Слот обновления модели представления данных
 * */
void MainWindow::slotUpdateModels()
{
    modelDevice->select();
    ui->deviceTableView->resizeColumnsToContents();
}

/* Метод для активации диалога добавления записей в режиме редактирования
 * с передачей индекса выбранной строки
 * */
void MainWindow::slotEditRecord()
{
    /* Также создаем диалог и подключаем его сигнал завершения работы
     * к слоту обновления вида модели представления данных, но передаём
     * в качестве параметров строку записи
     * */
    DialogAddDevice *addDeviceDialog = new DialogAddDevice(ui->deviceTableView->selectionModel()->currentIndex().row());
    connect(addDeviceDialog, SIGNAL(signalReady()), this, SLOT(slotUpdateModels()));

    /* Выполняем запуск диалогового окна
     * */
    addDeviceDialog->setWindowTitle(trUtf8("Редактировать Устройство"));
    addDeviceDialog->exec();
}

Итог

В результате Вы научились вызывать контекстное меню для объекта QTableView и в целом работать с классом QMenu. Также в качестве бонуса был параллельно освящен вопрос по удалению записей из таблицы и базы данных с помощью модели представления данных. Пример поведения QMenu показан в следующем видео:

Реклама

Комментарии

Комментарии

Только авторизованные пользователи могут оставлять комментарии.
Пожалуйста, Авторизуйтесь или Зарегистрируйтесь
Последние комментарии
  • EVILEG
  • 24 апреля 2017 г. 20:44

Подключение вашего Qt приложения к сервисам Google, используя OAuth 2.0

У меня пока мыслей на этот счёт нет ((

Подключение вашего Qt приложения к сервисам Google, используя OAuth 2.0

Пробовал играться с шарком, либо я криво смотрел, либо почему-то POST запросы на oauth.yandex.ru не летят, хотя должны постом лететь, я и исходники QOAuth2AuthorizationCodeFlow ковырял на пред...

  • EVILEG
  • 24 апреля 2017 г. 13:39

Подключение вашего Qt приложения к сервисам Google, используя OAuth 2.0

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

Сейчас обсуждают на форуме
  • Arrow
  • 1 мая 2017 г. 1:00

Callback функции

Первый раз пытаюсь работать с Callback функциями. Помогите понять, что и где я не так делаю. Вот код: ReverseString.h #ifndef REVERSESTRING_H#define REVERSESTRING_H#includ...

  • EVILEG
  • 30 апреля 2017 г. 10:22

QMenu

Вам не кажется, что вы увлеклись со скриншотами? Добавляйте голый программный код в сообщения через специальный диалог. Это кнопка с двумя фигурными скобками. Иногда требуется повторить код у ...

  • CJIaBiK
  • 29 апреля 2017 г. 21:07

QPushButton

Спасибо

  • CJIaBiK
  • 29 апреля 2017 г. 17:57

QWebEngineView

спасибо помогло

  • EVILEG
  • 29 апреля 2017 г. 17:47

Ошибка

Такое случается, когда добавляете новые файлы, а объектный файл, в данном случае mainwindow.obj, не пересобирается как положено. Приходится чистить сборку.