【问题标题】:Adding button to QTableview将按钮添加到 QTableview
【发布时间】:2012-08-02 12:39:37
【问题描述】:

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

有什么办法可以做到吗?

【问题讨论】:

    标签: c++ qt qt4


    【解决方案1】:

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

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

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

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

    UPD

    这是来自 Qt 文档的稍微 修改的示例(我在 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();
    }
    

    结果将如下所示:

    【讨论】:

    • 我正在使用 QTableview 。我想把那个按钮放在一个特定的单元格中(那个单元格的右上角)..你能分享一些代码吗?感谢广告中的 ..
    • @vikuseth,哦,它对我来说总是可见的。
    • 你是对的 .. 请忽略我最后的评论。但是当我们要再次编辑单元格时,它会消失..有什么解决方案吗?
    • 但是在这里,当我们使用我们的代表时,单元格内的项目没有出现。(如上面的 1,2,3,4 等)。有没有办法解决这个问题?
    • 抱歉问了这么多愚蠢的问题。因为我是 Qt 新手,所以我无法理解发生了什么。
    【解决方案2】:

    我有一个解决方案,无需对整个油漆过程进行任何复杂的重新发明。 我有一个 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 会发生什么......(它工作正常,但它可能不会删除旧的按钮指针当创建新的时)

    【讨论】:

    • 在 Qt5 中,您甚至不必使用 QSignalMapper;您可以使用您选择的外壳将按钮的信号连接到 lambda。
    • 请注意,setIndexWidget 应该只用于静态内容,因为它的性能很差。如果您只有一行带有按钮 - 使用它。如果您有 n 行和添加/删除功能,则更喜欢使用 QStyledItemDelegate 派生类。
    【解决方案3】:

    setIndexWidget 为我工作。 示例:

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

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

    【讨论】:

    • 我发现如果我在setIndexWidget 之前添加QList&lt;QString&gt; headerlabels = {"col1","col2","col3","col4"}; model-&gt;setHorizontalHeaderLabels(headerlabels); 会失败,但如果放在setIndexWidget 之后,它可以正常工作!
    【解决方案4】:
        // 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);
    

    【讨论】:

      【解决方案5】:

      我得到了解决方案.. 老画法:

      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 .
      
        }
        }
      }
      

      【讨论】:

        【解决方案6】:

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-04-09
          • 2017-08-15
          • 2018-06-13
          • 2013-03-07
          • 2014-03-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多