Как реализовать механизм фильтрации, подобный Excel, в QTableWidget?

Может ли кто-нибудь дать мне представление о создании механизма фильтрации (доступного в Microsoft Excel) в QTableWidget?

Всякий раз, когда я нажимаю на имя столбца, я хочу, чтобы механизм фильтрации заголовков автоматически активировался для этой таблицы.

Я строю на 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();
}

person lekhraj    schedule 05.12.2011    source источник
comment
Здравствуйте, Лехрай. Добро пожаловать в StackOverflow. (Кстати, нет необходимости подписывать ваши сообщения, хотя заполнение данных вашей учетной записи, таких как имя пользователя, может помочь.) Вы ищете именно этот механизм? microsoft.com/business/smb/en-ca/smallbiz/products/howto/   -  person HostileFork says dont trust SE    schedule 05.12.2011
comment
@HostileFork, да, я хочу реализовать тот же формат, что и в ссылке, которой вы поделились, но я хочу реализовать это через код QT, а не через xls.   -  person lekhraj    schedule 05.12.2011


Ответы (2)


Я создал макет отслеживания столбцов, который наследуется от QHBoxLayout. Это не так хорошо, как встраивание виджетов в заголовок, но, по крайней мере, создается впечатление, что виджеты привязаны к соответствующим столбцам таблицы:

Скриншот демо

введите здесь описание изображения

Проект размещен на GitHub по адресу https://github.com/sashoalm/ColumnAlignedLayout.

Вам нужны только columnalignedlayout.cpp и columnalignedlayout.h

Поскольку они достаточно маленькие, я вставлю их напрямую.

столбецalignedlayout.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

столбецalignedlayout.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();
}
person sashoalm    schedule 11.09.2016
comment
Я объединил класс в отдельный виджет, и он работал как шарм. Голем си! - person Uga Buga; 24.11.2017
comment
Рад, что помог :) - person sashoalm; 25.11.2017

Там нет ничего встроенного, что делает эту конкретную функцию. Но вы можете создать свой собственный класс из QHeaderView, как это сделал этот человек:

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

Я попробовал, и кажется, что текстовое поле виджетов и поле со списком успешно размещено под соответствующим столбцом заголовка. При таком приеме, если у вас длинная таблица и прокрутка, фильтры останутся с заголовком.

(Был предыдущий поток, в котором люди предлагали поместить «фальшивую» строку в прокси-модель данных. Это довольно отвратительный способ сделать это, и столбцы фильтра также будут прокручиваться сверху, когда вы прокручиваете свои данные вниз.)

Его пример кода не показывает фильтрацию. Но вы можете увидеть шаблон для этой функциональности, взглянув на базовый пример модели сортировки/фильтрации:

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

Хорошей новостью является то, что Qt достаточно гибок, чтобы справляться с подобными вещами. Плохая (?) новость заключается в том, что то, как заполняются те виджеты, которые вы помещаете в заголовки столбцов, зависит от вас. Не будет никакого сканирования, чтобы найти уникальные значения и представить их в поле со списком, если вы не напишете это. Однако заполнение фиксированным списком было бы тривиальным.

person HostileFork says dont trust SE    schedule 05.12.2011
comment
Уважаемый Hostile, Большое спасибо за ваш ответ. Мы проверим это и свяжемся с вами в ближайшее время. - person lekhraj; 06.12.2011
comment
@user671112 user671112 Глядя на строку в вашем добавленном коде this->tablewidget->setCellWidget(0,c,combo);, кажется, что вы пытаетесь поместить виджет фильтра в саму сетку, а не расширять заголовок. Это означает, что вы не следуете совету, указанному в моем ответе (но вы должны!!!). Кроме того: если вы хотите выполнять фильтрацию в Qt, вам действительно нужно понять, как работают прокси-модели и QSortFilterProxyModel... изучите документацию и примеры. ! doc.qt.nokia.com/latest/ - person HostileFork says dont trust SE; 07.12.2011
comment
Я также с большей вероятностью помогу вам, если вы опубликуете снимок экрана, доказывающий, что вы потрудились скомпилировать код по ссылке, которую я предоставил... :-/ - person HostileFork says dont trust SE; 07.12.2011
comment
@QHostileFork: - я не могу скомпилировать этот код, и он дает следующую ошибку. ошибка: нет подходящей функции для вызова 'QObject::connect(QScrollBar*, const char*, FilterHorizontalHeaderView*, const char*)' примечание: кандидатами являются: static bool QObject::connect(const QObject*, const char*, const QObject*, const char*, Qt::ConnectionType) (m получаю эту ошибку для обоих сигналов, которые вызываются из основного метода. - person lekhraj; 07.12.2011
comment
@user671112 user671112 Вы #include "MyModel.h" и #include "MyHeaderView.h" в main.cpp? Эти заголовки успешно скомпилировались? Вы исправили места, где комментарии разбивались на строки? - person HostileFork says dont trust SE; 07.12.2011
comment
:- Да, я включил эти оба заголовка в свой main.cpp, а также исправил разделенную строку комментариев. Пожалуйста, найдите ниже файлы заголовков, которые я включил в main.cpp #include ‹QTableView› #include MyHeaderView.h #include MyModel.h - person lekhraj; 07.12.2011
comment
@ user671112 Попробуйте включить ‹QtGui› вместо ‹QTableView› - person HostileFork says dont trust SE; 07.12.2011
comment
:- да, теперь он также успешно скомпилирован и работает. - person lekhraj; 07.12.2011
comment
@ user671112 Хорошо. Мой совет здесь такой же, как и в моем ответе: опирайтесь на это, изучайте и изучайте, как работает Qt QSortFilterProxyModel, соединяйте эти два метода вместе. Если у вас возникли проблемы с какой-либо частью этого, разбейте свои проблемы на НОВЫЕ короткие, четкие, отвечающие вопросы! - person HostileFork says dont trust SE; 07.12.2011
comment
Спасибо за вашу помощь, и я попробую это и сообщу вам в случае возникновения каких-либо проблем. Просто хотел еще одну вещь: возможно ли использовать QSortFilterProxyModel с QTablewidget??. На самом деле мое существующее приложение основано на tablewidget. - person lekhraj; 07.12.2011
comment
@ user671112 Вам придется использовать QTableView. QTableWidget — это упрощенный класс, наложенный поверх QTableView, который работает только с моделью по умолчанию. Он наследуется от QTableView, чтобы получить большую часть своей функциональности, поэтому они во многом одинаковы. Обратите внимание, что вы можете просто изменить образцы Qt basicsortfiltermodel и customortfiltermodel с использования QTreeView на QTableView, и они просто будут работать. - person HostileFork says dont trust SE; 07.12.2011
comment
Поскольку мое существующее приложение использует Qtablewidget для отображения данных в таблице. Поэтому я думаю, что я не могу использовать QSortFilterProxyModel. Пожалуйста, поправьте меня, если я ошибаюсь. Так что у меня есть только возможность подумать и реализовать поле со списком в столбце tablewidget. - person lekhraj; 08.12.2011
comment
Спасибо за вашу помощь, мы проверим это и свяжемся с вами. - person lekhraj; 08.12.2011
comment
Обратите также внимание на их комментарии относительно удобных классов, таких как QTableWidget, которые были сохранены только для совместимости с Qt3: эти классы менее гибки, чем классы представлений, и их нельзя использовать с произвольными моделями. Мы рекомендуем вам использовать подход модель/представление для обработки данных в представлениях элементов, если только вам не нужен набор классов на основе элементов. - person HostileFork says dont trust SE; 08.12.2011