3

Can anybody give me some idea to create a filter mechanism (as available in Microsoft Excel) on QTableWidget?

Whenever I click on a column name, I want the header filter mechanism to automatically activate for that table.

I'm building on Windows.


UPDATE Here is a partial implementation I have. But I need help with the implemetation of slot testanother(const QString &text) to display matching data in table and hide unmatched data.

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
  • 111
  • 2
  • 4
  • 7
  • Hello Lekhraj. Welcome to StackOverflow. (There is no need to sign your posts, BTW, although filling out your account details like username would help.) Are you looking specifically for this mechanism? http://www.microsoft.com/business/smb/en-ca/smallbiz/products/howto/use-excel-filtering-to-find-data-fast.mspx – HostileFork says dont trust SE Dec 05 '11 at 11:08
  • @HostileFork,Yes, i want to implement like the same format as mentioned in link which you have shared but I want to implement this through QT code not through xls. – lekhraj Dec 05 '11 at 12:24

2 Answers2

3

I've created a column-tracking layout that inherits from QHBoxLayout. It is not as good as embedding the widgets into the header, but at least it gives the appearance that the widgets are bound to their respective table columns:

Demo screencap

enter image description here

The project is hosted on GitHub at https://github.com/sashoalm/ColumnAlignedLayout.

You need only columnalignedlayout.cpp and columnalignedlayout.h

Since they're small enough I'll paste them directly.

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

Sample usage:

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

And then in the slot call invalidate():

void MainWindow::invalidateAlignedLayout()
{
    alignedLayout->invalidate();
}
sashoalm
  • 75,001
  • 122
  • 434
  • 781
1

There's nothing built-in that does that particular feature. But you could derive your own class from QHeaderView, like what this person has done:

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

I tried it and it seems to successfully put widgets—a text box and a combo box—underneath the appropriate header column. With this technique, if you have a long table and scroll, the filters will remain with the header.

(There was a prior thread where people propose putting a "fake" row into a proxy data model. That's a pretty hideous way to do it, and the filter columns would also scroll off the top as you scrolled your data down.)

His sample code doesn't show it filtering. But you can see the pattern for that functionality by looking at the basic sorting/filtering model example:

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

The good news is that Qt is flexible enough to handle this kind of thing. The bad (?) news is that how those widgets you put in the column headers get populated is up to you. There won't be any scanning to find unique values and present them in a combo box unless you write it. Populating with a fixed list would be trivial, though.

  • Dear Hostile,Thanks a lot for your response.will check this and get back to you very soon. – lekhraj Dec 06 '11 at 04:40
  • @user671112 By looking at the line in your added code `this->tablewidget->setCellWidget(0,c,combo);` it seems you're trying to put the filter widget into the grid itself, as opposed to extending the header. That means you are not taking the advice listed in my answer (but you should!!!) Also: if you want to do filtering in Qt, you really need to absorb how proxy models and `QSortFilterProxyModel` work...study the documentation and examples! http://doc.qt.nokia.com/latest/model-view-programming.html#proxy-models – HostileFork says dont trust SE Dec 07 '11 at 15:07
  • I'll also be more likely to help you if you post a screen shot proving you've bothered to compile the code in the link I've provided... :-/ – HostileFork says dont trust SE Dec 07 '11 at 15:13
  • @QHostileFork :- m not able to copile this code and it's giving below error. "error: no matching function for call to 'QObject::connect(QScrollBar*, const char*, FilterHorizontalHeaderView*, const char*)'" note: candidates are: static bool QObject::connect(const QObject*, const char*, const QObject*, const char*, Qt::ConnectionType) (m getting this error for both signals which is calling from main method. – lekhraj Dec 07 '11 at 18:09
  • @user671112 Did you `#include "MyModel.h"` and `#include "MyHeaderView.h"` in main.cpp? Did those headers compile successfully? Did you fix up the places where the comments got split across lines? – HostileFork says dont trust SE Dec 07 '11 at 18:16
  • :- Yes i have included this both headers on my main.cpp and also fixes the splitted commented line.Please find below header files which i have included on main.cpp #include #include "MyHeaderView.h" #include "MyModel.h" – lekhraj Dec 07 '11 at 18:27
  • @user671112 Try including instead of – HostileFork says dont trust SE Dec 07 '11 at 18:29
  • 1
    :- yes now it is successfully compiled and running as well. – lekhraj Dec 07 '11 at 18:37
  • @user671112 Good. My advice from here is just like in my answer: Build on that, study and learn how Qt's QSortFilterProxyModel works, wire those two techniques together. If you are having trouble getting through some part of that, break down your problems into NEW short, clear, *answerable* questions! – HostileFork says dont trust SE Dec 07 '11 at 18:49
  • Thanks for your help and will try this and let u know in case of any issue.Just wanted to one more thing is it possible to use QSortFilterProxyModel with QTablewidget??.Actually my existing application is based on tablewidget. – lekhraj Dec 07 '11 at 18:53
  • @user671112 You will have to use QTableView. QTableWidget is a simplified class layered on top of QTableView which is stuck working only with a default model. It inherits from QTableView to get most of its functionality, so they are largely the same. Note that you can just change the basicsortfiltermodel and customsortfiltermodel Qt samples from using QTreeView to QTableView and they will "just work". – HostileFork says dont trust SE Dec 07 '11 at 19:14
  • As my existing application is using Qtablewidget for display data in table.So i think it's not possible for me to use QSortFilterProxyModel.Please correct me if i am wrong.So i have only option to think and implement combo box on tablewidget column. – lekhraj Dec 08 '11 at 07:34
  • @user671112 You are wrong, so I will correct you. If you can edit the source code of your application, *a QTableView is easily interchangeable with a QTableWidget*. Note that a QTableWidget is *derived* from a QTableView. If you do not currently understand the model/view system in Qt you absolutely must sit down and make the effort to get your head around it...because trying to sort/filter in the Qt architecture without it is a complete dead end. See the note about QTableWidget and "convenience classes" when you READ THIS: http://doc.qt.nokia.com/latest/model-view-programming.html – HostileFork says dont trust SE Dec 08 '11 at 13:03
  • Thanks for your help and will check this and get back to you. – lekhraj Dec 08 '11 at 16:44
  • Note also their comments on the convenience classes like QTableWidget, which were only kept for compatibility with Qt3: "These classes are less flexible than the view classes, and cannot be used with arbitrary models. We recommend that you use a model/view approach to handling data in item views unless you strongly need an item-based set of classes." – HostileFork says dont trust SE Dec 08 '11 at 17:06