向QTableview添加按钮

时间:2012-08-02 12:39:38

标签: c++ qt qt4

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

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

6 个答案:

答案 0 :(得分:20)

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

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

Qt doc对这些内容有很好的报道(关键字:Model/View programming),您还可以找到一些示例herehere

另外(有点偏离主题,但我想我应该指出这一点),如果你使用普通的QTableWidget,你可以使用setCellWidget()函数将任何内容插入任何单元格。

UPD

这是一个来自Qt docs的略微修改的例子(我在Qt中使用模型/视图的东西很糟糕,所以不要为了这段代码而狠狠地打败我)。它将在右侧的每个单元格中绘制一个按钮,并捕获单元格中的单击事件以检查单击是否在“按钮”上,并做出相应的反应。

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

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

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


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();
}

结果如下:

result

答案 1 :(得分:7)

我有一个解决方案,没有任何复杂的重新发明整个油漆过程。 我有一个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)));

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

private SLOTS:
    void doSomething(int row);

如果你有特定的细胞,它会起作用。

请注意,我在此示例中并不关心内存泄漏,而且我也不清楚如果更新TableView会发生什么......(它工作正常,但可能不会删除创建新按钮时的旧按钮指针

答案 2 :(得分:5)

setIndexWidget为我工作。 例如:

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

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

如果你只是想添加一个按钮并点击它做一些事情,使用setIndexWidget()添加一个按钮就可以了。我相信我们不需要繁琐的绘画方法或实施代表。

答案 3 :(得分:2)

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

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

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

答案 4 :(得分:0)

当视图想要绘制单元格时,它会调用委托的paint()函数,其中包含有关绘制单元格内容的方式,内容和位置的一些信息。默认委托只会绘制Qt::DisplayRole文本和selectionState

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

答案 5 :(得分:0)

我得到了解决方案.. 旧油漆方法:

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);
 }

这是更新的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 .

  }
  }
}