ДК
June 17, 2020, 6:04 p.m.

разместить LineEdit под каждым столбом QTableView

Привет. Хочу сделать делегат от QTableView, в котором разместить QLineEdit под каждым столбцом, но в QTableView! Вводим текст в QLineEdit и он через 0,5 сек делает фильтр по введенному шаблону для этого столбца. Вобщем-то сделать всё получилось, только вот как разместить QLineEdit под каждым столбцом я не знаю. Прошу подсказать. ПС: пока разместил его просто поверх HorizontalHeaderLabels, как на скрине. Проект прилагаю .zip

  1. #ifndef FILTERTABLEVIEW_H
  2. #define FILTERTABLEVIEW_H
  3.  
  4. #include <QTableView>
  5. #include <QTimer>
  6. #include <QLineEdit>
  7. #include <QHBoxLayout>
  8. #include <QHeaderView>
  9. #include <QRegExpValidator>
  10. #include <QAbstractItemModel>
  11. #include <QSortFilterProxyModel>
  12.  
  13.  
  14. class FilterTableView : public QTableView
  15. {
  16. Q_OBJECT
  17. public:
  18. explicit FilterTableView(QWidget *parent = nullptr);
  19.  
  20. void setRegExpForColumn(QMap<int, QString> regexpColumns);
  21. void setEditColumns(QVector<int> editColumns);
  22.  
  23. void setModel(QAbstractItemModel *model) Q_DECL_OVERRIDE;
  24.  
  25. private:
  26. void setFilter(const QString text, const int column);
  27. QWidget *createLineEditForColumn(const int column);
  28. void filterLayoutAddWidgets();
  29.  
  30.  
  31. QHBoxLayout *_filterLayout;
  32. QAbstractItemModel *_model;
  33. QMap<int, QString> _regexpColumns;
  34. QVector<int> _editColumns;
  35. QTimer *_timer;
  36. signals:
  37. void filterTViewTextChanged(const int column, const QString text);
  38. };
  39.  
  40. #endif // FILTERTABLEVIEW_H
  41.  
  1. #include "filtertableview.h"
  2.  
  3.  
  4. FilterTableView::FilterTableView(QWidget *parent) :
  5. QTableView(parent)
  6. {
  7. _timer = new QTimer(this);
  8. _filterLayout = new QHBoxLayout;
  9. horizontalHeader()->setLayout(_filterLayout);
  10. horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeMode::Stretch);
  11. }
  12.  
  13.  
  14. void FilterTableView::filterLayoutAddWidgets()
  15. {
  16. if(!_editColumns.isEmpty())
  17. for(int i(0); i < _editColumns.size(); ++i)
  18. _filterLayout->addWidget(createLineEditForColumn(_editColumns[i]));
  19. else
  20. for(int i(0); i < _model->columnCount(); ++i)
  21. _filterLayout->addWidget(createLineEditForColumn(i));
  22. }
  23.  
  24. QWidget *FilterTableView::createLineEditForColumn(const int column)
  25. {
  26. QLineEdit *widget = new QLineEdit();
  27. if(_regexpColumns.contains(column))
  28. widget->setValidator(new QRegExpValidator(QRegExp(_regexpColumns.value(column))));
  29.  
  30. connect(widget, &QLineEdit::textChanged, [this, column](const QString text)
  31. {
  32. _timer->start(500);
  33. connect(_timer, &QTimer::timeout, [this, column, text](){
  34. emit filterTViewTextChanged(column, text);});
  35. });
  36. return widget;
  37. }
  38.  
  39. void FilterTableView::setRegExpForColumn(QMap<int, QString> regexpColumns)
  40. {
  41. _regexpColumns = regexpColumns;
  42. }
  43.  
  44. void FilterTableView::setEditColumns(QVector<int> editColumns)
  45. {
  46. _editColumns = editColumns;
  47. }
  48.  
  49. void FilterTableView::setModel(QAbstractItemModel *model)
  50. {
  51. _model = model;
  52. QTableView::setModel(model);
  53. filterLayoutAddWidgets();
  54. }
  55.  
  56.  
  1. #include "mainwindow.h"
  2. #include "ui_mainwindow.h"
  3.  
  4. MainWindow::MainWindow(QWidget *parent)
  5. : QMainWindow(parent)
  6. , ui(new Ui::MainWindow)
  7. {
  8. ui->setupUi(this);
  9. _tv = new FilterTableView();
  10.  
  11. _proxy = new QSortFilterProxyModel;
  12. _model = new QStandardItemModel(_tv);
  13. _model->setHorizontalHeaderLabels(QStringList() << "Column 1" << "Column 2" << "Column 3");
  14. for (int i = 0; i < 4; ++i) {
  15. QList<QStandardItem *> items;
  16. items.append(new QStandardItem(QString("Row %1").arg(i))); // Первая колонка
  17. items.append(new QStandardItem("Item 2")); // Вторая колонка
  18. items.append(new QStandardItem("Item 3")); // Третья колонка
  19. _model->appendRow(items);
  20. }
  21. _proxy->setSourceModel(_model);
  22. _tv->setModel(_proxy);
  23. ui->verticalLayout->addWidget(_tv);
  24.  
  25. connect(_tv, &FilterTableView::filterTViewTextChanged, [this](const int column, const QString text){
  26. setFilter(column, text);
  27. });
  28. }
  29.  
  30. MainWindow::~MainWindow()
  31. {
  32. delete ui;
  33. }
  34.  
  35. void MainWindow::setFilter(const int column, const QString pattern)
  36. {
  37. _proxy->setFilterKeyColumn(column);
  38. _proxy->setFilterCaseSensitivity(Qt::CaseInsensitive);
  39. _proxy->setFilterFixedString(pattern);
  40. }
  41.  
  42.  

Ну и замечания по коду приму во внимание.

Filter.zip Filter.zip

3
12
Evgenii Legotckoi
  • June 17, 2020, 6:14 p.m.

Добрый день.

QHeaderView имеет метод setItemDelegateForColumn . Думаю, что вам нужно написать делегат, в котором будет QLineEdit. И устанавливать этот делегат в колонки QHeaderView.

Пример написания делегата есть в этой статье Qt/C++ - Урок 091. Как написать кастомный делегат управляющий подсветкой строки в таблице

Единственное, вам нужно будет разобраться с тем, чтобы добавить туда QLineEdit... Возможно, через метод createEditor (кажется так называется), то есть переопределить его.

    ДК
    • June 17, 2020, 8:31 p.m.

    не получается. Может быть из-за этого

    Note: Each header renders the data for each section itself, and does not rely on a delegate. As a result, calling a header's setItemDelegate() function will have no effect.

      Evgenii Legotckoi
      • June 17, 2020, 8:32 p.m.

      наверное )) Этого я не заметил, сорян

        ДК
        • June 17, 2020, 8:35 p.m.
        • (edited)

        какие способы вообще приемлемы для отображения строки ввода под названием столбца?
        Пример, как я хочу сделать (нажать кнопку фильтра).

          ДК
          • June 17, 2020, 8:40 p.m.

          headerView переопределить может быть..

            ДК
            • June 17, 2020, 9:39 p.m.

            делаю проверку в делегате такую

            1. if(!_filterLayout->setAlignment(horizontalHeader(), Qt::AlignBottom))
            2. qDebug() << "FALSE";

            всегда FALSE. никуда ничего в QHeaderView не хочет ни добавляться, ни перемещаться. Жестянка какая-то.

              Evgenii Legotckoi
              • June 18, 2020, 12:35 p.m.

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

                ДК
                • June 18, 2020, 1:26 p.m.

                я вот , что вчера нашел))
                уже сделал, но что-то не так, хотя, заметно лучше уже)

                  ДК
                  • June 18, 2020, 1:28 p.m.
                  • (edited)

                  а еще решение подсказали:
                  присосаться к

                  1. signal void QHeaderView::sectionDoubleClicked(int logicalindex)

                  по которому открывать лайнэдит прямо под курсором. Но мне может быть такое не разрешат сделать.

                    ДК
                    • June 18, 2020, 3:55 p.m.
                    • (edited)

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

                    1. class FilterHeader : public QHeaderView
                    2. {
                    3. Q_OBJECT
                    4. public:
                    5. explicit FilterHeader(Qt::Orientation orientation, QWidget *parent = nullptr);
                    6.  
                    7. void setFilterBoxes(const int columnCount);
                    8.  
                    9. QSize sizeHint() const Q_DECL_OVERRIDE;
                    10.  
                    11. protected:
                    12. void updateGeometries() Q_DECL_OVERRIDE;
                    13.  
                    14. private:
                    15. void adjustPositions();
                    16.  
                    17. private:
                    18. QVector<QLineEdit*> _editors;
                    19. int _padding;
                    20. QTimer *_timer;
                    21.  
                    22. signals:
                    23. void filterTViewTextChanged(const int column, const QString text);
                    24. };
                    1. #include "filterheader.h"
                    2.  
                    3.  
                    4. FilterHeader::FilterHeader(Qt::Orientation orientation, QWidget *parent):
                    5. QHeaderView(orientation, parent),
                    6. _editors({}),
                    7. _padding(4)
                    8. {
                    9. _timer = new QTimer(this);
                    10. setStretchLastSection(true);
                    11. setSectionResizeMode(QHeaderView::Stretch);
                    12. setDefaultAlignment(Qt::AlignLeft | Qt::AlignCenter);
                    13. setSortIndicatorShown(false);
                    14. connect(this, &FilterHeader::sectionResized, this, &FilterHeader::adjustPositions);
                    15. connect(horizontalScrollBar(), &QScrollBar::valueChanged, this, &FilterHeader::adjustPositions);
                    16. }
                    17.  
                    18. void FilterHeader::setFilterBoxes(const int columnCount)
                    19. {
                    20. QMap<int, QString> regexpColumns = static_cast<FilterTableView*>(parent())->getRegExpColumns();
                    21. for(int i(0); i < columnCount; ++i)
                    22. {
                    23. //Если массив исключений содержит столбцы, котрым не нужно добавлять QLineEdit
                    24. if(static_cast<FilterTableView*>(parent())->getExpcludeColumns().contains(i))
                    25. break;
                    26. QLineEdit *le = new QLineEdit(this);
                    27. le->setPlaceholderText(QString("Фильтр"));
                    28. //Если массив проверки валидации для добавляемого QLineEdit столбца содержит правила валидации
                    29. if(regexpColumns.contains(i))
                    30. le->setValidator(new QRegExpValidator(QRegExp(regexpColumns.value(i))));
                    31.  
                    32. _editors.append(le);
                    33. //Данный коннект делает задержку фильтрации на 1 секунду
                    34. connect(le, &QLineEdit::textChanged, [this, i](const QString text)
                    35. {
                    36. _timer->start(1000);
                    37. connect(_timer, &QTimer::timeout, [this, i, text](){
                    38. emit filterTViewTextChanged(i, text);});
                    39. });
                    40. }
                    41. adjustPositions();
                    42. }
                    43.  
                    44. QSize FilterHeader::sizeHint() const
                    45. {
                    46. QSize size = QHeaderView::sizeHint();
                    47. if(!_editors.isEmpty())
                    48. {
                    49. const int height = _editors[0]->sizeHint().height();
                    50. size.setHeight(size.height() + height + _padding);
                    51. }
                    52. return size;
                    53. }
                    54.  
                    55. void FilterHeader::updateGeometries()
                    56. {
                    57. if(!_editors.isEmpty())
                    58. {
                    59. const int height = _editors[0]->sizeHint().height();
                    60. setViewportMargins(0, 0, 0, height + _padding);
                    61. }
                    62. else
                    63. setViewportMargins(0, 0, 0, 0);
                    64. QHeaderView::updateGeometries();
                    65. adjustPositions();
                    66. }
                    67.  
                    68. void FilterHeader::adjustPositions()
                    69. {
                    70. //Метод изменения позиции QLineEdit
                    71. int column = 0;
                    72. foreach(QLineEdit *le, _editors)
                    73. {
                    74. const int height = _editors[column]->sizeHint().height() - 2;
                    75. le->move(sectionPosition(column) - offset(), height + (_padding/5));
                    76. le->resize(sectionSize(column), height);
                    77. ++column;
                    78. }
                    79. }
                    1. class FilterHeader;
                    2.  
                    3. class FilterTableView : public QTableView
                    4. {
                    5. Q_OBJECT
                    6. public:
                    7. explicit FilterTableView(QWidget *parent = nullptr);
                    8.  
                    9. void setRegExpForColumn(QMap<int, QString> regexpColumns);
                    10. void setEditColumns(QVector<int> editColumns);
                    11.  
                    12. QMap<int, QString> getRegExpColumns();
                    13. QVector<int> getExpcludeColumns();
                    14.  
                    15. void setModel(QAbstractItemModel *model) Q_DECL_OVERRIDE;
                    16.  
                    17. QMap<int, QString> *getGetRegEpColumns() const;
                    18. void setGetRegEpColumns(QMap<int, QString> *value);
                    19.  
                    20. private:
                    21. QVBoxLayout *_filterLayout;
                    22. QAbstractItemModel *_model;
                    23. QMap<int, QString> _regExpColumns;
                    24. QVector<int> _expcludeColumns;
                    25. FilterHeader *_header;
                    26.  
                    27. signals:
                    28. void filterTViewTextChanged(const int column, const QString text);
                    29. };
                    1. #include "filtertableview.h"
                    2.  
                    3.  
                    4. FilterTableView::FilterTableView(QWidget *parent) :
                    5. QTableView(parent)
                    6. {
                    7. _header = new FilterHeader(Qt::Horizontal, this);
                    8. setHorizontalHeader(_header);
                    9. _filterLayout = new QVBoxLayout(this);
                    10. horizontalHeader()->setLayout(_filterLayout);
                    11. horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeMode::Stretch);
                    12.  
                    13. connect(_header, &FilterHeader::filterTViewTextChanged, this, &FilterTableView::filterTViewTextChanged);
                    14. }
                    15.  
                    16.  
                    17. void FilterTableView::setModel(QAbstractItemModel *model)
                    18. {
                    19. _model = model;
                    20. _header->setFilterBoxes(_model->columnCount());
                    21. QTableView::setModel(model);
                    22. }
                    23.  
                    24. void FilterTableView::setRegExpForColumn(QMap<int, QString> regexpColumns)
                    25. {
                    26. _regExpColumns = regexpColumns;
                    27. }
                    28.  
                    29. void FilterTableView::setEditColumns(QVector<int> editColumns)
                    30. {
                    31. _expcludeColumns = editColumns;
                    32. }
                    33.  
                    34. QMap<int, QString> FilterTableView::getRegExpColumns()
                    35. {
                    36. return _regExpColumns;
                    37. }
                    38.  
                    39. QVector<int> FilterTableView::getExpcludeColumns()
                    40. {
                    41. return _expcludeColumns;
                    42. }
                    1. MainWindow::MainWindow(QWidget *parent)
                    2. : QMainWindow(parent)
                    3. , ui(new Ui::MainWindow)
                    4. {
                    5. ui->setupUi(this);
                    6. createModel();
                    7. _tv = new FilterTableView();
                    8. _tv->setModel(_proxy);
                    9.  
                    10. ui->verticalLayout->addWidget(_tv);
                    11.  
                    12. connect(_tv, &FilterTableView::filterTViewTextChanged, [this](const int column, const QString text){
                    13. setFilter(column, text);
                    14. });
                    15. }
                    16.  
                    17. MainWindow::~MainWindow()
                    18. {
                    19. delete ui;
                    20. }
                    21.  
                    22. void MainWindow::setFilter(const int column, const QString pattern)
                    23. {
                    24. _proxy->setFilterKeyColumn(column);
                    25. _proxy->setFilterCaseSensitivity(Qt::CaseInsensitive);
                    26. _proxy->setFilterFixedString(pattern);
                    27. }
                    28.  
                    29. void MainWindow::createModel()
                    30. {
                    31. _model = new QStandardItemModel(ui->_tableView);
                    32. _model->setHorizontalHeaderLabels(QStringList() << "Column 1" << "Column 2" << "Column 3");
                    33. for (int i = 0; i < 4; ++i) {
                    34. QList<QStandardItem *> items;
                    35. items.append(new QStandardItem(QString("Row %1").arg(i))); // Первая колонка
                    36. items.append(new QStandardItem("Item 2")); // Вторая колонка
                    37. items.append(new QStandardItem("Item 3")); // Третья колонка
                    38. _model->appendRow(items);
                    39. }
                    40. _proxy = new QSortFilterProxyModel;
                    41. _proxy->setSourceModel(_model);
                    42. }

                      Evgenii Legotckoi
                      • June 18, 2020, 3:56 p.m.

                      Думаю, что сообщество будет радо увидеть подобную статью. Дерзайте ))

                        ВП
                        • Jan. 1, 2023, 6:15 p.m.
                        • (edited)

                        Наидобрейший человек! Спасибо! Код действительно очень помог сообществу. Его до сих под не сыскать на просторах чего то подобного на C++. Сделал несколько оптимизаций:

                        (1). Вернуть сортировку по нажатию на столбец можно в конструкторе FilterTableView, добавив:

                        1. _header->setSectionsClickable(true);
                        2. _header->setHighlightSections(true);

                        Функция

                        1. setSortingEnabled(true)

                        тут не поможет

                        (2). Чтобы не дергать итоговую проксимодель ненужными сигналами, то на выходе мы создаем единственный сигнал об изменениях которые были сделаны во всех столбцах с задержской в 1 секунду.
                        В конструкторе "FilterHeader" добавляем

                        1. timer->setSingleShot(true);

                        Переписываем FilterHeader::setFilterBoxes, ну и меняем сигнал на нужный тип данных в заголовочном файле

                        1. void FilterHeader::setFilterBoxes(const int columnCount)
                        2. {
                        3. QMap<int, QString> regexpColumns = static_cast<FilterTableView*>(parent())->getRegExpColumns();
                        4. for (int i=0; i < columnCount; ++i)
                        5. {
                        6. QLineEdit *le = new QLineEdit(this);
                        7. le->setPlaceholderText(QString("Фильтр"));
                        8. //Если массив исключений содержит столбцы, котрым не нужно добавлять QLineEdit
                        9. if (static_cast<FilterTableView*>(parent())->getExpcludeColumns().contains(i))
                        10. {
                        11. le->hide();
                        12. }
                        13. //Если массив проверки валидации для добавляемого QLineEdit столбца содержит правила валидации
                        14. if(regexpColumns.contains(i))
                        15. le->setValidator(new QRegularExpressionValidator(QRegularExpression(regexpColumns.value(i))));
                        16.  
                        17. _editors.append(le);
                        18. //Данный коннект делает задержку фильтрации на 1 секунду
                        19. connect(le, &QLineEdit::textChanged, [this]()
                        20. {
                        21. if (timer->isActive())
                        22. timer->setInterval(100);
                        23. else
                        24. timer->start(100);
                        25. });
                        26. }
                        27. connect(timer, &QTimer::timeout, [this]()
                        28. {
                        29. QStringList editors_values;
                        30. for (int i=0; i<_editors.count(); i++)
                        31. {
                        32. editors_values.append(_editors[i]->text());
                        33. }
                        34. emit textReady(editors_values);
                        35. });
                        36. adjustPositions();
                        37. }

                        (3). Возвращаем подвижность столбцам в конструкторе FilterTableView параметром

                        1. horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeMode::Interactive);

                          Comments

                          Only authorized users can post comments.
                          Please, Log in or Sign up
                          • Last comments
                          • Evgenii Legotckoi
                            March 9, 2025, 9:02 p.m.
                            К сожалению, я этого подсказать не могу, поскольку у меня нет необходимости в обходе блокировок и т.д. Поэтому я и не задавался решением этой проблемы. Ну выглядит так, что вам действитель…
                          • VP
                            March 9, 2025, 4:14 p.m.
                            Здравствуйте! Я устанавливал Qt6 из исходников а также Qt Creator по отдельности. Все компоненты, связанные с разработкой для Android, установлены. Кроме одного... Когда пытаюсь скомпилиров…
                          • ИМ
                            Nov. 22, 2024, 9:51 p.m.
                            Добрый вечер Евгений! Я сделал себе авторизацию аналогичную вашей, все работает, кроме возврата к предидущей странице. Редеректит всегда на главную, хотя в логах сервера вижу запросы на правильн…
                          • Evgenii Legotckoi
                            Oct. 31, 2024, 11:37 p.m.
                            Добрый день. Да, можно. Либо через такие же плагины, либо с постобработкой через python библиотеку Beautiful Soup
                          • A
                            Oct. 19, 2024, 5:19 p.m.
                            Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html