对表格的排序、搜索的处理

  • 主要使用的类:QtreeView、QAbstractItemModel、QSortFilterProxyModel
  • 相互之间的关系:QtreeView <--> QSortFilterProxyModel <--> QAbstractItemModel
  • 主要的实现语句:
    this->setModel(session_sort_filter_proxy_model_);
    this->setSortingEnabled(false);
    this->sortByColumn(0, Qt::AscendingOrder);
    session_sort_filter_proxy_model_->setSourceModel(session_tree_model_);
  • QSortFilterProxyModel的实现细节:
class SessionSortFilterProxyModel : public QSortFilterProxyModel {
    Q_OBJECT
  public:
    bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
    bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
};

bool SessionSortFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
    QModelIndex index0 = sourceModel()->index(sourceRow, 1, sourceParent);
    QModelIndex index1 = sourceModel()->index(sourceRow, 2, sourceParent);

    return (sourceModel()->data(index0).toString().contains(filterRegExp())
            || sourceModel()->data(index1).toString().contains(filterRegExp()));
}

bool SessionSortFilterProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const {
    QVariant leftData = sourceModel()->data(left);
    QVariant rightData = sourceModel()->data(right);

    if (leftData.type() == QVariant::DateTime) {
        return leftData.toDateTime() < rightData.toDateTime();
    } else if (leftData.canConvert<int>() && leftData.canConvert<int>()) {
        return leftData.toInt() < rightData.toInt();
    } else {
        static QRegExp emailPattern("[\\w\\.]*@[\\w\\.]*)");

        QString leftString = leftData.toString();
        if(left.column() == 1 && emailPattern.indexIn(leftString) != -1) {
            leftString = emailPattern.cap(1);
        }

        QString rightString = rightData.toString();
        if(right.column() == 1 && emailPattern.indexIn(rightString) != -1) {
            rightString = emailPattern.cap(1);
        }

        return QString::localeAwareCompare(leftString, rightString) < 0;
    }
}

其中,filterAcceptsRow函数主要是针对搜索过滤的处理,lessThan主要是对排序的处理。

  • 关于搜索功能还写了单独的类来实现相关的功能:
Q_DECLARE_METATYPE(QRegExp::PatternSyntax)

class SessionFilter : public QLineEdit {
    Q_OBJECT
    Q_PROPERTY(Qt::CaseSensitivity caseSensitivity
               READ caseSensitivity WRITE setCaseSensitivity)
    Q_PROPERTY(QRegExp::PatternSyntax patternSyntax
               READ patternSyntax WRITE setPatternSyntax)
  public:
    explicit SessionFilter(QWidget *parent = nullptr);

    Qt::CaseSensitivity caseSensitivity() const;
    void setCaseSensitivity(Qt::CaseSensitivity);

    QRegExp::PatternSyntax patternSyntax() const;
    void setPatternSyntax(QRegExp::PatternSyntax);

  signals:
    void SignalFilterChanged();

  private:
    QAction *m_case_sensitivity_action_;
    QActionGroup *m_pattern_group_;
};

SessionFilter::SessionFilter(QWidget *parent)
    : QLineEdit(parent)
    , m_pattern_group_(new QActionGroup(this))

{
    setClearButtonEnabled(true);

    connect(this, &QLineEdit::textChanged, this, &SessionFilter::SignalFilterChanged);

    QMenu *menu = new QMenu(this);
    m_case_sensitivity_action_ = menu->addAction(tr("区分大小写"));
    m_case_sensitivity_action_->setCheckable(true);
    connect(m_case_sensitivity_action_, &QAction::toggled,
            this, &SessionFilter::SignalFilterChanged);

    menu->addSeparator();
    m_pattern_group_->setExclusive(true);
    QAction *patternAction = menu->addAction(tr("普通字符"));
    patternAction->setData(QVariant(int(QRegExp::FixedString)));
    patternAction->setCheckable(true);
    patternAction->setChecked(true);
    m_pattern_group_->addAction(patternAction);
    patternAction = menu->addAction(tr("正则表达式"));
    patternAction->setCheckable(true);
    patternAction->setData(QVariant(int(QRegExp::RegExp2)));
    m_pattern_group_->addAction(patternAction);
    patternAction = menu->addAction(tr("通配符"));
    patternAction->setCheckable(true);
    patternAction->setData(QVariant(int(QRegExp::Wildcard)));
    m_pattern_group_->addAction(patternAction);
    connect(m_pattern_group_, &QActionGroup::triggered,
            this, &SessionFilter::SignalFilterChanged);

    const QIcon icon = QIcon(QPixmap(":/common/search.png"));
    QToolButton *optionsButton = new QToolButton;
#ifndef QT_NO_CURSOR
    optionsButton->setCursor(Qt::ArrowCursor);
#endif
    optionsButton->setFocusPolicy(Qt::NoFocus);
    optionsButton->setStyleSheet("* { border: none; }");
    optionsButton->setIcon(icon);
    optionsButton->setMenu(menu);
    optionsButton->setPopupMode(QToolButton::InstantPopup);

    QWidgetAction *optionsAction = new QWidgetAction(this);
    optionsAction->setDefaultWidget(optionsButton);
    addAction(optionsAction, QLineEdit::LeadingPosition);
}

Qt::CaseSensitivity SessionFilter::caseSensitivity() const {
    return m_case_sensitivity_action_->isChecked() ?
           Qt::CaseSensitive : Qt::CaseInsensitive;
}

void SessionFilter::setCaseSensitivity(Qt::CaseSensitivity cs) {
    m_case_sensitivity_action_->setChecked(cs == Qt::CaseSensitive);
}

static inline QRegExp::PatternSyntax patternSyntaxFromAction(const QAction *a) {
    return static_cast<QRegExp::PatternSyntax>(a->data().toInt());
}

QRegExp::PatternSyntax SessionFilter::patternSyntax() const {
    return patternSyntaxFromAction(m_pattern_group_->checkedAction());
}

void SessionFilter::setPatternSyntax(QRegExp::PatternSyntax s) {
    foreach (QAction *a, m_pattern_group_->actions()) {
        if (patternSyntaxFromAction(a) == s) {
            a->setChecked(true);
            break;
        }
    }
}

此处主要是一个继承自QLineEdit的类,来实现一些过滤的处理。

  • 交互部分的功能细节:
connect(ui->session_filter, &SessionFilter::SignalFilterChanged,
        this, &SessionView::SlotTextFilterChanged);
connect(ui->session_filter, &QLineEdit::textChanged,
        this, &SessionView::SlotTextFilterChanged);

void SessionView::SlotTextFilterChanged() {
    QRegExp regExp(ui->session_filter->text(),
                   ui->session_filter->caseSensitivity(),
                   ui->session_filter->patternSyntax());
    ui->tree_view->GetProxyModel()->setFilterRegExp(regExp);
}
  • 补充:碰到崩溃的情况之一,在清空QAbstractItemModel表的内容的时候添加相关信号控制。
bool SessionTreeModel::ResetRow() {
    QAbstractItemModel::beginResetModel();
    session_list_.clear();
    QAbstractItemModel::endResetModel();
    return true;
}
posted @ 2020-07-18 18:15  背叛的故里纸鹤  阅读(186)  评论(0)    收藏  举报