Russian Qt Forum

Qt => Model-View (MV) => Тема начата: LeX от Август 26, 2009, 19:53



Название: QTableView и QCheckBox
Отправлено: LeX от Август 26, 2009, 19:53
Доброго времени суток.
Помогите решить проблему :(
Есть QTableView в котором необходимо поместить QCheckBox. Поместил я его по стандарту с помощью делегатов. Так вот проблема в том, что при редактировании ячейки таблицы всё хорошо (появляется QCheckBox), но когда курсор мыши попадает на QCheckBox, то текст в ячейке исчезает, а при отводе с него появляется опять.
В методе паинт уже перерисовал всё что только можно, но текст так и исчезает :(
Вопрос собственно в том, как сделать так чтобы при попадании на QCheckBox текст не исчезал, а оставался на месте.
Попутно, если кто-то занимался: как постоянно отображать QCheckBox?.
Вот собственно код делегата:

Код:
MyChBDelegate::MyChBDelegate(QObject *parent)
: QItemDelegate(parent)
{
}

QWidget *MyChBDelegate::createEditor(QWidget *parent,const QStyleOptionViewItem& /* option */,const QModelIndex&  index ) const
{
QCheckBox *editor = new QCheckBox(parent);
int value = index.model()->data(index,Qt::EditRole).toInt();
editor->setCheckState(value != 0 ? Qt::Checked : Qt::Unchecked);
editor->installEventFilter(const_cast<MyChBDelegate*>(this));
return editor;
}

void MyChBDelegate::setEditorData(QWidget *editor,const QModelIndex &index) const
{
int value = index.model()->data(index, Qt::EditRole).toInt();
QCheckBox *dsb = static_cast<QCheckBox*>(editor);
dsb->setCheckState(value != 0 ? Qt::Checked : Qt::Unchecked);
}

void MyChBDelegate::setModelData(QWidget *editor,QAbstractItemModel *model,const QModelIndex& index) const
{
QCheckBox *dsb = static_cast<QCheckBox*>(editor);
bool value = dsb->checkState();
model->setData(index, value);
}

void MyChBDelegate::updateEditorGeometry(QWidget *editor,const QStyleOptionViewItem &option,const QModelIndex& /* index */) const
{
editor->setGeometry(option.rect);
}

void MyChBDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QVariant value = index.model()->data(index,Qt::EditRole);
QString text = value.toInt() != 0 ? QString::fromUtf8("Да") : QString::fromUtf8("Нет");
QPalette palet;
palet.setColor(QPalette::Text,Qt::red);
palet.setColor(QPalette::HighlightedText,Qt::green);
palet.setColor(QPalette::Highlight,Qt::yellow);
QStyleOptionViewItem myOption = option;
myOption.palette=palet;
myOption.displayAlignment = Qt::AlignCenter;

drawDisplay(painter,myOption,myOption.rect,text);
drawFocus(painter,myOption,myOption.rect);
}


Название: Re: QTableView и QCheckBox
Отправлено: Rcus от Август 26, 2009, 20:01
"broken as intended" ©
::paint управляет отображением вне режима редактирования, а QCheckBox в режиме редактирования.
/** решил бы это через Qt::CheckStateRole без привлечения своих делегатов */


Название: Re: QTableView и QCheckBox
Отправлено: LeX от Август 26, 2009, 20:28
"broken as intended" ©
::paint управляет отображением вне режима редактирования, а QCheckBox в режиме редактирования.
/** решил бы это через Qt::CheckStateRole без привлечения своих делегатов */

Ды рад бы, только используется QSqlTableModel и нельзя переопределить мне метод data  и flags :(
Если подскажешь как по другому можно, я буду рад :)


Название: Re: QTableView и QCheckBox
Отправлено: Rcus от Август 27, 2009, 03:36
Эм то есть как это нельзя? Я пропустил введение final классов в C++? А вещь еще есть проксии модели.


Название: Re: QTableView и QCheckBox
Отправлено: LeX от Август 27, 2009, 08:30
Эм то есть как это нельзя? Я пропустил введение final классов в C++? А вещь еще есть проксии модели.

Да всё там можно  :D Просто говорю что мне нельзя это сделать (поставлена задача таким образом (Использовать в качестве модели QSqlTableModel (нельзя мне говорят переопределять методы flags и data дабы не потерять QSqlTableModel::onManualSubmit запар говорят меньше будет с сохранением результатов, а там в другом месте запар выше крыши появляется) (я и так уже извратился переопределив метод setQuery чтобы писать запросы полнофункциональные (хз чем обернётся, но я бы лучше не делал этого))):() Вот и парюсь (извращаюсь) вешая QCheckBox в делегата  :(

Так есть способ исправить этот недостаток в делегате?


Название: Re: QTableView и QCheckBox
Отправлено: sergeyvl12 от Август 27, 2009, 10:23
Цитировать
Попутно, если кто-то занимался: как постоянно отображать QCheckBox?.

Не знаю поможет это или нет, но я недавно не мог избавиться от чекбоксов (без всяких делегатов).

Избавился...

Вот ссылка: http://www.prog.org.ru/topic_10393_0.html

Они выводились как раз слева от текста. Их можно сделать редактируемыми :)


Название: Re: QTableView и QCheckBox
Отправлено: LeX от Август 27, 2009, 10:41
Не знаю поможет это или нет, но я недавно не мог избавиться от чекбоксов (без всяких делегатов).

Избавился...

Вот ссылка: http://www.prog.org.ru/topic_10393_0.html

Они выводились как раз слева от текста. Их можно сделать редактируемыми :)


Я же говорю нельзя для моей задачи переопределять методы flags и data.
Я мог бы сделать так:
Код:
Qt::ItemFlags MyModel::flags(const QModelIndex &index) const 
{
        Qt::ItemFlags flags = QSqlTableModel::flags(index);
        if (index.column() > 1 && index.column() < 3)
                flags |= Qt::ItemIsEditable;
        if (index.column() == 3)
                flags |= Qt::ItemIsUserCheckable;
        return flags;
}

QVariant MyModel::data(const QModelIndex &index,int role) const
{
        QVariant value = QSqlTableModel::data(index, role);
        switch (role)
        {
        . . .
           case Qt::CheckStateRole:
             if (index.column() == 3)
                return (QSqlTableModel::data(index).toInt() != 0) ? Qt::Checked : Qt::Unchecked;
                        else
                          return value;
        . . .
        }
        return value;
}

Мне нужно решение проблемы через делегаты, если это возможно ???


Название: Re: QTableView и QCheckBox
Отправлено: spectre71 от Август 28, 2009, 09:19
Мне нужно решение проблемы через делегаты, если это возможно ???
Легко.
1) Определяешь в своей модели получение QPixmap от индекса.
2) В делегате получаешь QPixmap для индекса и отрисовываешь

Отрисовка QCheckBox примерно такая:

Код
C++ (Qt)
 drawCheckBox(QStyle::State_Off);
 drawCheckBox(QStyle::State_On);
 drawCheckBox(QStyle::State_Enabled | QStyle::State_Off);
 drawCheckBox(QStyle::State_Enabled | QStyle::State_On);
 drawCheckBox(QStyle::State_Enabled | QStyle::State_Off | QStyle::State_MouseOver);
 drawCheckBox(QStyle::State_Enabled | QStyle::State_On  | QStyle::State_MouseOver);
 drawCheckBox(QStyle::State_Enabled | QStyle::State_Off | QStyle::State_MouseOver | QStyle::State_Sunken);
 drawCheckBox(QStyle::State_Enabled | QStyle::State_On  | QStyle::State_MouseOver | QStyle::State_Sunken);
 
 
QPixmap drawCheckBox(QStyle::State State, QWidget* w) {
 QStyle* Style = QApplication::style();
 QStyleOptionButton StyleOptionButton;
 if(w) {StyleOptionButton.initFrom(w);}
 StyleOptionButton.state = State;
 QRect r = Style->subElementRect (QStyle::SE_CheckBoxIndicator, &StyleOptionButton);
 StyleOptionButton.rect = r;
 if(!(State&QStyle::State_Enabled)) {
   QPalette p = QApplication::palette();
   p.setColor(QPalette::Active, QPalette::Text, p.color(QPalette::Disabled, QPalette::Text));
   StyleOptionButton.palette = p;
 }
 
 QPixmap pixmap(r.width(), r.height());
 pixmap.fill(Qt::transparent);
 QPainter painter;
 painter.begin(&pixmap);
 painter.translate(-r.left(), -r.top());
 Style->drawPrimitive(QStyle::PE_IndicatorCheckBox, &StyleOptionButton, &painter);
 painter.end();
 return pixmap;
}


Название: Re: QTableView и QCheckBox
Отправлено: LeX от Август 28, 2009, 13:25
Легко.
1) Определяешь в своей модели получение QPixmap от индекса.
2) В делегате получаешь QPixmap для индекса и отрисовываешь
А поподробнее рассказать можешь? Я просто этим не занимался ни разу да иопыта в Qt не особо много.

Кстати через флаги сделал. Всё гуд получилось :)
Вот код может кому пригодится
Код:
Qt::ItemFlags QPGTableModel::flags(const QModelIndex &index) const
{
Qt::ItemFlags flags = QSqlTableModel::flags(index);
if (index.column() == 4)
flags |= Qt::ItemIsUserCheckable | Qt::ItemIsEditable;
return flags;
}

QVariant QPGTableModel::data(const QModelIndex &index,int role) const
{
QVariant value = QSqlTableModel::data(index, role);
switch (role)
{
case Qt::DisplayRole:
case Qt::EditRole:
if(index.column()==4)
return value.toInt() != 0 ? QString::fromUtf8("Да") : QString::fromUtf8("Нет");
return QSqlTableModel::data(index,role);
case Qt::CheckStateRole:
if (index.column() == 4)
return (QSqlTableModel::data(index).toInt() != 0) ? Qt::Checked : Qt::Unchecked;
}
return value;
}

bool QPGTableModel::setData(const QModelIndex &index,const QVariant &value,int role)
{
if(role==Qt::CheckStateRole)
return QSqlTableModel::setData(index,value.toBool(),Qt::EditRole);
return QSqlTableModel::setData(index,value);
}

P. S. Руководитель сказал сделать через делегатов  :(


Название: Re: QTableView и QCheckBox
Отправлено: break от Октябрь 18, 2009, 01:44
нет никаких проблем с делегатом - вот рабочий код - отображает и иконку и текст и в режиме редактирования и в режиме отображения
используйте соотв. методы делегата для заполнения значений иконки и текста

Код
C++ (Qt)
#ifndef __CHECKBOX_DELEGATE_H__
#define __CHECKBOX_DELEGATE_H__
 
#include <QItemDelegate>
 
class CChecBox_Delegate : public QItemDelegate
{
Q_OBJECT;
QString m_sIconPath;
QString m_sText;
 
public:
CChecBox_Delegate( QObject * parent = 0 );
QWidget * createEditor( QWidget * parent,
const QStyleOptionViewItem &option,
const QModelIndex &index ) const;
void setEditorData( QWidget * editor, const QModelIndex &index ) const;
void setModelData( QWidget *editor, QAbstractItemModel *model,
  const QModelIndex &index ) const;
void updateEditorGeometry( QWidget *editor,
  const QStyleOptionViewItem &option,
  const QModelIndex &index) const;
void paint( QPainter * painter, const QStyleOptionViewItem &option,
const QModelIndex &index ) const;
 
inline void setIconPath( QString sVal ) { m_sIconPath = sVal; }
inline void setText( QString sVal )     { m_sText = sVal; }
};
 
#endif // __CHECKBOX_DELEGATE_H__
 
 


Код
C++ (Qt)
 
#include "CheckBox_Delegate.h"
 
#include <QCheckBox>
#include <QStylePainter>
#include <QPalette>
#include <QAbstractItemView>
#include <QDebug>
 
CChecBox_Delegate::CChecBox_Delegate( QObject *parent ) : QItemDelegate(parent)
{
m_sIconPath = "";
m_sText = "";
}
 
QWidget * CChecBox_Delegate::createEditor( QWidget * parent,
 const QStyleOptionViewItem& /* option */,
 const QModelIndex&  index ) const
{
QCheckBox * pEditor = new QCheckBox( parent );
pEditor->setText( m_sText );
pEditor->setCheckable( true );
pEditor->setIcon( QIcon( m_sIconPath ) );
 
pEditor -> installEventFilter( const_cast<CChecBox_Delegate*>( this ) );
return pEditor;
}
 
void CChecBox_Delegate::setEditorData( QWidget * editor, const QModelIndex &index) const
{
int value = index.model()->data( index, Qt::EditRole ).toInt();
QCheckBox * cb = static_cast<QCheckBox*>( editor );
 
cb->setChecked( value );
}
 
void CChecBox_Delegate::setModelData( QWidget * editor,
  QAbstractItemModel *model,
  const QModelIndex& index) const
{
QCheckBox * cb = static_cast<QCheckBox*>( editor );
model->setData( index, cb->isChecked() );
}
 
void CChecBox_Delegate::updateEditorGeometry( QWidget *editor,
  const QStyleOptionViewItem &option,
  const QModelIndex& index ) const
{
editor->setGeometry( option.rect );
}
 
void CChecBox_Delegate::paint( QPainter * painter, const QStyleOptionViewItem &option,
 const QModelIndex &index ) const
{
QWidget * w = dynamic_cast<QWidget *>( painter->device() );
if ( w )
{
QStylePainter p( w );
QStyleOptionButton opt;
opt.text = m_sText;
opt.icon = QIcon( m_sIconPath );
opt.iconSize = QSize( 24, 24 );
opt.initFrom( w );
opt.rect = option.rect;
 
bool bChecked = index.data().toInt() > 0;
if ( bChecked )
opt.state |= QStyle::State_On;
p.drawControl( QStyle::CE_CheckBox, opt );
}
 
drawFocus( painter, option, option.rect );
}
 
 


Название: Re: QTableView и QCheckBox
Отправлено: cdsmika от Октябрь 25, 2009, 20:56
Подскажите как расположить QCheckBox по центру колонки при редактировании ячейки в QTableView?


Название: Re: QTableView и QCheckBox
Отправлено: cdsmika от Октябрь 25, 2009, 21:00
Кто-нибудь использовал такой подход:
Код
C++ (Qt)
QItemEditorFactory *factory = new QItemEditorFactory;
factory->registerEditor(QVariant::Bool, new QStandardItemEditorCreator<QCheckBox>());
QItemEditorFactory::setDefaultFactory(factory);
?


Название: Re: QTableView и QCheckBox
Отправлено: cdsmika от Октябрь 25, 2009, 21:32
Кто-нибудь использовал такой подход:
Код
C++ (Qt)
QItemEditorFactory *factory = new QItemEditorFactory;
factory->registerEditor(QVariant::Bool, new QStandardItemEditorCreator<QCheckBox>());
QItemEditorFactory::setDefaultFactory(factory);
?
Так все проще.
Вот прорисовка:
void paint( QPainter * painter, const QStyleOptionViewItem &option,
                    const QModelIndex &index ) const
{
   const QSqlRelationalTableModel *sqlModel =
         qobject_cast<const QSqlRelationalTableModel *>(
               qobject_cast<const QSortFilterProxyModel *>( index.model() )->sourceModel() );

   if ( sqlModel->record(index.row()).field(index.column()).typeID() == 16 )
   {
      QItemDelegate::drawBackground( painter, option, index );
      QItemDelegate::drawCheck( painter, option, option.rect, index.data(Qt::EditRole).toBool() ? Qt::Checked : Qt::Unchecked );
      QItemDelegate::drawFocus( painter, option, option.rect );

   }
   else
      QItemDelegate::paint(painter, option, index);
}


Название: Re: QTableView и QCheckBox
Отправлено: Barmaglodd от Ноябрь 03, 2009, 14:51
У решений с createEditor есть один большой минус - если ячейка не в фокусе, надо 2 раза жать на мышку, чтобы изменить состояние чекбокса.
В архиве делегат, который работает, как при установке Qt::ItemIsUserCheckable.


Название: Re: QTableView и QCheckBox
Отправлено: Yuriy от Август 20, 2011, 22:53
Barmaglodd, спасибо огромное. Давно с этим зверьком боролся. Ваш код великолепно сработал.


Название: Re: QTableView и QCheckBox
Отправлено: Barmaglodd от Август 22, 2011, 14:53
Не за что :)


Название: Re: QTableView и QCheckBox
Отправлено: AlekseyK от Май 01, 2016, 16:16
У решений с createEditor есть один большой минус - если ячейка не в фокусе, надо 2 раза жать на мышку, чтобы изменить состояние чекбокса.
В архиве делегат, который работает, как при установке Qt::ItemIsUserCheckable.
А можно в этом делегате сделать, чтобы при нажатии на ячейку, а не только на чекбокс, отмечать/снимать галочку?


Название: Re: QTableView и QCheckBox
Отправлено: PimenS от Май 01, 2016, 17:16
А можно в этом делегате сделать, чтобы при нажатии на ячейку, а не только на чекбокс, отмечать/снимать галочку?

Можно.


Название: Re: QTableView и QCheckBox
Отправлено: AlekseyK от Май 01, 2016, 19:34
Можно.
:)))))))))))) Как в замечательном грузинском фильме "Самые быстрые в мире":
Цитировать
Посылают телеграмму в другой город: - Ты знаешь адрес родственника, где свадьба?
Поздно вечером приходит ответ: "Знаю!" :)
- Ну тогда пошли! :)))))))

А как?


Название: Re: QTableView и QCheckBox
Отправлено: AlekseyK от Май 01, 2016, 19:36
Barmaglodd, спасибо большое в моём случае тоже заработало, только подправил немного под логику своей модели и в одном месте пришлось DisplayRole совместить с EditRole.


Название: Re: QTableView и QCheckBox
Отправлено: AlekseyK от Май 01, 2016, 19:49
А можно в этом делегате сделать, чтобы при нажатии на ячейку, а не только на чекбокс, отмечать/снимать галочку?
Нужно всего лишь вот это удалить:
Код
C++ (Qt)
|| !cr.contains(me->pos())
Спасибо!


Название: Re: QTableView и QCheckBox
Отправлено: PimenS от Май 01, 2016, 22:05
А как?

Для того, чтобы ответить на этот вопрос, нужно как минимум видеть, что у вас уже написано.

Цитировать
чтобы при нажатии на ячейку

Нажатием чего вы хотите изменить чекбокс? У меня например в программе есть вьюхи которые меняют чекбокс в выделенной строке, при нажатии на интер, есть
меняющие чекбокс при клике мышкой по ячейке. Что именно вы хотите получить?


Название: Re: QTableView и QCheckBox
Отправлено: AlekseyK от Май 04, 2016, 01:21
Для того, чтобы ответить на этот вопрос, нужно как минимум видеть, что у вас уже написано.
Я уже ответил на это выше. Вопрос решён. А написано в точности в соответствии с делегатом товарища Barmaglodd: ссылка но код есть выше в теме.