Страницы

Поиск по вопросам

воскресенье, 29 марта 2020 г.

Фильтр для каждого столбца в QTableView

#qt #qwidget


Имеется tableview, который отображает некоторую модель данных. В модели несколько
столбцов (текст, числа, чекбоксы).

Так же есть прокси модель, которая фильтрует данные.

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

В идеале, хочется засунуть виджеты прямо в шапку tableview. Но для этого нужно написать
свой QHeaderView и нагородить кучу кода, что не есть хорошо.

Думаю над вариантом: накидать на форму несколько lineedit в какой-то layout, чтоб
это автоматически подстраивалось под qtableview по размерам и в итоге красиво отображалось.
Чтобы каждый фильтр-виджет был именно над тем столбцом, для которого он предназначен.

Какие есть инструменты для решения такой задачи?

    


Ответы

Ответ 1



Думаю в шапку виджет засунуть не получится, если верить докам: 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. Как вариант - при клацанье на шапку нужной секции над ней появляется виджет с lineedit'ом, и при вводе текста в него вызывать член-функции сортировки. Вот пример кода картинки выше: QStandardItemModel* model = new QStandardItemModel; for (int row = 0; row < 4; ++row) { for (int column = 0; column < 4; ++column) { QStandardItem *item = new QStandardItem(QString("row %0, column %1").arg(row).arg(column)); model->setItem(row, column, item); } } ui->tableView->setModel(model); //При клацанье на заголовок секции открывать вижет сортировки connect(ui->tableView->horizontalHeader(), &QHeaderView::sectionClicked, [this](int section) { QHeaderView* headerView = ui->tableView->horizontalHeader(); QWidget* sortWidget = new QWidget(this, Qt::Popup); sortWidget->setAttribute(Qt::WA_TranslucentBackground); sortWidget->setStyleSheet("background-color: rgba(255, 255, 255, 128);" "color: white;"); QHBoxLayout* lo = new QHBoxLayout(sortWidget); QLineEdit* le = new QLineEdit(sortWidget); connect(le, &QLineEdit::textChanged, [this](const QString& toSort) { //TODO вызываем логику сортировки }); lo->addWidget(le); sortWidget->setLayout(lo); sortWidget->resize(headerView->sectionSize(section), 30); sortWidget->show(); const auto sx = section * headerView->sectionSize(section) + (this->pos().x() + ui->tableView->pos().x()); const auto sy = this->pos().y() + ui->tableView->pos().y(); sortWidget->move(sx, sy); }); Только лучше конечно всю эту красоту инкапсулировать в какой-нибудь SortPopUpWidget.

Ответ 2



Спасибо @magrif, Ваше решение вдохновило меня. Я решил задачу таким способом. Идею реализации я описал выше в вопросе. Однако виджеты создаются программно (динамически). Заранее, руками, на форму я добавил layout, в котором буду хранить виджеты. Это сверху, над tableview. Подключаю модель к tableview ui->view_scan->setModel(m_scanning_filter_model); ui->view_scan->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeMode::Stretch); Теперь мы знаем кол-во столбцов. Таким образом, для каждого столбца в tableview создаем свой виджет for (int i = 0; i < m_scanning_model->columnCount(); i++) { ui->filter_layout->addWidget(create_filter_widget_by_scanning_column(i)); } В методе create_filter_widget_by_scanning_column определяем по индексу столбца, какой виджет будет создан для этого столбца. Сразу же к созданному виджету подключаем необходимые слоты. QWidget *MainWindow::create_filter_widget_by_scanning_column(const int &column) const { switch (column) { // пример текстового поля case 0: { auto widget = new QLineEdit(); widget->setValidator(new QRegExpValidator(QRegExp("[A-Za-z]{0,255}"))); connect(widget, &QLineEdit::textChanged, m_scanning_filter_model, &ScanningFilterModel::set_type); return widget; } // пример чекбокса case 7: { auto widget = new QCheckBox(); widget->setTristate(true); widget->setCheckState(Qt::CheckState::PartiallyChecked); connect(widget, &QCheckBox::stateChanged, m_scanning_filter_model, &ScanningFilterModel::set_enable); return widget; } default: return nullptr; } } Для красивого отображения виджетов (чтоб виджет был точно над столбцом, за который отвечает) подключаем изменение размера. Таким образом, при изменении размера окна или таблицы виджеты будут на своих местах. connect(ui->view_scan->horizontalHeader(), &QHeaderView::sectionResized, this, [this] (int index, int old_size, int new_size) { Q_UNUSED(old_size); auto widget = ui->filter_layout->itemAt(index)->widget(); widget->setMaximumWidth(new_size - 5); }); Вот то, что получилось в итоге:

Комментариев нет:

Отправить комментарий