© EVILEG 2015-2018
Рекомендует хостинг
TIMEWEB
19 февраля 2018 г. 20:48

Qtableviev после сортировки

Qt

Сделал проект по уроку + добавил фильтр по "Типу устройств". Проблема заключается в редактировании записей после фильтрации.


На 1 скрине до фильтрации, а на 2 после.


  • #
  • 19 февраля 2018 г. 20:48

2 Скрин

  • #
  • отредактировано 19 февраля 2018 г. 20:53
  • 19 февраля 2018 г. 20:50

А вот что происходит, когда я пытаюсь отредактировать третью запись в отфильтрованной таблице :/

  • #
  • 19 февраля 2018 г. 20:56

EVILEG наведи на путь истинный, что делаю не так подскажи :(

  • #
  • 19 февраля 2018 г. 21:02
void MainWindow::on_SearchButton_clicked()
{
    modelDevice->setFilter(QString( DEVICE_TYPE "= '%1'").arg(ui->SearchLine->text()));
    modelDevice->select();
    
}

Фильтрую вот так, если что
Добрый день!
Как я понимаю, вы в качестве id используете номер строки. В вашем случае не получится так сделать.
QTableView поддерживает скрытие колонок. Так вот, вам нужно использовать колонку с ID записи. Эту колонку можно скрыть, чтобы он не мешалась в таблице.
Когда кликаете по QTableView с помощью метода data через индекс (QModelIndex) вам следует забрать ID записи и уже с помощью Id записи открывать диалог на редактирование.

"QTableView с помощью метода data через индекс (QModelIndex) "



Немного не понял, это как?

Ну вы используете слот для открытия диалога редактирования. Выглядеть он будет так.

void MainWindow::slotEditRecord(QModelIndex index)
{
    DialogAddDevice addDeviceDialog(index.row());
    connect(&addDeviceDialog, SIGNAL(signalReady()), this, SLOT(slotUpdateModel()));
 
    addDeviceDialog.setWindowTitle(trUtf8("Редактировать Устройство"));
    addDeviceDialog.exec();
}
Используете там index.row().
то есть открываете через номер строки. А нужно через информацию об ID записи, который обычно должен идти первой колонкой.
Поэтому можно сделать примерно так.
void MainWindow::slotEditRecord(QModelIndex index)
{
    // В качестве номера колонки будет 0, поскольку именно такую колонку чаще всего имеет ID
    DialogAddDevice addDeviceDialog(index.model()->data(index.model()->index(index.row(), 0)));
    connect(&addDeviceDialog, SIGNAL(signalReady()), this, SLOT(slotUpdateModel()));
 
    addDeviceDialog.setWindowTitle(trUtf8("Редактировать Устройство"));
    addDeviceDialog.exec();
}
  • EVILEG
  • #
  • отредактировано 20 февраля 2018 г. 13:03
  • 20 февраля 2018 г. 12:58
До этого слот вот такой юзал

void MainWindow::slotEditRecord()
{
    
    DialogAddDevice *addDeviceDialog = new DialogAddDevice(ui->deviceTableView->selectionModel()->currentIndex().row(););
    connect(addDeviceDialog, SIGNAL(signalReady()),this, SLOT(slotUpdateModels()));
    addDeviceDialog->setWindowTitle(trUtf8("Редактировать Устройство"));
    addDeviceDialog->exec();
}

С вашим слотом выдаёт ошибку :(

Две последних строки с ошибками в коде вы не переписали. А в первой я забыл учесть один момент.

void MainWindow::slotEditRecord(QModelIndex index)
{
    // В качестве номера колонки будет 0, поскольку именно такую колонку чаще всего имеет ID
    DialogAddDevice addDeviceDialog(index.model()->data(index.model()->index(index.row(), 0)).toInt());
    connect(&addDeviceDialog, SIGNAL(signalReady()), this, SLOT(slotUpdateModel()));
 
    addDeviceDialog.setWindowTitle(trUtf8("Редактировать Устройство"));
    addDeviceDialog.exec();
}
  • #
  • 20 февраля 2018 г. 13:03

.

А теперь ещё раз и внимательно смотрим моё последнее сообщение

Всё, поменял таки заработало. Но почему то оно выбирает строку с индексом больше на 1. В итоге вот что юзаю и оно корректно работает :)

 DialogAddDevice addDeviceDialog((index.model()->data(index.model()->index(index.row(), 0)).toInt())-1);
EVILEG Спасибо вам больше что помогли разобраться :)

  • sol11
  • #
  • отредактировано 20 февраля 2018 г. 13:30
  • 20 февраля 2018 г. 13:29

Потому, что в mainwindow вы работаете уже с индексами, когда создаёте диалог для редактирования, а диалоге в всё ещё работаете со строками.

Вам нужно переписать диалог, чтобы также данные забирались через индекс, а не через строку. Поскольку когда будете удалять некоторые строки, то правка на -1 уже Вам не поможет. Там будет расхождение id со строкой гораздо больше.

Evileg, не совсем понимаю что тут нужно переписать, чтобы данные забирались через индекс, а не строку. :(


#include "dialogadddevice.h"
#include "ui_dialogadddevice.h"
#include <QDebug>

DialogAddDevice::DialogAddDevice(int row, QWidget *parent) :
    QDialog(parent),
    ui(new Ui::DialogAddDevice)
{
    ui->setupUi(this);

   
    setupModel();

    
    if(row == -1){
        model->insertRow(model->rowCount(QModelIndex()));
        mapper->toLast();
    /* В противном случае диалог настраивается на заданную запись
     * */
    } else {
        mapper->setCurrentModelIndex(model->index(row,0));
    }

    createUI();
}

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

/* Метод настройки модели данных и mapper
 * */
void DialogAddDevice::setupModel()
{
    /* Инициализируем модель и делаем выборку из неё
     * */
    model = new QSqlTableModel(this);
    model->setTable(DEVICE);
    model->setEditStrategy(QSqlTableModel::OnManualSubmit);
    model->select();

    /* Инициализируем mapper и привязываем
     * поля данных к объектам LineEdit
     * */
    mapper = new QDataWidgetMapper();
    mapper->setModel(model);
    mapper->addMapping(ui->Device_Name, 1);
    mapper->addMapping(ui->Device_Type, 2);
    mapper->addMapping(ui->Dev_invent_number, 3);
    mapper->addMapping(ui->Dev_location, 4);
    mapper->addMapping(ui->Dev_status, 5);

  
    mapper->setSubmitPolicy(QDataWidgetMapper::ManualSubmit);

    qDebug() << ui->Device_Name->text();
    
    connect(ui->previousButton, SIGNAL(clicked()), mapper, SLOT(toPrevious()));
    connect(ui->nextButton, SIGNAL(clicked()), mapper, SLOT(toNext()));
    /* При изменении индекса в mapper изменяем состояние кнопок
     * */
    connect(mapper, SIGNAL(currentIndexChanged(int)), this, SLOT(updateButtons(int)));
}

void DialogAddDevice::createUI()
{

    QRegExp Name_Range("[a-zA-Z0-9]{20}");
    ui->Device_Name->setValidator(new QRegExpValidator (Name_Range,this));


    /*
    QString macRange = "(?:[0-9A-Fa-f][0-9A-Fa-f])";
    QRegExp macRegex ("^" + macRange
                      + "\\:" + macRange
                      + "\\:" + macRange
                      + "\\:" + macRange
                      + "\\:" + macRange
                      + "\\:" + macRange + "$");
    QRegExpValidator *macValidator = new QRegExpValidator(macRegex, this);
    ui->Device_Type->setValidator(macValidator);
    */
}

void DialogAddDevice::on_buttonBox_accepted()
{
    
    QSqlQuery query;
    QString str = QString("SELECT EXISTS (SELECT " DEVICE_NAME " FROM " DEVICE
                          /*" WHERE ( " DEVICE_NAME " = '%1' "*/" WHERE " DEVICE_INVENTORY_NUMBER " = '%1' "
                          " AND id NOT LIKE '%2' )")
            .arg(/*ui->Device_Name->text(),*/
                 ui->Dev_invent_number->text(),
                 model->data(model->index(mapper->currentIndex(),0), Qt::DisplayRole).toString());

    query.prepare(str);
    query.exec();
    query.next();

   
    if(query.value(0) != 0){
        QMessageBox::information(this, trUtf8("Ошибка добавления"),
                                 trUtf8("В базе уже присутствует устройство с таким серийным номером"));
    
    } else {
        mapper->submit();
        model->submitAll();
        emit signalReady();
        this->close();
    }
}

void DialogAddDevice::accept()
{
qDebug() << ui->Device_Name->text();
}


void DialogAddDevice::updateButtons(int row)
{
   
    ui->previousButton->setEnabled(row > 0);
    ui->nextButton->setEnabled(row < model->rowCount() - 1);
}
Кстати на удивление, удаление записей работает абсолютно нормально, без каких либо проблем вот с таким кодом:
void MainWindow::slotRemoveRecord()
{

    // Получение id_ строки
    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Возможно мешает какая то зависимость"));
            }
            modelDevice->select();
            ui->deviceTableView->setCurrentIndex(modelDevice->index(-1, -1));
        }
    }
}

Можешь навести пожалуйста, что мне нужно переписать в диалоге добавления :x
  • #
  • Ответ был помечен как решение
  • отредактировано 21 февраля 2018 г. 8:54
  • 21 февраля 2018 г. 8:53

Вот так можно написать

DialogAddDevice::DialogAddDevice(int id, QWidget *parent) :
    QDialog(parent),
    ui(new Ui::DialogAddDevice)
{
    ui->setupUi(this);
   
    setupModel();
    
    if(row == -1){
        model->insertRow(model->rowCount(QModelIndex()));
        mapper->toLast();
    /* В противном случае диалог настраивается на заданную запись
     * */
    } else {
        for (int row = 0; row < model->rowCount(); ++row)
        {
            if (model->data(model->index(row, 0)).toInt() == id)
            {
                mapper->setCurrentModelIndex(model->index(row, 0));
            }
        }
    }

    createUI();
}
Внимательно только посмотрите изменение кода, там я немного поменял аргументы конструктора.
Вообще, как вариант можно передавать ещё и QModelIndex вместо Id, тогда будет ещё более гарантированный результат без ошибок, но в этом случае нужно будет иметь указатель на ту модель, которая находится в главном диалоге, а это уже более сложный для понимания вариант реализации.

Но в данном случа оба варианта будут рабочими.

Спасибо, всё заработало :)


Единственное вот тут row на id поменял и всё круто :))
if(id == -1){
        model->insertRow(model->rowCount(QModelIndex()));
        mapper->toLast();

Ответы

Только авторизованные пользователи могут отвечать на форуме.
Пожалуйста, Авторизуйтесь или Зарегистрируйтесь
15 июня 2018 г. 12:42
Nicky

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

  • Результат 100 баллов
  • Очки рейтинга 10
15 июня 2018 г. 12:36
Nicky

C++ - Тест 003. Условия и циклы

  • Результат 57 баллов
  • Очки рейтинга -2
15 июня 2018 г. 12:29
Nicky

C++ - Тест 001. Первая программа и типы данных

  • Результат 46 баллов
  • Очки рейтинга -6
Последние комментарии
18 июня 2018 г. 7:12
EVILEG

PyQt5 - Урок 007. Работаем с QML QtQuick (Сигналы и слоты)

Я вот сейчас банальность скажу, но у меня всё работало. Так что даже и не знаю, надо на код смотреть, что ещё у вас добавлено или отсутствует из библиотек. P/S/ Извините, вы сейчас вс...
18 июня 2018 г. 7:10
EVILEG

Qt/C++ - Урок 042. PopUp уведомление в стиле Gnome с помощью Qt

Недоработки, вряд ли этот зверь вообще является официально поддерживаемым
18 июня 2018 г. 7:01
EVILEG

QML - Урок 016. База данных SQLite и работа с ней в QML Qt

что-то мне сдаётся, что здесь просто пересобрать проект нужно с удалением build каталога
18 июня 2018 г. 7:00
EVILEG

Qt - WinAPI. Как показать запущенное приложение поверх своего приложения

Если зарыться в API системы, то, думаю, что можно, тут тоже использовался WinAPI.
16 июня 2018 г. 15:19
pro100belik

Qt - WinAPI. Как показать запущенное приложение поверх своего приложения

А можно по ID процесса  выводить на передний план окно? myProcess->processId();
Сейчас обсуждают на форуме
19 июня 2018 г. 7:56
EVILEG

как редактировать порядок обхода этементов по нажатию TAB в Qt5 qml

Что-то наподобие такого TextField { Keys.onReturnPressed: nextItemInFocusChain().forceActiveFocus()}
19 июня 2018 г. 6:31
kabanov

Как сохранить фокус в TextField после перезагрузки модели

Rectangle { ListView { id: listView delegate: Item { id: cDelegate Item { Row { ComboBox { ...
18 июня 2018 г. 10:51
alex_lip

Qml and JavaScript

В том то и дело что просто в JS так нельзя Если использовать state - onReleased - не нужен вот так все работает Text { ...
18 июня 2018 г. 7:16
EVILEG

почему не выполняется код после вызова слота?

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

Рекомендуемые страницы