对表格的排序、搜索的处理
- 主要使用的类: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;
}
浙公网安备 33010602011771号