24 апреля 2019 г. 6:07

Помогите разобраться с 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);
    }

}
Рекомендуем хостинг TIMEWEB
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.
10

Добрый день

А вот этот код

    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;
    }
0

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

0

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

0
  • 25 апреля 2019 г. 6:51
  • Ответ был помечен как решение.

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

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;

}
1

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

0

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

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 бы отловить...

0

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

0

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

0

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

0

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

0

Комментарии

Только авторизованные пользователи могут публиковать комментарии.
Пожалуйста, авторизуйтесь или зарегистрируйтесь
МБ
14 июля 2019 г. 17:57
Максим Беликов

C++ - Тест 005. Структуры и Классы

  • Результат:100баллов,
  • Очки рейтинга10
МБ
14 июля 2019 г. 17:52
Максим Беликов

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

  • Результат:90баллов,
  • Очки рейтинга8
МБ
14 июля 2019 г. 17:45
Максим Беликов

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

  • Результат:71баллов,
  • Очки рейтинга1
Последние комментарии
16 июля 2019 г. 15:15
Евгений Легоцкой

Конечно )) На самом деле не все читали Шлее... я например не читал ))
16 июля 2019 г. 15:05
IscanderChe

Так пример с QLocalServer и QLocalSocket я целиком переписал с QTcpSocket и QTcpServer из книги Шлее. Принципиальное отличие - где коннект ставить. :)) Разве что на это упор сделать. Но я могу...
16 июля 2019 г. 14:47
Евгений Легоцкой

Лучше API ))) Кстати, по использованию QLocalServer и QLocalSocket на сайте нет статей, было бы очень полезно и хорошо пошло бы в раздел Qt.
16 июля 2019 г. 12:36
IscanderChe

Да, прямой доступ не предполагается. Впрочем, можно, конечно, и напрямую. Всё равно всё локально происходит. Проблема в том, как донести сведения об изменениях в базе, которые вносит клиент, д...
b
16 июля 2019 г. 8:38
bbb116

спасибо, до smart pointer еще не дошел )
Сейчас обсуждают на форуме
17 июля 2019 г. 11:49
Михаиллл

В настройкак указан индификатор проекта и ключ. Осталось понять как использовать ключ. Попробовал вставить в этот запрос 'https://[PROJECT_ID].firebaseio/users/jack/name.json?access_to...
b
17 июля 2019 г. 9:01
bbb116

Вообщем работает только если делать setSceneRect только в конструкторе главного окна, если потом менять rect например при вставке картинки то появляются сколлы все как надо только области не р...
17 июля 2019 г. 5:54
Алексей Внуков

хочу не стандартный набор символов, а все ненужное убрать чтоб не мешало. для начала решил посмотреть как работает клава на родном примере, а он на телефоне не взлетел вот и начал разби...
17 июля 2019 г. 5:06
Михаиллл

Добрый день.Возможно вы сталкивались с облаками.Нужно из Qt создавать на облаке папки, записывать в папки файлы, читать и удалять с компьютера файлы.Возможно знаете, что лучше и проще испол...
Ищу работу?
25,000.00 руб. - 30,000.00 руб.
Разработчик Qt/C++
Barnaul, Altai Krai, Russia

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

EVILEG
О нас
Услуги
Присоединяйтесь к нам
© EVILEG 2015-2019
Рекомендует хостинг TIMEWEB