Russian Qt Forum

Qt => Model-View (MV) => Тема начата: paxerus от Январь 11, 2010, 10:59



Название: QSqlQueryModel ,QAbstractItemModel
Отправлено: paxerus от Январь 11, 2010, 10:59
Добрый день

У меня есть наследник от QSqlQueryModel , хотелось бы перегрузить  QAbstractItemModel и связать както её с со своим наследником.

Другими словами мне нужно в итемах QSqlQueryModel иметь доп поля,сам QSqlQueryModel я перегрузил но как теперь перегрузить итемы?



Название: Re: QSqlQueryModel ,QAbstractItemModel
Отправлено: lit-uriy от Январь 11, 2010, 11:34
>>Другими словами мне нужно в итемах QSqlQueryModel иметь доп поля
а точнее, что за допполя?


Название: Re: QSqlQueryModel ,QAbstractItemModel
Отправлено: paxerus от Январь 11, 2010, 11:42
мне нужно как минимум ввести целочисленное(или просто bool) поле отвечает за то, будут ли по этому итему в дальнейшем вестись вычисления, менять значения в этом поле буду в методе data
в начале хотел в самом методе data записывать данные в QModelIndex &index, например методом setdata но у него нет такого в публичных, поэтому приходиться извращаться


Название: Re: QSqlQueryModel ,QAbstractItemModel
Отправлено: paxerus от Январь 11, 2010, 11:47
если в поле присутствует значение из value_mask то значит в него нужно соотв-й статус поставить
Код:
QVariant CustomQueryModel::data(const QModelIndex &index, int role) const
{
    QVariant value = QSqlQueryModel::data(index, role);
QString sss;
QVariant ret;
if(status_mask)
{
if (role == Qt::DisplayRole && index.column() == 5)
{
if(value_mask.isValid())


if(value_mask.type() == QVariant::Type::String)
{ QStringList sss;
QRegExp reg("(.*)"+value_mask.toString()+"(.*);");
QString exp(value.toString());

if(reg.exactMatch(exp)>=0)
sss.append(reg.cap(2));

if(!sss.isEmpty())
{
  // тут чтото типа index.setdata()
}
else
{
  // тут чтото типа index.setdata()
}

}
else if (role == Qt::TextColorRole )
{
if(index.data(Qt::UserRole) == -1)
qVariantFromValue(QColor(Qt::red));
else  qVariantFromValue(QColor(Qt::green));
}
}

}

}


    return value;
}


Название: Re: QSqlQueryModel ,QAbstractItemModel
Отправлено: crossly от Январь 11, 2010, 11:52
а почему бы это значение не [хранить к примеру в UserRole+1


Название: Re: QSqlQueryModel ,QAbstractItemModel
Отправлено: paxerus от Январь 11, 2010, 11:59
а почему бы это значение не [хранить к примеру в UserRole+1

Примерчик можно?


Название: Re: QSqlQueryModel ,QAbstractItemModel
Отправлено: crossly от Январь 11, 2010, 21:04
а чем вам ваш же примерчик не нравится.... добавить еще метод setData и все..


Название: Re: QSqlQueryModel ,QAbstractItemModel
Отправлено: paxerus от Январь 12, 2010, 14:09
а чем вам ваш же примерчик не нравится.... добавить еще метод setData и все..

еслиб все было так просто то давно бы сделал.
метод QVariant   data(const QModelIndex &item, int role) const; константный и не получается из него ниче меня при компиляции дает ошибку  cannot convert 'this' pointer from 'const CustomQueryModel' to 'QObject &'
, если сделать не константным то соотв-о он не будет виртуальным
какие идеи?


Название: Re: QSqlQueryModel ,QAbstractItemModel
Отправлено: crossly от Январь 12, 2010, 18:57
чет я вообще ниче понять не могу.... опишите подробнее в чем задача.... и причем тут виртуальность вообще??


Название: Re: QSqlQueryModel ,QAbstractItemModel
Отправлено: MoPDoBoPoT от Январь 12, 2010, 22:54
Менять какие-либо значения в методе data() - моветон, потому как этот метод зовется из прикрепленного к модели представления для отрисовки итема. Значит, каждый раз при отрисовки будет проверяться соответствие некой маске и перезапись старого (такого же) значения, то есть выполняется одна и та же работа.
Изменение значения этого доп. поля для итема надо производить после загрузки новых данных (переопределить setQuery(), только надо будет что-нибудь придумать для fetchMore) и после изменения значений итема (переопределить setData()), если такое подразумевается.
Замечания:
1.
Код:
QVariant CustomQueryModel::data(const QModelIndex &index, int role) const
{
    ...
if (role == Qt::DisplayRole && index.column() == 5)   // __role == Qt::DisplayRole__
{
...
if(value_mask.type() == QVariant::Type::String)
{
...
}
else if (role == Qt::TextColorRole ) //<=сюда никогда не зайдем, т.к. role = Qt::DisplayRole
{
...
}
}

}

}


    return value;
}
2. Для изменения значения члена класса в константном методе сущетсвует спецификатор mutable.


Название: Re: QSqlQueryModel ,QAbstractItemModel
Отправлено: paxerus от Январь 13, 2010, 10:34
чет я вообще ниче понять не могу.... опишите подробнее в чем задача.... и причем тут виртуальность вообще??
абстрагируемся от того что написано. у меня есть QSqlQueryModel, есть QTableView отображения
В возвращаемых с базы данных в одном из полей(текстового) есть есть грубо говоря ключ (например "key="),
если он присутствует в этом поле то нужно для текущей записи установить какое то признак что он присутствует(все что после нужно тоже считать в другую переменную которую  желательно тоже привязать привязать к итему) что б я потом где нить, напимер в делегате(но не обязательно в нем) от QTableView мог видеть такие записи, и например мог раскрасить их или еще что с ними сделать.
Т.е мне нужно что в итемах был признак присутствия ключа в заданном поле


Название: Re: QSqlQueryModel ,QAbstractItemModel
Отправлено: Kolobok от Январь 13, 2010, 11:45
А разве присутствие ключа не является признаком того, что он присутствует?


Название: Re: QSqlQueryModel ,QAbstractItemModel
Отправлено: paxerus от Январь 13, 2010, 12:57
А разве присутствие ключа не является признаком того, что он присутствует?
ну можно просто в текстовое поле писать и проверять его на пустоту,если нету значение.важен сам принцип


Название: Re: QSqlQueryModel ,QAbstractItemModel
Отправлено: crossly от Январь 13, 2010, 14:05
лан.... есть у нас метод дата.... есть у нас QSqlQuery у модели... к примеру нужное значение у нас во 2й колноке, а кеу в 4....
Код:
....
query.seek(index.row());
if(index.column()==1){
        switch(role){
              case Qt::UserRole+1:
                      return query.value(3);
              default:
                      return query.value(index.column());

        }
}else
       return query.value(index.column());

.....

это конечно грубо..... ну суть должна быть понятна.... в итоге в UserRole+1 2й колонки мы получаем твой key.... хотя зачем так делать я так и не понял.... он же в любом случае будет отражатся в 4й колонке... почему бы его оттуда не использовать...




Название: Re: QSqlQueryModel ,QAbstractItemModel
Отправлено: paxerus от Январь 13, 2010, 14:08
лан.... есть у нас метод дата.... есть у нас QSqlQuery у модели... к примеру нужное значение у нас во 2й колноке, а кеу в 4....
Код:
....
query.seek(index.row());
if(index.column()==1){
        switch(role){
              case Qt::UserRole+1:
                      return query.value(3);
              default:
                      return query.value(index.column());

        }
}else
       return query.value(index.column());

.....

это конечно грубо..... ну суть должна быть понятна.... в итоге в UserRole+1 2й колонки мы получаем твой key.... хотя зачем так делать я так и не понял.... он же в любом случае будет отражатся в 4й колонке... почему бы его оттуда не использовать...




Потому что колонка текстовая и парсить её я хочу на начальном этапе,а не потом где то глубоко в программе и по 100 раз, ,спасибо за метод, попробую


Название: Re: QSqlQueryModel ,QAbstractItemModel
Отправлено: crossly от Январь 13, 2010, 14:27
на практике.... если вы наследуетесь от QSqlQueryModel.... то соответственно и данные вам надо брать не из query а из data базового класса ... т.е. QSqlQueryModel::data....


Название: Re: QSqlQueryModel ,QAbstractItemModel
Отправлено: paxerus от Январь 13, 2010, 14:47
на практике.... если вы наследуетесь от QSqlQueryModel.... то соответственно и данные вам надо брать не из query а из data базового класса ... т.е. QSqlQueryModel::data....
да, я так и беру


Название: Re: QSqlQueryModel ,QAbstractItemModel
Отправлено: MoPDoBoPoT от Январь 13, 2010, 16:05
Я же писал, что парсить надо в методе setQuery (путем переопределения). После выбора данных делаем разбор, и запоминаем что надо (признак или еще что-то в нашу структуру, например, QList). А в методе data уже обрабатываем этот признак (подкрашиваем и т.п.)


Название: Re: QSqlQueryModel ,QAbstractItemModel
Отправлено: crossly от Январь 13, 2010, 16:30
Я же писал, что парсить надо в методе setQuery (путем переопределения). После выбора данных делаем разбор, и запоминаем что надо (признак или еще что-то в нашу структуру, например, QList). А в методе data уже обрабатываем этот признак (подкрашиваем и т.п.)
а если модель только для чтения... ??.... тем более что это все равно надо хранить в базе...


Название: Re: QSqlQueryModel ,QAbstractItemModel
Отправлено: MoPDoBoPoT от Январь 13, 2010, 16:35
а если модель только для чтения... ??
Ну, а в чем проблема? Я так и предполагал.
тем более что это все равно надо хранить в базе...
Где это сказано?


Название: Re: QSqlQueryModel ,QAbstractItemModel
Отправлено: paxerus от Январь 14, 2010, 07:25
В принципи предложенный метод меня вполне устраивает , в методе дата делаю разбор и возвращаю строку, но есть другой вопрос насколько быстро это будет происходить, тут ведь нужно постоянно RegExp делать при каждом выове Data,а если строк много например не будет ли тормозить?
В данном случае возможно setquery может быть лучше, я правильно понимаю что если делать через него то я смогу непросто подставлять данные а еще и сохраню их?


Название: Re: QSqlQueryModel ,QAbstractItemModel
Отправлено: crossly от Январь 14, 2010, 14:03
а если модель только для чтения... ??
Ну, а в чем проблема? Я так и предполагал.
тем более что это все равно надо хранить в базе...
Где это сказано?
ну использование QSqlQueryModel предполагает использование БД...


Название: Re: QSqlQueryModel ,QAbstractItemModel
Отправлено: paxerus от Январь 14, 2010, 14:36
данные я не меняю в таблице, и вообще прямого изменения данных у меня нет, только через вызов процедур


Название: Re: QSqlQueryModel ,QAbstractItemModel
Отправлено: MoPDoBoPoT от Январь 14, 2010, 15:09
ну использование QSqlQueryModel предполагает использование БД...
Я, как бы, в курсе :) Как я понял, предполагается читать данные из таблички БД и на стороне клиента как-то обработать/распарсить данные, выделив некую особенность, и указать на нее (цветом выделить или еще как-то). Исходя из этого я предложил разбор данных делать не каждый раз в методе data(), а один раз в методе setQuery() и закэшировать результат в какой-нибудь структуре (для признаков подойдет QBitArray). А в методе data() возпользоваться ранее полученными результатами разбора.
Например:
Код:
class CustomQueryModel : public QSqlQueryModel
{
Q_OBJECT
...
private:
conts int parseColumn; //номер столбца, в который надо разобрать
QBitArray *bitArray;       //массив признаков (наличие "ключа")
...
};
Код:
...
void CustomQueryModel::setQuery(const QSqlQuery & query)
{
QSqlQueryModel::setQuery(query);

//выбираем все данные, а то хз как их потом разобрать
while (myModel->canFetchMore())
    myModel->fetchMore();

parseData();   //<=в этом методе идет разбор данных
}

void CustomQueryModel::setQuery(const QString & query, const QSqlDatabase & db/* = QSqlDatabase()*/)
{
CustomQueryModel::setQuery(QSqlQuery(query, db));
}

void CustomQueryModel::parseData()
{
int count = rowCount();
QString strData;            //строка данных

//переинициализируем массив признаков
delete bitArray;
bitArray = new QBitArray(count, false);

for (int i = 0; i < count; ++i) {
strData = QSqlQueryModel::index(i, parseColumn).data().toString();
//далее идет проверка на наличие "ключа" и запись признака...
}
}

QVariant CustomQueryModel::data(const QModelIndex &index, int role) const
{
QVariant value = QSqlQueryModel::data(index, role);

//если "наш" столюец и роль= Qt::TextColorRole, то подкрашиваем текст
if (index.column() == parseColumn && role == ) {
if (bitArray->testBit(index.row())) {
return qVariantFromValue(QColor(Qt::green));
} else {
return qVariantFromValue(QColor(Qt::red));
}
}

return value;
}
...
НО возможно лучше будет денормализовать саму таблицу в БД, добавив еще одно поле - этот самый признак (чтобы каждый раз на каждом клиенте не делать разбор). Этот признак будет расчитываться в триггере на добавление/обновление записи в таблице БД.


Название: Re: QSqlQueryModel ,QAbstractItemModel
Отправлено: paxerus от Январь 15, 2010, 11:33
ну использование QSqlQueryModel предполагает использование БД...
Я, как бы, в курсе :) Как я понял, предполагается читать данные из таблички БД и на стороне клиента как-то обработать/распарсить данные, выделив некую особенность, и указать на нее (цветом выделить или еще как-то). Исходя из этого я предложил разбор данных делать не каждый раз в методе data(), а один раз в методе setQuery() и закэшировать результат в какой-нибудь структуре (для признаков подойдет QBitArray). А в методе data() возпользоваться ранее полученными результатами разбора.
Например:
Код:
class CustomQueryModel : public QSqlQueryModel
{
Q_OBJECT
...
private:
conts int parseColumn; //номер столбца, в который надо разобрать
QBitArray *bitArray;       //массив признаков (наличие "ключа")
...
};
Код:
...
void CustomQueryModel::setQuery(const QSqlQuery & query)
{
QSqlQueryModel::setQuery(query);

//выбираем все данные, а то хз как их потом разобрать
while (myModel->canFetchMore())
    myModel->fetchMore();

parseData();   //<=в этом методе идет разбор данных
}

void CustomQueryModel::setQuery(const QString & query, const QSqlDatabase & db/* = QSqlDatabase()*/)
{
CustomQueryModel::setQuery(QSqlQuery(query, db));
}

void CustomQueryModel::parseData()
{
int count = rowCount();
QString strData;            //строка данных

//переинициализируем массив признаков
delete bitArray;
bitArray = new QBitArray(count, false);

for (int i = 0; i < count; ++i) {
strData = QSqlQueryModel::index(i, parseColumn).data().toString();
//далее идет проверка на наличие "ключа" и запись признака...
}
}

QVariant CustomQueryModel::data(const QModelIndex &index, int role) const
{
QVariant value = QSqlQueryModel::data(index, role);

//если "наш" столюец и роль= Qt::TextColorRole, то подкрашиваем текст
if (index.column() == parseColumn && role == ) {
if (bitArray->testBit(index.row())) {
return qVariantFromValue(QColor(Qt::green));
} else {
return qVariantFromValue(QColor(Qt::red));
}
}

return value;
}
...
НО возможно лучше будет денормализовать саму таблицу в БД, добавив еще одно поле - этот самый признак (чтобы каждый раз на каждом клиенте не делать разбор). Этот признак будет расчитываться в триггере на добавление/обновление записи в таблице БД.
Спасибо ,вроде как данный метод самый целесообразный, денормализовать саму базу не могу, данные не мои и база от другой системы,в которую нельзя залезть