Russian Qt Forum

Qt => Пользовательский интерфейс (GUI) => Тема начата: PavelVX от Август 15, 2012, 12:52



Название: Как получить PartiallyChecked?
Отправлено: PavelVX от Август 15, 2012, 12:52
Есть model + tableview. Хочу одну колонку сделать чекбоксами с тремя состояниями. Для этого в model::flags делаю так:
        flags = flags | Qt::ItemIsTristate | Qt::ItemIsUserCheckable;
Чеки появляются, но при нажатиях на них значения всегда Qt::Checked или Qt::Unchecked! Как же мне получить Qt::PartiallyChecked?
Ответ и через поисковик искал, но или плохо искал, или нет его :(


Название: Re: Как получить PartiallyChecked?
Отправлено: Syveren от Август 16, 2012, 09:18
А как вы в модель устанавливаете потом измененные флаги?
нужно делать либо через item'ы void QStandardItem::setFlags ( Qt::ItemFlags flags ), либо наследоваться от модели и переопределять тот самый flags(), чтобы он возвращал то, что нужно.


Название: Re: Как получить PartiallyChecked?
Отправлено: PavelVX от Август 16, 2012, 09:49
я ж написал:
Для этого в model::flags делаю так:
        flags = flags | Qt::ItemIsTristate | Qt::ItemIsUserCheckable;
Они показываются нормально, кликаются, но получить третье состояние не получается. Либо тру, либо фолс, а третьего нет :(
В методе model::setData, смотрю состояние value, оно всегда или 0 или 2, uncheck или check. как мне мышкой нащелкать PartiallyChecked? Или только как-то насильно присваивать?
То-есть в итоге-то хотелось следующее: есть документ, у него 3 состояния, проверен, не проверен, доки не приходили.
Человек, соответственно, щелкая мышко по этому чеку и должен выставить правильное состояние. Но получается, что или проверен, или нет. Но документ еще не пришел, поэтому и нужен вариант. хз :)


Название: Re: Как получить PartiallyChecked?
Отправлено: fte от Август 16, 2012, 10:15
Цитировать
Есть model + tableview. Хочу одну колонку сделать чекбоксами с тремя состояниями. Для этого в model::flags делаю так:
        flags = flags | Qt::ItemIsTristate | Qt::ItemIsUserCheckable;
Чеки появляются, но при нажатиях на них значения всегда Qt::Checked или Qt::Unchecked! Как же мне получить Qt::PartiallyChecked?
Ответ и через поисковик искал, но или плохо искал, или нет его

Надо переопределить методы data и setData у модели, причем при стандартном вызыве setData с ролью = Qt::CheckStateRole
value принимает только два значения Qt::Checked и Qt::Unchecked
типа так:
Код
C++ (Qt)
QVariant myModel::data ( const QModelIndex &index, int role ) const
{
if (!index.isValid())
return QVariant();
       .........
if( role == Qt::CheckStateRole )
{
if( index.data(Qt::EditRole).isNull() )
return Qt::PartiallyChecked;
               return index.data(Qt::EditRole).toInt() == Qt::Unchecked ? Qt::Unchecked : Qt::Checked;
}
return standardModel::data(index,role);
}
 
bool myModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
.................
if( role == Qt::CheckStateRole )
{
if( flags(index) & Qt::ItemIsTristate )
{
if(index.data(Qt::EditRole).isNull())
    return setData(index,Qt::Checked,Qt::EditRole);
 
setData(index,index.data(Qt::EditRole).toInt() == Qt::Checked ? QVariant():Qt::Unchecked,Qt::EditRole);
}
 
}
.................
}
 





Название: Re: Как получить PartiallyChecked?
Отправлено: PavelVX от Август 16, 2012, 11:59
то-есть предалагется самому вставлять третье значение. У меня тоже только два впихиваются :(
index.data(Qt::EditRole).isNull() - у меня никогда не бывает, постоянно 0 выдает. Может потому, что колонка, над которой это происходит интовая. Но с ходу попробовал над булевой, та же фигня. Но вот с подставить свое значение, это мысль хорошая.


Название: Re: Как получить PartiallyChecked?
Отправлено: PavelVX от Август 16, 2012, 13:00
Частично заработало!!!
Код:
bool myModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
.................
if( role == Qt::CheckStateRole )
{
if( flags(index) & Qt::ItemIsTristate )
{
if(index.data(Qt::EditRole).isNull())
     return setData(index,Qt::Checked,Qt::EditRole);
 
setData(index,index.data(Qt::EditRole).toInt() == Qt::Checked ? QVariant():Qt::Unchecked,Qt::EditRole);
}
 
}
.................
}
Только один момент слегонца непонятен: если я в setData делаю другой setData, то у меня данные правильно запишутся, но на экране они будут такие, как будто прошел основной setData.
Поясняю: у меня последовательность перебора следующая: Qt::Unchecked, Qt::PartiallyChecked, Qt::Checked.
То-есть: жмакаем мышкой и меняем значение с Qt::Unchecked на Qt::Checked! После наших изменения получается, что на
setData(index, Qt::Checked,Qt::EditRole)
вызыватся
setData(index, Qt::PartiallyChecked,Qt::EditRole)
Но на экране отрисовывается как будто нажали
setData(index, Qt::Checked,Qt::EditRole)
Как побороть?


Название: Re: Как получить PartiallyChecked?
Отправлено: Syveren от Август 16, 2012, 13:48
Цитировать
Для этого в model::flags делаю так:
 flags = flags | Qt::ItemIsTristate | Qt::ItemIsUserCheckable;
А где этот флаг обратно записываеться в модель? У моделей отсутсвует метод setFlags(). Вот почему я и спрашивал.
Qt::ItemFlags flags = model->flags() |  Qt::ItemIsTristate | Qt::ItemIsUserCheckable;
Этот код исправил локальную переменную flags, но не модель
Простейший код:
Код
C++ (Qt)
   QStandardItemModel m;
   QListView v;
   v.setModel(&m);
   m.setRowCount(3);
   m.setItem(0,new QStandardItem("item 1"));
   m.setItem(1,new QStandardItem("item 2"));
   m.setItem(2,new QStandardItem("item 3"));
   for(int i=0;i<m.rowCount();++i)
   {
       m.item(i)->setFlags(m.item(i)->flags()|Qt::ItemIsUserCheckable);
       m.item(i)->setData(Qt::PartiallyChecked,Qt::CheckStateRole);
   }
   v.show();
   return a.exec();


Название: Re: Как получить PartiallyChecked?
Отправлено: fte от Август 16, 2012, 15:43
Код:
bool myModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
.................
if( role == Qt::CheckStateRole )
{
if( flags(index) & Qt::ItemIsTristate )
{
if(index.data(Qt::EditRole).isNull())
     return setData(index,Qt::Checked,Qt::EditRole);
 
setData(index,index.data(Qt::EditRole).toInt() == Qt::Checked ? QVariant():Qt::Unchecked,Qt::EditRole);
}

}
.................
}



ну это я без  проверки накидал, как скелет .....

естественно внутри myModel::setData, надо вызывать - baseModel::setData или emit dataChanged,
поэтому частично работает......

давайте Ваш вариант setData подправим....


Название: Re: Как получить PartiallyChecked?
Отправлено: PavelVX от Август 17, 2012, 06:15
Ну ваш скелет потребовал мало доработок, поэтому мой вам за это поклон.
myModel наследник от QSqlTableModel
Код:
bool myModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
/*тут подготовка всякая*/
    if (role == Qt::CheckStateRole)
        if( (flags(index) & Qt::ItemIsTristate ) && (index.data(Qt::EditRole) == Qt::Unchecked) && (value == Qt::Checked))
            return setData(index, Qt::PartiallyChecked, role);
/*
тут собственно запись через вызов доп функции,
все взято с учебников, про редактируемую QSqlQueryModel, но применено к QSqlTableModel
bool setDataToQuery(strWhereCond, index.column(), value);
*/
     bool ok = setDataToQuery(strWhereCond, index.column(), value);
     if (ok) QSqlTableModel::setData(index, value);
     return ok;


}
Как-то так. Все отрабатывается и записывается в базу правильно, но на экран показывает не совсем корректно. Т.е. чек имеет значение Qt::Unchecked, щелкаю по нему мышкой, в базу улетает значение Qt::PartiallyChecked, на экране покажет Qt::Checked. Уже и сигнал emit dataChanged пытался прикрутить, но что-то не так делаю походу.
Код:
    if (role == Qt::CheckStateRole)
        if( (flags(index) & Qt::ItemIsTristate ) && (index.data(Qt::EditRole) == Qt::Unchecked) && (value == Qt::Checked))
        {
            bool ok = setData(index, Qt::PartiallyChecked, role);
            if (ok) emit dataChanged(index, index);
            return ok;
        }
куда дальше копать, пока не представляю. Но самое главное, не понимаю, почему троли, разрешив третье состояние, не сделали его корректную реализацию. Все напильником доделывать приходится :(


Название: Re: Как получить PartiallyChecked?
Отправлено: fte от Август 17, 2012, 10:51
Цитировать
Все отрабатывается и записывается в базу правильно, но на экран показывает не совсем корректно.

Значит метод data надо подправить!
в моем примере Qt::PartiallyChecked - соответствует значению в  базе Null, а у Вас он соответствует значению Qt::PartiallyChecked, т.е. 1


Название: Re: Как получить PartiallyChecked?
Отправлено: PavelVX от Август 17, 2012, 11:04
нет, дело не в дата. В базу пишется null, при переоткрытии формы, данные отобразятся правильно.
Код:
setDataToQuery(strWhereCond, index.column(), value)
{
......
                switch(value.toInt())
                {
                    case Qt::PartiallyChecked: // если данные нет вообще
                        updVal = "null";
                        break;
                    case Qt::Checked: // если check
                        updVal = "1";
                        break;
                    case Qt::Unchecked: // если uncheck
                        updVal = "0";
                        break;
                }
......
}
Я думаю дело в то, что бы прога как-то сама себя известила, что value при записи было изменено :(
Решил приколоться и сделать так: value = Qt::PartiallyChecked;
Но, что не удивитльно :), появляется ошибка:
 passing 'const QVariant' as 'this' argument of 'QVariant& QVariant::operator=(const QVariant&)' discards qualifiers
В общем, какой-то тупик.


Название: Re: Как получить PartiallyChecked?
Отправлено: fte от Август 17, 2012, 12:08
Код:
bool ok = setDataToQuery(strWhereCond, index.column(), value);
вот здесь Вы в базу пишите - null

Код:
if (ok) QSqlTableModel::setData(index, value);
а вот здесь в модель пишете - 1


Название: Re: Как получить PartiallyChecked?
Отправлено: PavelVX от Август 17, 2012, 14:32
Да, именно так :(
А как тогда быть? :(


Название: Re: Как получить PartiallyChecked?
Отправлено: fte от Август 17, 2012, 14:46
if (ok) QSqlTableModel::setData(index, value == Qt::PartiallyChecked ? QVariant():value);


Название: Re: Как получить PartiallyChecked?
Отправлено: PavelVX от Август 20, 2012, 08:38
fte, большой респект и уважуха! :)
кучу времени сегодня потратил, но ВРОДЕ решил проблему :) выкладываю, вдруг кому пригодится.
Для этого поля использовал тип данных int.
Код:
bool myModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
/*обратить внимание, что проверяется не только новое значение, но и состояние, а не значение предыдущего!*/
    if (role == Qt::CheckStateRole)
        if( (flags(index) & Qt::ItemIsTristate ) && (!index.data(Qt::EditRole).isNull()) && (value == Qt::Checked))
            return setData(index, Qt::PartiallyChecked, role);
/*
подготовка и всякая всячина
тут собственно запись через вызов доп функции,
все взято с учебников, про редактируемую QSqlQueryModel, но применено к QSqlTableModel
обратить внимание на сохранение в модель!
Тут 2 момента: само по себе сохранение, и что мы сохраняем для null!! Именно это и было камнем преткновения!
bool setDataToQuery(strWhereCond, index.column(), value);
*/
     bool ok = setDataToQuery(strWhereCond, index.column(), value);
     if (ok) QSqlTableModel::setData(index, (value == Qt::PartiallyChecked ? QVariant( QVariant::Int ):value));
     return ok;
}
В data модели все по прежнему!

PS снимаю свои восторги, не работет полноценно эта хрень!
Если изначально поле пустое, то не дает редактировать, если получекнутое, то дает полноценно. Если чекнутое, то или чек или анчек. Короче, гонит.

PPS Вроде все подправил. Извиняюсь, если кого напрягали мои правки, но мало ли, вдруг кому будет полезен нормальный, работающий код.


Название: Re: Как получить PartiallyChecked?
Отправлено: fte от Август 20, 2012, 10:34
setDataToQuery можете полностью показать?


Название: Re: Как получить PartiallyChecked?
Отправлено: PavelVX от Август 20, 2012, 11:00
fte, все заработало, но тебе большой респект, с
QSqlTableModel::setData(index, (value == Qt::PartiallyChecked ? QVariant( QVariant::Int ):value));
я бы врятли сам допетрил! ;)
см предыдущий пост. я все в кучку свел.


Название: Re: Как получить PartiallyChecked?
Отправлено: chu от Август 21, 2012, 23:42
setDataToQuery можете полностью показать?
+1. Что это за загадочная функция ??? Из кучи предыдущего поста непонятно


Название: Re: Как получить PartiallyChecked?
Отправлено: PavelVX от Август 22, 2012, 06:27
у меня это функция, которая из исходных данных и различных условий формирует SQL запрос и обновляет данные. Посмотрите на пример с редактируемым QSQLQuery. Просто у меня она уже настолько переработана от примера, что смысла приводить её тут нет.


Название: Re: Как получить PartiallyChecked?
Отправлено: break от Сентябрь 16, 2015, 17:37
Что вообще дает Qt::ItemIsTristate во флагах итема, если в результате приходится хаками обрабатывать setData для установки значения в Qt::PartiallyChecked;

Как будто по задумке именно если Qt::ItemIsTristate есть во флаге итема, то и должно в setData приходить не два а три возможных значения....

После того как у себя реализовал этот хак, убрал Qt::ItemIsTristate из флагов - ничего не изменилоь, как работало, так и работает


Код:
				Qt::CheckState state = ( Qt::CheckState )( value.toInt() );

if ( ( state == Qt::Checked ) && ( m_ThreeStateRows[ nROW_ID ] != Qt::PartiallyChecked ) )
state = Qt::PartiallyChecked;

m_ThreeStateRows[ nROW_ID ] = state;

похоже на ошибку Qt