模型在 QTableView 中动态插入和删除行时的信号/插槽

Posted

技术标签:

【中文标题】模型在 QTableView 中动态插入和删除行时的信号/插槽【英文标题】:Signal/Slot while model inserts and removes rows in QTableView dynamically 【发布时间】:2017-08-25 07:55:38 【问题描述】:

我在QTableview 的最后一列中插入QPushButton。使用该按钮,我将使用按钮释放信号和插槽handlebutton(int) 删除该特定行。

cpp代码:

MainWindow::MainWindow(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::MainWindow)

    ui->setupUi(this);
    QSortFilterProxyModel *model = new QSortFilterProxyModel(this);
    model = pCApp->guiClient()->getConnectionManagement()->getProxyModel();
    ui->tableView->setModel(model);
    connect(pCApp, SIGNAL(CloseOpenWindowsRequested()), SLOT(close()));
    connect(ui->tableView->model(), SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(onRowsNumberChanged()));
    connect(ui->tableView->model(), SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(onRowsNumberChanged()));
    ui->tableView->setSortingEnabled(true);
    QPushButton *button;
    QSignalMapper *mapper = new QSignalMapper(this);
    QObject::connect(mapper, SIGNAL (mapped(int)), this, SLOT (handleButton(int)));
    for (int i = 0; i < model->rowCount(); i++)
    
        button = new QPushButton;
        button->setText("Disconnect " + QString::number(i));
        button->setStyleSheet("QPushButton  color: #E5E5E5; ");
        ui->tableView->setIndexWidget(model->index(i,2, QModelIndex()), button);
        QObject::connect(button, SIGNAL(released()), mapper, SLOT(map()));
        connect(ui->tableView->model(), SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(onRowsNumberChanged()));
        connect(ui->tableView->model(), SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(onRowsNumberChanged()));
        mapper->setMapping(button, i);
    
    setAttribute(Qt::WA_DeleteOnClose);


MainWindow::~MainWindow()

    delete ui;


void MainWindow::handleButton(int row)

    this->ui->tableView->model()->removeRow(row);


void MainWindow::onRowsNumberChanged()

    QSortFilterProxyModel *model = new QSortFilterProxyModel(this);
    model = pCApp->guiClient()->getConnectionManagement()->getProxyModel();
    ui->tableView->setModel(model);
    ui->tableView->setSortingEnabled(true);
    QPushButton *button;
    QSignalMapper *mapper = new QSignalMapper(this);
    QObject::connect(mapper, SIGNAL (mapped(int)), this, SLOT (handleButton(int)));
    for (int i = 0; i < model->rowCount(); i++)
    
        button = new QPushButton;
        button->setText("Disconnect " + QString::number(i));
        button->setStyleSheet("QPushButton  color: #E5E5E5; ");
        ui->tableView->setIndexWidget(model->index(i,2, QModelIndex()), button);
        QObject::connect(button, SIGNAL(released()), mapper, SLOT(map()));
        mapper->setMapping(button, i);
    


hpp 代码:

#ifndef MAINWINDOW_HPP
#define MAINWINDOW_HPP

namespace Ui 
class MainWindow;


class MainWindow : public QDialog

    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
public slots:
    void onLanguageChanged();
    void handleButton(int row);
    void onRowsNumberChanged();

private:
    Ui::MainWindow *ui;
;

#endif // MAINWINDOW_HPP

在正常情况下,代码运行正常。但是,当插入新行和/或删除旧行时,按钮不会按需要出现在最后一列中。我尝试使用信号 -

connect(ui->tvServStat->model(), SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(onRowsNumberChanged()));

connect(ui->tvServStat->model(), SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(onRowsNumberChanged()));

两个插槽,我与onRowsNumberChanged() 保持相同,我再次尝试在最后一列中插入按钮。我的想法是可能是行数正在改变,所以我正在重新实现相同的逻辑。但是,它不起作用。

任何人都可以帮助纠正我的逻辑或其他逻辑以实现此功能。提前致谢!

【问题讨论】:

【参考方案1】:

您应该为该列使用delegate。这样,视图会自动处理行的创建/删除。见this question


您的代码还有一些其他问题:

    您多次连接rowsInserted/rowsRemoved 在您的代码中,您可以创建多个信号映射器来映射相同类型的连接。这不是它的预期用途 onRowsNumberChanged 循环的重复

【讨论】:

我之前使用过代理,但它会生成需要设置样式的标准样式按钮。我尝试了两天,但无法适应这种风格。使用这种方法,我能够实现最大的功能,不包括自动创建/删除行的处理。你能帮我修改这个方法吗?非常感谢您的宝贵时间。 另外多个条目只是因为我试图找出正确的位置。另外,如果你能帮忙的话。 如链接问题(以及 qtcenter 的后续链接)中所述,使用小部件不能很好地扩展。你真的应该使用委托。我建议您使用代表方法发布一个新问题 已经完成了 - ***.com/questions/45812500/… 我明白了...也许您可以尝试this post 中的方法并设置按钮样式?【参考方案2】:

要使用小部件解决您的问题,您可以使用以下方法。它使用 Qt 5 的新连接语法和 C++ lambda,因此可以消除对信号映射器的需要:

#include "form.h"
#include <QtWidgets>
#include <QStandardItemModel>

Form::Form(QWidget *parent) :
    QWidget(parent)

    QPushButton *b = new QPushButton("add row");
    m_tree = new QTreeView(this);
    QBoxLayout *l = new QVBoxLayout(this);
    l->addWidget(m_tree, 1);
    l->addWidget(b);

    QStandardItemModel *m = new QStandardItemModel(0, 3, this);
    m_tree->setModel(m);

    connect(b, &QPushButton::clicked, this, &Form::addRow);
    connect(m, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(addItemButtons()));
    connect(m, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(addItemButtons()));


Form::~Form()



void Form::addRow()

    m_tree->model()->insertRow(m_tree->model()->rowCount());


void Form::addItemButtons()

    for (int i = 0; i < m_tree->model()->rowCount(); ++i) 
        auto idx = m_tree->model()->index(i, 2);
        QPushButton *b = new QPushButton("X");
        b->setStyleSheet("QPushButton color: #E5E5E5;");
        m_tree->setIndexWidget(idx, b);
        connect(b, &QPushButton::clicked, [=]()
            m_tree->model()->removeRow(i);
        );
    

【讨论】:

以上是关于模型在 QTableView 中动态插入和删除行时的信号/插槽的主要内容,如果未能解决你的问题,请参考以下文章

来自模型的数据未插入 QTableView

选择多行时QTableView变得很慢

在 QTableView 中插入行

PyQt4 - QTableView - 如何循环 QTableView

如何在 UITableView 中插入和删除行时模拟折纸

如何删除 QTableView 中的标题?