Adding a Button in QTableview

I created one table using QTableview and QAbstractTableModel. In one of the cells I want to add one help button (the right corner of this cell).

Is there a way to achieve the above?

+7
source share
5 answers

To do this, you will have to implement your own delegate.

In Qt, in addition to data, models, and views, you have your delegates. They provide input capabilities, and they are also responsible for providing โ€œspecialโ€ elements in the presentation, which is what you need.

Qt doc has good coverage for those (keywords: Model/View programming ), and you can also find some examples here and here .

Also (a little off topic, but I think I should point this out), if you use a regular QTableWidget , you can insert anything into any cell using the setCellWidget() function.

UPD

here is a slightly modified example from Qt docs (I suck with a model / view in Qt, so don't beat me for this code). He will draw a button in each cell on the right and catch the click events in the cells to check if there was a click on the "button" and react accordingly.

This is probably not the best way to do this, but as I mentioned, I'm not too good with Qt models and views.

To do everything right and allow correct editing, you also need to implement the createEditor() , setEditorData() and setModelData() .

To draw your things in a specific cell instead of all the cells, just add a condition to the paint() function (note that it takes the model index as an argument, so you can always find out which cell you draw in and draw accordingly).


delegate.h:

 class MyDelegate : public QItemDelegate { Q_OBJECT public: MyDelegate(QObject *parent = 0); void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index); }; 

delegate.cpp:

  #include <QtGui> #include "delegate.h" MyDelegate::MyDelegate(QObject *parent) : QItemDelegate(parent) { } void MyDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { QStyleOptionButton button; QRect r = option.rect;//getting the rect of the cell int x,y,w,h; x = r.left() + r.width() - 30;//the X coordinate y = r.top();//the Y coordinate w = 30;//button width h = 30;//button height button.rect = QRect(x,y,w,h); button.text = "=^.^="; button.state = QStyle::State_Enabled; QApplication::style()->drawControl( QStyle::CE_PushButton, &button, painter); } bool MyDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) { if( event->type() == QEvent::MouseButtonRelease ) { QMouseEvent * e = (QMouseEvent *)event; int clickX = e->x(); int clickY = e->y(); QRect r = option.rect;//getting the rect of the cell int x,y,w,h; x = r.left() + r.width() - 30;//the X coordinate y = r.top();//the Y coordinate w = 30;//button width h = 30;//button height if( clickX > x && clickX < x + w ) if( clickY > y && clickY < y + h ) { QDialog * d = new QDialog(); d->setGeometry(0,0,100,100); d->show(); } } return true; } 

main.cpp

 #include "delegate.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); QStandardItemModel model(4, 2); QTableView tableView; tableView.setModel(&model); MyDelegate delegate; tableView.setItemDelegate(&delegate); tableView.horizontalHeader()->setStretchLastSection(true); tableView.show(); return app.exec(); } 

The result will look like this:

result

+16
source

I have a solution WITHOUT any complex re-invention of all paint processes. I have a TableView in which I have a button in each row. Please note that in my case, the for loop runs through each line.

 QSignalMapper *signalMapper = new QSignalMapper(this); for( int i=0; i<rows.length(); i++ ) { //replace rows.length with your list or vector which consists of the data for your rows. //do something with your data for normal cells... auto item = model->index(i, COLUMN_FOR_WHATEVER_YOU_WANT); model->setData(item, QVariant::fromValue(yourObject.getSpecificInformation())); //make new button for this row item = model->index(i, COLUMN_BUTTON); QPushButton *cartButton = new QPushButton("Add"); ui->table_view->setIndexWidget(item, cartButton); signalMapper->setMapping(cartButton, i); connect(cartButton, SIGNAL(clicked(bool)), signalMapper, SLOT(map())); } connect(signalMapper, SIGNAL(mapped(int)), this, SLOT(doSomething(int))); 

Then you automatically get the index of the row in which the user clicked the button. You just need to create your own slot:

 private SLOTS: void doSomething(int row); 

If you have certain cells, it will work similarly.

Please note that in this example I donโ€™t need memory leaks, and I donโ€™t know exactly what will happen if you update your TableView ... (it works fine, but may not delete old pointer buttons when new ones are created)

+5
source

setIndexWidget worked for me. Example:

 QPushButton* helpButton = new QPushButton("Help"); tableView->setIndexWidget(model->index(position,COLUMN_NUMBER), helpButton); 

If you just want to add a button and do something at its click, adding a button using setIndexWidget () works fine. I believe that we do not need a cumbersome drawing method or delegate execution.

+4
source

When a view wants to draw a cell, it calls the delegates paint () function with some information about how, what, and where to draw the contents of the cell. The default delegate simply draws the text and selection state of Qt :: DisplayRole. If you replace the delegate, you completely replace the default behavior: you can draw whatever you like. If you need text, you need to organize its drawing. You can do it yourself or, using standard C ++ mechanisms, you can first call the default drawing code and then draw on top. It works after adding QItemDelegate :: paint (painter, option, index); at the beginning of my paint () method.

0
source

I got a solution. Old Paint Method:

 void MyDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { QStyleOptionButton button; QRect r = option.rect;//getting the rect of the cell int x,y,w,h; x = r.left() + r.width() - 30;//the X coordinate y = r.top();//the Y coordinate w = 30;//button width h = 30;//button height button.rect = QRect(x,y,w,h); button.text = "=^.^="; button.state = QStyle::State_Enabled; QApplication::style()->drawControl( QStyle::CE_PushButton, &button, painter); } 

Here is the updated paint () method.

 void MyDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { QItemDelegate::paint(painter, option, index); if(index.row()==8)//since i have to make it display only at (8,0) position . { if(index.column()==0) { QStyleOptionButton button; QRect r = option.rect;//getting the rect of the cell int x,y,w,h; x = r.left() + r.width() - 20;//the X coordinate y = r.top();//the Y coordinate w = 15;//button width(based on the requirement) h = 15;//button height(based on the requirement) button.icon= QIcon(QString::fromUtf8("Resources/HelpIcon.png")); button.iconSize = QSize(20,20); button.rect = QRect(x,y,w,h); button.text = "";//no text . since if text will be given then it will push the icon to left side based on the coordinates . button.state = QStyle::State_Enabled; //QApplication::style()->drawControl( QStyle::CE_PushButton, &button, painter); QApplication::style()->drawControl( QStyle::CE_PushButtonLabel, &button, painter);//To make the Button transparent . } } } 
0
source

All Articles