Политика конфиденциальностиКонтактыО сайтеОтзывыGitHubDonate
© EVILEG 2015-2018
Рекомендует хостинг
TIMEWEB

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

QMenu, QMenu example, QMenu Qt, Qt, контекстное меню, меню

Для работы с контекстным меню в 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 показан в следующем видео:

Комментарии

Только авторизованные пользователи могут публиковать комментарии.
Пожалуйста, авторизуйтесь или зарегистрируйтесь
КА
19 февраля 2019 г. 18:32
Кристина Афанасьева

C++ - Тест 006. Перечисления

  • Результат:70баллов,
  • Очки рейтинга1
КА
19 февраля 2019 г. 18:26
Кристина Афанасьева

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:60баллов,
  • Очки рейтинга-1
КА
19 февраля 2019 г. 18:00
Кристина Афанасьева

C++ - Тест 002. Константы

  • Результат:50баллов,
  • Очки рейтинга-4
Последние комментарии
21 февраля 2019 г. 12:51
Евгений Легоцкой

Иногда CMake приходится перезапускать начисто, не обновляет кэш
R
21 февраля 2019 г. 12:29
RandyGallup

Я указал данные строки, т.к. без них у меня вылетала следующая ошибка: By not providing "FindQt5Core.cmake" in CMAKE_MODULE_PATH this project has asked CMake to find a package configurat...
21 февраля 2019 г. 12:08
BlinCT

Вот атк выглядит мой проектник, посмотрите его. cmake_minimum_required(VERSION 3.6)project(projecttimer)set(CMAKE_CXX_STANDARD 11)set(CMAKE_AUTOMOC ON)set(CMAKE_AUTORCC ON)find_packa...
21 февраля 2019 г. 12:04
BlinCT

Смотрите, если вы используете глобально для проекта -DCMAKE_PREFIX_PATH= то вам не надо уже указывать вот эти строкиset(Qt5Core_DIR "C:/Qt/5.12.1/mingw73_64/lib/cmake/Qt5Core")set(Qt5Gui_DIR...
R
21 февраля 2019 г. 11:54
RandyGallup

Даже не запускается. main.cpp у меня точно такой же, как в статье. CMakeLists.txt пришлось немного подправить (прикрепил ниже), т.к. не находились некоторые файлы. cmake_minimum_requi...
Сейчас обсуждают на форуме
21 февраля 2019 г. 8:58
Евгений Легоцкой

Ну у меня координаты передавались в зависимости от положения курсора мыши, а в вам по сути нужно будет аналогичным способом посылать даннные из полей ввода. Так что здесь скорее интерфес...
20 февраля 2019 г. 21:55
Евгений Легоцкой

Не до конца понимаю сути вопроса, наверное, нужно увидеть программный код и попытку его применения, но к методам базового класса можно обращаться в наследованном классе через вызов по имени ба...
MU
20 февраля 2019 г. 15:06
Maciej Urmański

Yes, ok I have solution! Thank you for directing me about annotate.:) Solution is: users_in = User.objects.filter(joined_users__goal=goal, joined_users__joined=True)
20 февраля 2019 г. 14:40
Евгений Легоцкой

Думаю, что ещё можно переопределить mouseReleaseEvent(QMouseEvent* event) у QTableView, который содержит модель и немного поиграться с индексом. Если это индекс, который соответству...
20 февраля 2019 г. 10:34
Евгений Легоцкой

Да, так тоже можно. Единственный момент в том, что lupdate не всегда понимает, к какому контексту это дело относится, и может запихать в левый контекст. В небольшом проекте это не критич...
Присоединяйтесь к нам в социальных сетях

Для зарегистрированных пользователей на сайте присутствует минимальное количество рекламы