Реклама

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

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

Для работы с контекстным меню в 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
  • 13 июля 2017 г. 2:12

Qt/C++ - Урок 023. Перетаскивание QGraphicsItem на QGraphicsScene мышью

Ну например так можете сделать.void MoveItem::mousePressEvent(QGraphicsSceneMouseEvent *event){ if (QApplication::mouseButtons() == Qt::RightButton) { this->deleteLa...

  • Mark
  • 13 июля 2017 г. 1:26

Qt/C++ - Урок 023. Перетаскивание QGraphicsItem на QGraphicsScene мышью

Подскажите пожалуйста как в данном проекте по перетаскиванию организовать удаление объекта со scene методом delete item, допустим при щелчке ПКМ по объекту QGraphicsScene. Мои попытки оказалис...

  • EVILEG
  • 10 июля 2017 г. 21:34

Qt/C++ - Урок 048. QThread - работа с потоками с помощью moveToThread

А что делали? Повторяете урок или как? Пытались просто скачать проект в конце статьи и запустить?

Qt/C++ - Урок 048. QThread - работа с потоками с помощью moveToThread

У меня происходит переполнение счетчика count, появляется ошибка malloc(): memory corruption (fast). Не подскажите, как с этим бороться?

  • EVILEG
  • 9 июля 2017 г. 2:07

GameDev на Qt - Урок 3. Уничтожение противников

Поэтому в пятом уроке есть исходники всего проекта )))). Вообще, все эти материалы были не предыдущей версии сайта, которая на WordPress. Во время переноса мог что-то потерять.

Сейчас обсуждают на форуме

Как реализовать отправку e-mail

Возможно что уже и нет необходимости в почтовом клиенте, но в своё время так же столкнулся с данной проблемой в QT. Нашел один интересный проект под названием libqxt, там реализовано дов...

  • BlinCT
  • 18 июля 2017 г. 0:00

тестирование классов в QT

Это был вопрос или утверждение? Не понятно что вы хотели этим сказать. Интересное у вас обращение.

  • Asteri
  • 14 июля 2017 г. 12:23

css

Делюсь, может, пригодится когда-нибудь) QTableView QHeaderView { background-color: #ffffff; } Вот так эта проблема лечится, градиент задать не получается, но хоть...

  • EVILEG
  • 12 июля 2017 г. 19:52

QSqlQuery выполнение sql запросов из файла

Мне думается, что это уже будет дело вкуса и вашего взгляда на проект. Если Вы действительно собираетесь просто скармливать своему софту SQL скрипты, которые должны будут выполняться для...

QML Canvas + Line. Bug?

Вот оно что, значит не баг) Спасибо