Qt контекстік мәзірмен жұмыс істеу үшін QMenu класын пайдаланады. Мәзірді іске қосу керек әрекеттерді орындау кезінде мәзірді жасайтын және өңдеушілерді осы мәзірдегі әрекеттерге байланыстыратын өңдеуші шақырылады.
Бұл сабақта контекстік мәзірмен жұмыс QDataWidgetMapper бағдарламасымен жұмыс істеу сабағы код мысалы арқылы көрсетіледі. Бұл оқулықта алдыңғы оқулықтағы екі файл өңделеді, бірақ алдыңғы оқулықтағы өңделмеген файлдарды қоспайынша, жоба жұмыс істемейді .
Код Qt 5.4.1 негізінде QtCreator 3.3.1-де жазылған.
QMenu үшін жоба құрылымы
Жобаның құрылымы осы сабаққа негізделген сабақтағыдай болып қалады. Бағдарлама кодында тек екі файл өзгертіледі:
- main window.h
- mainwindow.cpp
mainwindow.h
Біз тақырып файлында қосымша SLOTтарды жариялаймыз. Бұл контекстік мәзірді шақыруға және жазбаны жоюға арналған SLOTтар. Сондай-ақ, жазбаны өңдеу үшін SLOT қолтаңбасын қайта жазу қажет, өйткені таңдалған жазбаны анықтаудың басқа әдісі пайдаланылады.
#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. үшін мәтінмәндік мәзірді қосу керек болады. Сондай-ақ контекстік мәзір шақыруын өңдеу әдісін жазыңыз және жазбаны кестеден және сәйкесінше дерекқордан жойыңыз. Жол бойында біз жазбаны өңдеу әдісін қайта жазамыз.
Нәтижесінде кестедегі жазбаны тінтуірдің оң жақ түймешігімен басу арқылы екі элементі бар контекстік мәзірді шақыратын қолданбаны алуыңыз керек: Өңдеу және Жою . Өңдеу тармағын шерткенде алдыңғы сабақтағы екі рет шерту әрекетіндегідей диалогтық терезе шығады. Ал Жою тармағын басу арқылы 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 әрекетінің мысалы келесі бейнеде көрсетілген:
Доброго дня.
У меня вопрос по поводу нового синтаксиса.
Никак не могу разобраться с подключением СЛОТ-а
... делаю
... но с ошибкой.
Добрый день. Если у вас нет перегрузок сигналов или слотов, то QOverload Вам не нужен
Ошибка при компиляции? Или QtCreator подсвечивает что-то красным без компиляции? И почему не привели текст ошибки? Экстрасены в отпуске.
Спасибо за ответ. Да перегрузок сигналов нет.
Добрый день,
в строке 49 файла mainwindow.cpp создаётся меню и оно будет создаваться каждый раз при его вызове. Т.е. каждый раз будет выделяться память под QMenu. Это же утечка памяти или Qt как то сам освобождает память при выходе их слота slotCustomMenuRequested?