如何在QTableWidget上实现类似Excel的筛选机制?

3

有没有人能给我一些想法,帮我在QTableWidget上创建一个筛选机制(就像Microsoft Excel中的那样)?

每当我单击列名时,我希望头部筛选机制自动为该表格激活。

我正在Windows上构建。


更新 这是我部分实现的代码。但我需要帮助实现插槽testanother(const QString &text),以显示匹配的数据并隐藏不匹配的数据。

bool TableData::filterSlot() {
    int columnCount = this->tablewidget->columnCount();
    int rowCount = this->tablewidget->rowCount();
    QStringList filterList;
    QString temp_string;
    qDebug()<<"Count inside filter slot is";
    qDebug()<<rowCount<<":"<<columnCount;
    for(int c = 0; c<columnCount;c++) {
        for(int r = 0; r<rowCount;r++) {
            temp_string = this->tablewidget->item(r,c)->text(); 
            if(!filterList.contains(temp_string))
                filterList << temp_string;
        }
        filterList << "None";
        combo = new QComboBox(tablewidget);
        combo->addItems(filterList);
        combo->setCurrentIndex(filterList.count()-1);
        this->tablewidget->setCellWidget(0,c,combo);
        filterList.clear();
        connect(combo,SIGNAL(activated(const QString &)),
            this,SLOT(testAnother(const QString &)));
    }
    return true;
}

void TableData::testAnother(const QString &text) {
    int c = sender()->objectName().toInt();
}

你好,Lekhraj。欢迎来到StackOverflow。(顺便说一句,没有必要签署您的帖子,不过填写您的账户细节,如用户名,会有所帮助。)您是否特别寻找这个机制?http://www.microsoft.com/business/smb/en-ca/smallbiz/products/howto/use-excel-filtering-to-find-data-fast.mspx - HostileFork says dont trust SE
@HostileFork,是的,我想要实现与您分享的链接中提到的相同格式,但我想要通过QT代码来实现,而不是通过xls。 - lekhraj
2个回答

3
我创建了一个从继承的列跟踪布局。它不像将小部件嵌入标题那样好,但至少它给人一种小部件与其相应表列绑定的外观:

演示截图

enter image description here

该项目托管在GitHub上:https://github.com/sashoalm/ColumnAlignedLayout

您只需要columnalignedlayout.cpp和columnalignedlayout.h

由于它们足够小,我将直接粘贴它们。

columnalignedlayout.h

#ifndef COLUMNALIGNEDLAYOUT_H
#define COLUMNALIGNEDLAYOUT_H

#include <QHBoxLayout>

class QHeaderView;

class ColumnAlignedLayout : public QHBoxLayout
{
    Q_OBJECT
public:
    ColumnAlignedLayout();
    explicit ColumnAlignedLayout(QWidget *parent);
    void setTableColumnsToTrack(QHeaderView *view) { headerView = view; }

signals:

public slots:

private:
    void setGeometry(const QRect &r);
    QHeaderView *headerView;
};

#endif // COLUMNALIGNEDLAYOUT_H

columnalignedlayout.cpp

#include "columnalignedlayout.h"
#include <QHeaderView>

ColumnAlignedLayout::ColumnAlignedLayout()
    : QHBoxLayout()
{

}

ColumnAlignedLayout::ColumnAlignedLayout(QWidget *parent)
    : QHBoxLayout(parent)
{

}

void ColumnAlignedLayout::setGeometry(const QRect &r)
{
    QHBoxLayout::setGeometry(r);

    Q_ASSERT_X(headerView, "layout", "no table columns to track");
    if (!headerView) {
        return;
    }

    Q_ASSERT_X(headerView->count() == count(), "layout", "there must be as many items in the layout as there are columns in the table");
    if (headerView->count() != count()) {
        return;
    }

    Q_ASSERT(parentWidget());

    int widgetX = parentWidget()->mapToGlobal(QPoint(0, 0)).x();
    int headerX = headerView->mapToGlobal(QPoint(0, 0)).x();
    int delta = headerX - widgetX;

    for (int ii = 0; ii < headerView->count(); ++ii) {
        int pos = headerView->sectionViewportPosition(ii);
        int size = headerView->sectionSize(ii);

        auto item = itemAt(ii);
        auto r = item->geometry();
        r.setLeft(pos + delta);
        r.setWidth(size);
        item->setGeometry(r);
    }
}

使用示例:

alignedLayout = new ColumnAlignedLayout();
alignedLayout->addWidget(new QLineEdit(this));
alignedLayout->addWidget(new QLineEdit(this));
alignedLayout->addWidget(new QLineEdit(this));
alignedLayout->addWidget(new QLineEdit(this));
ui->widget->setLayout(alignedLayout);
alignedLayout->setTableColumnsToTrack(ui->tableWidget->horizontalHeader());
alignedLayout->setParent(ui->widget);
connect(ui->tableWidget->horizontalHeader(), SIGNAL(sectionResized(int,int,int)), SLOT(invalidateAlignedLayout()));
connect(ui->tableWidget->horizontalScrollBar(), SIGNAL(valueChanged(int)), SLOT(invalidateAlignedLayout()));

然后在插槽中调用invalidate():

void MainWindow::invalidateAlignedLayout()
{
    alignedLayout->invalidate();
}

1
我将类组合在单独的小部件中,它像魅力一样运行。Golem si! - Uga Buga
很高兴能够帮助到您 :) - sashoalm

1

目前没有内置的功能可以实现这个特定的功能。但是你可以从QHeaderView派生出自己的类,就像这个人所做的那样:

http://lists.qt.nokia.com/pipermail/qt-interest/2009-August/011654.html

我尝试了一下,似乎成功地将小部件——文本框和组合框——放在了适当的标题列下面。使用这种技术,如果您有一个长表格并滚动,过滤器将与标题保持在一起。

(以前有人提出将“假”行放入代理数据模型的线程。那是一种相当丑陋的方法,而且随着您向下滚动数据,过滤列也会滚动到顶部。)

他的示例代码没有显示它进行过滤。但是,通过查看基本排序/过滤模型示例的模式,您可以看到该功能的模式:

http://doc.qt.nokia.com/latest/itemviews-basicsortfiltermodel.html

好消息是Qt足够灵活,可以处理这种情况。坏消息是放置在列标题中的那些小部件如何填充取决于您。除非您编写代码,否则不会有任何扫描来查找唯一值并将其呈现在组合框中。使用固定列表进行填充将非常简单。

亲爱的 Hostile,非常感谢您的回复。我会检查这个并尽快回复您。 - lekhraj
看你添加的代码行this->tablewidget->setCellWidget(0,c,combo);,似乎你正在尝试将筛选小部件放入网格本身,而不是扩展标题。这意味着您没有采纳我的答案中列出的建议(但您应该!)另外:如果您想在Qt中进行过滤,您真的需要吸收代理模型和QSortFilterProxyModel工作的方式...学习文档和示例!http://doc.qt.nokia.com/latest/model-view-programming.html#proxy-models - HostileFork says dont trust SE
如果您发布一个屏幕截图证明您已经编译了我提供的链接中的代码,我更有可能帮助您... :-/ - HostileFork says dont trust SE
是的,我已经在我的main.cpp文件中包含了这两个头文件,并且修复了被分割的注释行。请查看下面我在main.cpp中包含的头文件:#include <QTableView> #include "MyHeaderView.h" #include "MyModel.h" - lekhraj
1
是的,现在它已经成功编译并运行了。 - lekhraj
显示剩余10条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接