C++ 将按钮添加到 QTableview

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11777637/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 15:31:37  来源:igfitidea点击:

Adding button to QTableview

c++qtqt4

提问by Learner

I have created one table by using QTableviewand QAbstractTableModel. In one of the cells, I want to add one help buttonin the right corner of that cell.

我使用QTableviewand创建了一张表QAbstractTableModel。在其中一个单元格中,我想在该单元格的右上角添加一个帮助按钮

Is there any way to achieve this?

有没有办法实现这一目标?

回答by SingerOfTheFall

You will have to implement your own delegate for that.

您必须为此实现自己的委托。

In Qt, aside from the Data, the Model and the View, you have your Delegates. They provide input capabilities, and they are also responsible for rendering "special" items in the View, which is what you need.

在 Qt 中,除了数据、模型和视图之外,您还有Delegates。它们提供输入功能,并且还负责在视图中呈现“特殊”项目,这正是您所需要的。

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

Qt doc 对这些(关键字:)有很好的介绍Model/View programming,您还可以在此处此处找到一些示例。

Also (a little off-topic, but I think I should point this out), if you use an ordinary QTableWidget, you can insert anything into any cell with it's setCellWidget()function.

另外(有点跑题,但我想我应该指出这一点),如果您使用普通QTableWidget,则可以将任何内容插入具有其setCellWidget()功能的任何单元格中。

UPD

UPD

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

这是Qt 文档中的一个稍微修改过的示例(我很讨厌 Qt 中的模型/视图内容,所以不要为这段代码难倒我)。它将在右侧的每个单元格中绘制一个按钮,并捕获单元格中的单击事件以检查单击是否在“按钮”上,并做出相应的反应。

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

可能这不是最好的方法,但正如我所提到的,我对 Qt 的模型和视图不太好。

To do things right and allow proper editing, you will need to also implement createEditor(), setEditorData()and setModelData()functions.

为了做正确的事情并允许正确编辑,您还需要实现createEditor(),setEditorData()setModelData()功能。

To draw your stuff in a specific cell instead of all cells, just add a condition into the paint()function (note that it gets the model index as an argument, so you can always know in what cell you are painting, and paint accordingly).

要在特定单元格而不是所有单元格中绘制您的东西,只需在paint()函数中添加一个条件(请注意,它将模型索引作为参数,因此您始终可以知道要在哪个单元格中绘制,并相应地绘制)。



delegate.h:

委托.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:

委托.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

结果

回答by ElectRocnic

I've got a solution WITHOUT any complex re-invention of the whole paint-processes. I have a TableView in which I have a button in every row. Note, that, in my case the for loop runs through each row.

我有一个解决方案,无需对整个油漆过程进行任何复杂的重新发明。我有一个 TableView,其中每一行都有一个按钮。请注意,在我的情况下,for 循环贯穿每一行。

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 make your own slot:

然后您会自动获取用户单击按钮所在行的索引。你只需要制作自己的插槽:

private SLOTS:
    void doSomething(int row);

If you have specific cells, it would work similar.

如果您有特定的单元格,它的工作方式类似。

Note, that I did not care about memory leaks in this example, and I don't exactly know what would happen if you update your TableView... (It's working fine, but it might not delete the old button-pointers when new ones are created)

请注意,在这个例子中我并不关心内存泄漏,我也不知道如果你更新你的 TableView 会发生什么......(它工作正常,但当新的按钮指针出现时它可能不会删除旧的按钮指针被创建)

回答by wazza

setIndexWidget worked for me. Example:

setIndexWidget 为我工作。例子:

QPushButton* helpButton = new QPushButton("Help");

tableView->setIndexWidget(model->index(position,COLUMN_NUMBER), helpButton);

If you just want to add a button and do something on click of it, adding a button using setIndexWidget() works fine. I believe we don't need the cumbersome paint method or implementing delegates.

如果您只想添加一个按钮并在单击它时执行某些操作,则使用 setIndexWidget() 添加一个按钮效果很好。我相信我们不需要繁琐的绘制方法或实现委托。

回答by e.shirshov

    // use only standard style  
QApplication::style()->drawControl(QStyle::CE_PushButtonLabel, &button, painter);

For use user styles, need changed:

对于使用用户样式,需要更改:

    //use user style   
QPushButton* real_button = ....; // button inherited user styles
    real_button->style()->drawControl( QStyle::CE_PushButtonLabel, &button, painter, real_button);

回答by Learner

When the view wants to draw a cell it calls the delegate's paint()function with some information about how, what, and where to draw the contents of the cell. The default delegate just draws the Qt::DisplayRoletext and selectionState.

当视图想要绘制一个单元格时,它会调用委托的paint()函数,并提供一些关于如何绘制单元格内容、绘制内容以及绘制单元格内容的信息。默认委托只绘制Qt::DisplayRole文本和selectionState.

If you replace the delegate then you completely replace the default behaviour: you can draw whatever you like. If you want the text then you need to arrange to draw it. You can do it yourself or, using standard C++ mechanisms, you can call the default drawing code first then draw over the top. It works after adding QItemDelegate::paint(painter, option, index);at the beginning of my paint()method .

如果您替换委托,那么您将完全替换默认行为:您可以绘制任何您喜欢的内容。如果你想要文本,那么你需要安排绘制它。您可以自己完成,或者使用标准 C++ 机制,您可以先调用默认绘图代码,然后在顶部绘制。它QItemDelegate::paint(painter, option, index);在我的paint()方法开头添加后起作用。

回答by Learner

I got the 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 .

这是更新后的paint() 方法。

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 .

  }
  }
}