Ruslan Polupan
Ruslan PolupanApril 24, 2019, 4:07 p.m.

Помогите разобраться с CheckBox delegate в QAbstractTableModel

Delegate, qcheckbox, QAbstractTableModel

Доброго времени суток.
Где то я упустил что-то при изучении делегатов и их использовании.

Отображение работает. Но после того как выбираешь другую строку таблицы, предидущее выделение сбрсывается.
Не получается выбрать несколько объектов.


Файлы реализации делегата CheckBoxDelegate использовал такие же как в этой статье https://evileg.com/ru/post/478/

Реализация модели
modelterminals.h

#ifndef MODELTERMINALS_H
#define MODELTERMINALS_H
#include "terminalclass.h"

#include <QObject>
#include <QAbstractTableModel>

class ModelTerminals : public QAbstractTableModel
{
    Q_OBJECT
    QList<TerminalClass> m_listTerm;
public:
    ModelTerminals(QList<TerminalClass> lsTerm);

    // QAbstractItemModel interface
public:
    int rowCount(const QModelIndex &parent) const;
    int columnCount(const QModelIndex &parent) const;
    QVariant data(const QModelIndex &index, int role) const;
    bool setData(const QModelIndex &index, const QVariant &value, int role);
    Qt::ItemFlags flags(const QModelIndex &index) const;
    QVariant headerData(int section, Qt::Orientation orientation, int role) const;



};

#endif // MODELTERMINALS_H

modelterminals.cpp

#include "modelterminals.h"

ModelTerminals::ModelTerminals(QList<TerminalClass> lsTerm ) :
    m_listTerm(lsTerm)
{

}


int ModelTerminals::rowCount(const QModelIndex &parent) const
{
    return m_listTerm.size();
    Q_UNUSED(parent)
}

int ModelTerminals::columnCount(const QModelIndex &parent) const
{
    return m_listTerm.at(0).colParam();
    Q_UNUSED(parent)
}

QVariant ModelTerminals::data(const QModelIndex &index, int role) const
{
    if(!index.isValid()) { return QVariant();}
    TerminalClass t = m_listTerm[index.row()];
    switch (role) {
    case Qt::DisplayRole:
        switch (index.column()) {
        case 0: return t.isCheced();
        case 1: return t.terminalID();
        case 2: return t.terminalName();
        case 3: return t.regionID();
        case 4: return t.serverName();
        }
        break;
    case Qt::CheckStateRole:
        if(index.column() == 0) {
            return (!t.isCheced()) ? Qt::Checked : Qt::Unchecked;
        }
        break;
    default:
        break;
    }
    return QVariant();
}

bool ModelTerminals::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if(!index.isValid()) {return false;}

    TerminalClass t = m_listTerm[index.row()];

    if(role == Qt::CheckStateRole){
        if(value.toInt() == Qt::Checked){
            t.setIsCheced(true);
        } else {
            t.setIsCheced(false);
        }
        emit dataChanged(index,index);
        return true;
    }
    return false;
}

Qt::ItemFlags ModelTerminals::flags(const QModelIndex &index) const
{
    Qt::ItemFlags flags = QAbstractTableModel::flags(index);
    if(index.isValid() && index.column() == 0){
        flags |= Qt::ItemIsEditable;
    }
    return flags;
}

QVariant ModelTerminals::headerData(int section, Qt::Orientation orientation, int role) const
{
    if( role != Qt::DisplayRole) { return QVariant();}

    if( orientation == Qt::Vertical ) { return section; }

    switch (section) {
    case 0: return "";
    case 1: return "АЗС";
    case 2: return "Адрес";
    case 3: return "Регион";
    case 4: return "Сервер";
    default:
        break;
    }
    return QVariant();
}

Получаю данные для модели и создаю модель

#include "fuelnamedialog.h"
#include "ui_fuelnamedialog.h"

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

    createListTerminals();
    createModelterminals();
}

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

void FuelNameDialog::createModelterminals()
{
    qInfo(logInfo()) << "Заружено терминалов:" << listTerminals.size();
    CheckBoxDelegate *delegate = new CheckBoxDelegate();
    modelTerminals = new ModelTerminals(listTerminals);

    ui->tableViewTerminals->setModel(modelTerminals);
    ui->tableViewTerminals->setItemDelegateForColumn(0,delegate);

    ui->tableViewTerminals->verticalHeader()->hide();
    ui->tableViewTerminals->resizeColumnsToContents();

}

void FuelNameDialog::createListTerminals()
{
    QSqlQuery q;
    TerminalClass t;
    if(!q.exec("SELECT t.TERMINAL_ID, TRIM(t.name) AS NAME, t.OWNER_ID AS REGION, c.SERVER_NAME  FROM TERMINALS t "
               "LEFT JOIN CONNECTIONS c ON c.TERMINAL_ID = t.TERMINAL_ID "
               "WHERE t.TERMINALTYPE = 3 AND c.CONNECT_ID = 2 "
               "ORDER BY t.TERMINAL_ID")) {
        qInfo(logInfo()) << Q_FUNC_INFO  << "Не возможно получить список терминалов" << q.lastError().text();
        return;
    }
    while(q.next()){
        t.setIsCheced(false);
        t.setTerminalID(q.value(0).toInt());
        t.setTerminalName(q.value(1).toString());
        t.setRegionID(q.value(2).toInt());
        t.setServerName(q.value(3).toString());
        listTerminals.append(t);
    }

}
We recommend hosting TIMEWEB
We recommend hosting TIMEWEB
Stable hosting, on which the social network EVILEG is located. For projects on Django we recommend VDS hosting.

Do you like it? Share on social networks!

10
Evgenii Legotckoi
  • April 24, 2019, 5:09 p.m.

Добрый день

А вот этот код

    case Qt::CheckStateRole:
    if(index.column() == 0) {
        return (!t.isCheced()) ? Qt::Checked : Qt::Unchecked;
    }

Не должен быть написан так?

    case Qt::CheckStateRole:
    if(index.column() == 0) {
        return (t.isCheced()) ? Qt::Checked : Qt::Unchecked;
    }
    Ruslan Polupan
    • April 24, 2019, 5:22 p.m.

    Согласен. но ситуация не поменялась. Такое чуство что данные не записываются в модель.

      Evgenii Legotckoi
      • April 25, 2019, 1:45 p.m.

      Думаю, что в методе setData нужно в роли Qt::EditRole делать установку значения. Скорее всего у вас просто не заходит в ту ветку кода выполнение программы. Обычно для установки значения используется именно роль Qt::EditRole

        Ruslan Polupan
        • April 25, 2019, 4:51 p.m.
        • The answer was marked as a solution.

        Изменил функцию
        теперь работает.

        bool ModelTerminals::setData(const QModelIndex &index, const QVariant &value, int role)
        {
            Q_UNUSED(role)
            if(!index.isValid()) {return false;}
        
            m_listTerm[index.row()].setIsCheced(value.toBool());
            emit QAbstractTableModel::dataChanged(index,index);
            return true;
        
        }
        
          Ruslan Polupan
          • May 7, 2019, 1:36 p.m.

          Продолжаем вопросы... (Сори если что :-)
          Как теперь отловить сигнал checked от делегата?

            Ruslan Polupan
            • May 7, 2019, 2:09 p.m.

            Пока сделал так:

            connect(ui->tableViewTerminals->model(),&QAbstractTableModel::dataChanged,this,&SelectTerminalPage::terminalChecked);
            

            Где:

            void SelectTerminalPage::terminalChecked()
            {
                const int rowCount = ui->tableViewTerminals->model()->rowCount(QModelIndex());
            
                for(int i =0; i < rowCount; ++i){
                    if(ui->tableViewTerminals->model()->index(i,0).data(Qt::CheckStateRole).toInt() == Qt::Checked)
                        qInfo(logInfo()) << "Выбрана" << i << "строка";
                }
            
            }
            

            но это отрабатывает изменение модели
            А вот сам клик на checkbox бы отловить...

              Evgenii Legotckoi
              • May 7, 2019, 2:30 p.m.

              Ну по идее есть такой сигнал commitData у делегатов. В данном сигнале высылается указатель на виджет перед записью данных в модель. Можете попробовать на его основе что-то сообразить.

                Ruslan Polupan
                • May 7, 2019, 4:47 p.m.

                Еще обнаружил такую ситуацию. Оказывается данные в модель записываются, лиш после того как фокус получает любой item TableView.
                Т.е. Состояние CheckBox записывается в модель не при изменении его статуса а лишь тогда когда с него теряется фокус.

                  Evgenii Legotckoi
                  • May 7, 2019, 4:51 p.m.

                  Ну в общем-то да, есть такая ситуация. Думаю, что это правильное поведение. Дело в том, что если логика под капотом очень сложная и влияет на большое количество компонентов, то апдейт при редактировании может очень сильно уменьшить скорость работы софта, поскольку такие апдейты будут выполняться тогда, когда по факту в 99% случае они вовсе не нужны.

                    Ruslan Polupan
                    • May 7, 2019, 5:01 p.m.
                    • (edited)

                    Реализовать такую ситуацию:
                    Я выбрал несколько строк и не прешел на другую ячейку а нажал кнопку "Выполнить" например.
                    И тогда получается что последняя мною выбранная запись не попадет для дальнейшей обработки.
                    Или есть таки способ принудительно опросить делегаты и записать их состояние в модель?

                      Comments

                      Only authorized users can post comments.
                      Please, Log in or Sign up
                      Ua

                      Qt - Test 001. Signals and slots

                      • Result:84points,
                      • Rating points4
                      Ua

                      Qt - Test 001. Signals and slots

                      • Result:42points,
                      • Rating points-8
                      ОК

                      Qt - Test 001. Signals and slots

                      • Result:47points,
                      • Rating points-6
                      Last comments
                      ИМ
                      Игорь МаксимовNov. 22, 2024, 9:51 p.m.
                      Django - Tutorial 017. Customize the login page to Django Добрый вечер Евгений! Я сделал себе авторизацию аналогичную вашей, все работает, кроме возврата к предидущей странице. Редеректит всегда на главную, хотя в логах сервера вижу запросы на правильн…
                      Evgenii Legotckoi
                      Evgenii LegotckoiOct. 31, 2024, 11:37 p.m.
                      Django - Lesson 064. How to write a Python Markdown extension Добрый день. Да, можно. Либо через такие же плагины, либо с постобработкой через python библиотеку Beautiful Soup
                      A
                      ALO1ZEOct. 19, 2024, 5:19 p.m.
                      Fb3 file reader on Qt Creator Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html
                      ИМ
                      Игорь МаксимовOct. 5, 2024, 4:51 p.m.
                      Django - Lesson 064. How to write a Python Markdown extension Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
                      d
                      dblas5July 5, 2024, 8:02 p.m.
                      QML - Lesson 016. SQLite database and the working with it in QML Qt Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
                      Now discuss on the forum
                      f
                      firstlunoxodFeb. 15, 2025, 1:46 p.m.
                      Рисование на QGraphicsScene при зажатой кнопке мыши Подскажите, пожалуйста! Как данный класс можно дополнить, чтобы созданные объекты можно было перемещать мышкой по сцене?
                      Дмитрий
                      ДмитрийFeb. 3, 2025, 4:24 p.m.
                      Создание deb-пакета. Как создать ярлык на рабочем столе после установки собственного deb-пакета? Всем привет. Сделал свой deb-пакет с программой. Всё устанавливается и работает. Ставлю по пути /usr/bin/my_application. Как для пользователя при установке пакета сразу создать ярлык на раб…
                      NW
                      Nayo WaiJan. 30, 2025, 7:22 p.m.
                      не запускается компьютер!!! Не запускается компьютер (точнее работает блок , но сам монитор вообще жесть)В общем я ничего с интернета не скачивала в последнее время. На компе никаких левых пр…
                      n
                      nklyJan. 3, 2025, 12:52 p.m.
                      Нужно запретить перемещение только некоторых итемов, остальные перемещать можно. Вопрос решен. Узнать QModelIndex элемента на который мы перетаскиваем другой элемент, можно с помощью функции indexAt(event->position().toPoint()) представления QTreeViev вызываемой в переопр…
                      M
                      MarselAug. 17, 2023, 12:26 a.m.
                      OAuth2.0 через VK, получение email Спасибо большое за помощь и простите за то что отнял время своей невнимательностью.

                      Follow us in social networks