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

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

Qt

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


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


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

2 Скрин

  • #
  • 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 записи открывать диалог на редактирование.

Для Django рекомендую VDS-хостинг TIMEWEB

"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();
}

Для Django рекомендую VDS-хостинг TIMEWEB

До этого слот вот такой юзал

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();
}

Для Django рекомендую VDS-хостинг TIMEWEB

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

Для Django рекомендую VDS-хостинг TIMEWEB

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

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

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

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

Для Django рекомендую VDS-хостинг TIMEWEB

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

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

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, тогда будет ещё более гарантированный результат без ошибок, но в этом случае нужно будет иметь указатель на ту модель, которая находится в главном диалоге, а это уже более сложный для понимания вариант реализации.

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

Для Django рекомендую VDS-хостинг TIMEWEB

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


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

Ответы

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

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

  • Результат 100баллов,
  • Очки рейтинга10
24 сентября 2018 г. 17:37
edorofeeva

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

  • Результат 66баллов,
  • Очки рейтинга-1
23 сентября 2018 г. 14:38
No Names

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

  • Результат 60баллов,
  • Очки рейтинга-1
Последние комментарии
24 сентября 2018 г. 15:09
Евгений Легоцкой

Qt Linux - Урок 001. Автозапуск Qt приложения под Linux

А вот здесь у меня есть пример использования supervisor. https://evileg.com/ru/post/3/ Вся статья вам там не интересна, интересен только шаг с настройкой supervisor. Он получается ...
24 сентября 2018 г. 15:00
avovana

Qt Linux - Урок 001. Автозапуск Qt приложения под Linux

Не могли бы дать ссылку на пример? Какое-то рабочее использование. Т.е. у меня есть Qt Gui App, которое я бы хотел запускать при старте системы и в случае, если оно грохнется. Если о чем Вы го...
24 сентября 2018 г. 14:55
Евгений Легоцкой

Qt Linux - Урок 001. Автозапуск Qt приложения под Linux

Если честно, то я не уверен, что это вообще можно реализовать через *.desktop файл. Я сделал предположение на основе того, что вы сказали про *.desktop и рестарт. Все варианты, котор...
24 сентября 2018 г. 14:47
avovana

Qt Linux - Урок 001. Автозапуск Qt приложения под Linux

Просто сейчас правлю сам файл example.desktop. Пытаюсь понять какую пару key=value мне нужно дописать.
24 сентября 2018 г. 14:42
Евгений Легоцкой

Qt Linux - Урок 001. Автозапуск Qt приложения под Linux

Ну я имел ввиду, что дописать в коде вот сюда то, о чём вы говорили про рестарт QString autorunContent("[Desktop Entry]\n" "Type=Application\n" ...
Сейчас обсуждают на форуме
24 сентября 2018 г. 16:47
Евгений_Канусовский@1981

Чтение файлов в python

Добрый вечер Евгений и форумчане! Столкнулся с проблемой чтения файлов в python: файлы с обычным текстом в формате las и txt читаются, например: ~Version information VERS.          ...
24 сентября 2018 г. 13:29
Евгений Легоцкой

Трансляция видео с помощью VLC по RTP

Добрый день! Я не сталкивался, но предположу, что нужно настроить Input Codec в VLC. В настройках есть секция Input Codec, возможно, что там установлено низкое разрешение. ...
21 сентября 2018 г. 8:25
Евгений Легоцкой

Прокси-модель, содержащая на 1 столбец больше, чем модель-источник.

Попробуйте ещё PySide 2 - это официально поддерживаемый пакет привязок Python к Qt, возможно, что там не будет таких проблем.
20 сентября 2018 г. 20:06
Евгений Легоцкой

Qt Installer Framework

Добрый день. Зачем собирать Qt Installer Framework-то из исходников? Я ещё понимаю Qt собирают из исходников статически (хотя тоже считаю по большей части бесполезной тратой времени),...
Присоединяйтесь к нам в социальных сетях