For application I was using some different mechanism to create button inside custom item delegate, but now I found better way to create custom item delegate with QPushButton. So thought to share code.
Following is code for custom item delegate derived from QItemDelegate.
Update: I have uploaded following code to gitorous, Please visit this link if you want a working sample code.
#include <QItemDelegate> class CustomItemDelegate : public QItemDelegate { Q_OBJECT public: CustomItemDelegate(QObject *parent = 0); virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const ; virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const ; bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index); signals: void buttonClicked(const QModelIndex &index); private: QStyle::State _state; }; #include "customitemdelegate.h" ... CustomItemDelegate::CustomItemDelegate(QObject *parent) : QItemDelegate(parent) { _state = QStyle::State_Enabled; } void CustomItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { const QStandardItemModel* model = static_cast<const QStandardItemModel*>(index.model()); QStandardItem* item = model->item(index.row()); QString text = item->text(); QRect rect = option.rect; QRect textRect( rect); textRect.setHeight( 30); painter->drawText(textRect,text); QRect buttonRect( rect); buttonRect.setY(textRect.y()+ 35); buttonRect.setHeight( 30); QStyleOptionButton button; button.rect = buttonRect; button.text = text; button.state = _state | QStyle::State_Enabled; QApplication::style()->drawControl (QStyle::CE_PushButton, &button, painter); } QSize CustomItemDelegate::sizeHint(const QStyleOptionViewItem &/*option*/, const QModelIndex &/*index*/) const { //hard coding size for test purpose, //actual size hint can be calculated from option param return QSize(800,70); } bool CustomItemDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) { if( event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseButtonRelease ) { } else { //ignoring other mouse event and reseting button's state _state = QStyle::State_Raised; return true; } QRect buttonRect( option.rect); buttonRect.setY(option.rect.y()+ 35); buttonRect.setHeight( 30); QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event); if( !buttonRect.contains( mouseEvent->pos()) ) { _state = QStyle::State_Raised; return true; } if( event->type() == QEvent::MouseButtonPress) { _state = QStyle::State_Sunken; } else if( event->type() == QEvent::MouseButtonRelease) { _state = QStyle::State_Raised; emit buttonClicked( index); } return true; }Basically in above code, I am calculating rect where I want to draw my button and drawing QPushButton on list item using QStyleOptionButton class.
And in editor event on mouse press and release event, I am checking if mouse position on click falls into my button's rect or not. If it falls inside my button's rect then I am emitting signal.
I am using item's signal as shown in below code.
CustomList::CustomList(QWidget *parent) : QWidget(parent),_view(0) { _view = new QListView(); _view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); _view->setEditTriggers(QAbstractItemView::NoEditTriggers); //creating custom item delegate and setting it to view CustomItemDelegate* itemDelegate = new CustomItemDelegate(_view); _view->setItemDelegate( itemDelegate ); _view->setModel(&_model); //connecting delegate's signal to this class's slot connect(itemDelegate,SIGNAL(buttonClicked(QModelIndex)), this,SLOT(listButtonClicked(QModelIndex))); QHBoxLayout* mainLayout = new QHBoxLayout(this); mainLayout->addWidget( _view); //creating and adding data to model QStandardItem* item = new QStandardItem; item->setText("testing"); QStandardItem* item1 = new QStandardItem; item1->setText("testing1"); _model.appendRow(item); _model.appendRow(item1); } // following slot will be invoked when delegate's button is clicked void CustomList::listButtonClicked(const QModelIndex &index) { qDebug() << "######### listbutton clicked ######### " << index.row(); }Following is snap of how custom item delegate looks.
Hi Kunal, ur blog is really helpful one for beginning to use Qt.
ReplyDeleteI have sent you a mail, in case you have missed it. Thanx. :)
Hi,Thanks for writing. I will check and reply.
ReplyDeleteVery nice code!! i have tried it, but i have the problem that just the first click to a button it make me all the buttons as clicked... but if click another place of table it doesn't happens.. do you know why can it be?
ReplyDeleteCurrently not sure of exact problem, It seems to me that there is some problem regarding calculation to check mouse point inside button rect or not.
ReplyDeleteI will look in to my sample and see what happens there.
Thanks for writing.
Hi Kunal, the code is pretty good. One quick question, are you able to check the problem that just the first click to a button it make me all the buttons as clicked, I have the exact same problem. Thanks!
ReplyDeleteAhh.. looks like i forget to work on this, I will soon try to answer you. Thanks for checking my blog.
ReplyDeleteHi, I tried to reproduce the problem, but was not able to reproduce it. I have uploaded my code to gitorous, which is working fine. Please use this code and see if has same issue or not.
ReplyDeletehttps://gitorious.org/kunaltest/kunaltest/trees/master/testdelegate
Anyone solved this problem ? Got also that same one...
ReplyDeleteMee too
ReplyDeleteI solved this problem.
ReplyDeleteAll you need is to add parameter, for example:
int _currentRow
It will show current row in paint function.
In editorEvent set this parameter in case of QMousePressEvent:
_currentRow = index.row();
And in case of QMouseReleaseEvent:
_currentRow = -1;
And of course in constructor set:
_currentRow = -1;
Than in delegate paint function do something like that:
if (_currentRow == index.row)
{
/// Draw button with QStyle::State_Sunken style
}
else
{
/// Draw button with QStyle::State_Sunken style
}
That's all. It works!
If somebody needs code example, my mail BootGenius@yandex.ru
I have made a mistake.
DeleteAfter last else it needs to write:
/// Draw button with QStyle::State_Raised style
Thanx you, bro
DeleteWhat if you want to paint focus on the element clicked? if say, it was a qcheckbox?
ReplyDelete