Russian Qt Forum
Сентябрь 30, 2024, 10:36 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: Как получить PartiallyChecked?  (Прочитано 9431 раз)
PavelVX
Гость
« : Август 15, 2012, 12:52 »

Есть model + tableview. Хочу одну колонку сделать чекбоксами с тремя состояниями. Для этого в model::flags делаю так:
        flags = flags | Qt::ItemIsTristate | Qt::ItemIsUserCheckable;
Чеки появляются, но при нажатиях на них значения всегда Qt::Checked или Qt::Unchecked! Как же мне получить Qt::PartiallyChecked?
Ответ и через поисковик искал, но или плохо искал, или нет его Грустный
« Последнее редактирование: Август 15, 2012, 12:54 от PavelVX » Записан
Syveren
Гость
« Ответ #1 : Август 16, 2012, 09:18 »

А как вы в модель устанавливаете потом измененные флаги?
нужно делать либо через item'ы void QStandardItem::setFlags ( Qt::ItemFlags flags ), либо наследоваться от модели и переопределять тот самый flags(), чтобы он возвращал то, что нужно.
« Последнее редактирование: Август 16, 2012, 09:20 от Syveren » Записан
PavelVX
Гость
« Ответ #2 : Август 16, 2012, 09:49 »

я ж написал:
Для этого в model::flags делаю так:
        flags = flags | Qt::ItemIsTristate | Qt::ItemIsUserCheckable;
Они показываются нормально, кликаются, но получить третье состояние не получается. Либо тру, либо фолс, а третьего нет Грустный
В методе model::setData, смотрю состояние value, оно всегда или 0 или 2, uncheck или check. как мне мышкой нащелкать PartiallyChecked? Или только как-то насильно присваивать?
То-есть в итоге-то хотелось следующее: есть документ, у него 3 состояния, проверен, не проверен, доки не приходили.
Человек, соответственно, щелкая мышко по этому чеку и должен выставить правильное состояние. Но получается, что или проверен, или нет. Но документ еще не пришел, поэтому и нужен вариант. хз Улыбающийся
« Последнее редактирование: Август 16, 2012, 09:57 от PavelVX » Записан
fte
Гость
« Ответ #3 : Август 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);
}
 
}
.................
}
 



Записан
PavelVX
Гость
« Ответ #4 : Август 16, 2012, 11:59 »

то-есть предалагется самому вставлять третье значение. У меня тоже только два впихиваются Грустный
index.data(Qt::EditRole).isNull() - у меня никогда не бывает, постоянно 0 выдает. Может потому, что колонка, над которой это происходит интовая. Но с ходу попробовал над булевой, та же фигня. Но вот с подставить свое значение, это мысль хорошая.
« Последнее редактирование: Август 16, 2012, 12:35 от PavelVX » Записан
PavelVX
Гость
« Ответ #5 : Август 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)
Как побороть?
Записан
Syveren
Гость
« Ответ #6 : Август 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();
« Последнее редактирование: Август 16, 2012, 13:57 от Syveren » Записан
fte
Гость
« Ответ #7 : Август 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 подправим....
Записан
PavelVX
Гость
« Ответ #8 : Август 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;
        }
куда дальше копать, пока не представляю. Но самое главное, не понимаю, почему троли, разрешив третье состояние, не сделали его корректную реализацию. Все напильником доделывать приходится Грустный
« Последнее редактирование: Август 17, 2012, 06:49 от PavelVX » Записан
fte
Гость
« Ответ #9 : Август 17, 2012, 10:51 »

Цитировать
Все отрабатывается и записывается в базу правильно, но на экран показывает не совсем корректно.

Значит метод data надо подправить!
в моем примере Qt::PartiallyChecked - соответствует значению в  базе Null, а у Вас он соответствует значению Qt::PartiallyChecked, т.е. 1
Записан
PavelVX
Гость
« Ответ #10 : Август 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
В общем, какой-то тупик.
Записан
fte
Гость
« Ответ #11 : Август 17, 2012, 12:08 »

Код:
bool ok = setDataToQuery(strWhereCond, index.column(), value);
вот здесь Вы в базу пишите - null

Код:
if (ok) QSqlTableModel::setData(index, value);
а вот здесь в модель пишете - 1
Записан
PavelVX
Гость
« Ответ #12 : Август 17, 2012, 14:32 »

Да, именно так Грустный
А как тогда быть? Грустный
Записан
fte
Гость
« Ответ #13 : Август 17, 2012, 14:46 »

if (ok) QSqlTableModel::setData(index, value == Qt::PartiallyChecked ? QVariant():value);
Записан
PavelVX
Гость
« Ответ #14 : Август 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 Вроде все подправил. Извиняюсь, если кого напрягали мои правки, но мало ли, вдруг кому будет полезен нормальный, работающий код.
« Последнее редактирование: Август 20, 2012, 10:54 от PavelVX » Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.09 секунд. Запросов: 21.