QML如何通过单击列的标题对tableView进行排序
Posted
技术标签:
【中文标题】QML如何通过单击列的标题对tableView进行排序【英文标题】:QML How to sort a tableView just by clicking on the header of the column 【发布时间】:2020-06-02 10:17:39 【问题描述】:所以在我的项目中,我使用的是具有模型的 tableview:tableModel fopm Qt.labs.qmlmodels 1.0;所以我想使用一些方法对其进行排序,我找到了 QAbsructProxyModel 类,我不知道我是否用得好,但我发现过滤和排序的问题在我的代码下方,提前谢谢`需要帮助
import QtQuick 2.15
import QtQuick.Window 2.12
import Qt.labs.qmlmodels 1.0
import QtQuick.Controls 2.15
import QtQml.Models 2.15
import org.qtproject.example 1.0
ApplicationWindow
width: 1000
height: 400
visible: true
header: ToolBar
TextField
id: searchBox
placeholderText: "Search..."
inputMethodHints: Qt.ImhNoPredictiveText
//width: window.width / 5 * 2
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
TableView
id:tableView
anchors.fill: parent
//sortIndicatorVisible: true
//anchors.topMargin: 30
columnSpacing: 1
rowSpacing: 3
anchors.topMargin:30
//boundsBehavior: Flickable.StopAtBounds
model:SortFilterProxyModel
id: proxyModel
source: sourceModel.rowCount> 0 ? sourceModel : null
onSourceChanged: console.log(source+" source")
sortOrder: Qt.AscendingOrder//tableView.sortIndicatorOrder
sortCaseSensitivity: Qt.CaseInsensitive
sortRole: sourceModel.rowCount > 0 ? " nomdetrame": ""
onSortRoleChanged: console.log(" role")
filterString: "*" + searchBox.text + "*"
//onFilterStringChanged: console.log(filterString)
filterSyntax: SortFilterProxyModel.Wildcard
filterCaseSensitivity: Qt.CaseInsensitive
TableModel
id:sourceModel
TableModelColumn display: " teta"
TableModelColumn display: "visibilite"
TableModelColumn display: "couleur"
TableModelColumn display: "chaine_can"
TableModelColumn display: "nomdetrame"
TableModelColumn display: "nondusignal"
TableModelColumn display: "valeurDec"
TableModelColumn display: "valeurHex"
TableModelColumn display: "TxouRx"
// Each row is one type of fruit that can be ordered
rows: [
// Each property is one cell/column.
teta:"+",
visibilite: false,
couleur: "red",
chaine_can: "CAN 4",
nomdetrame: "rRX",
nondusignal: "1.50",
valeurDec: "CAN 4",
valeurHex: "rRX",
TxouRx: "Tx"
,
teta:"+",
visibilite: false,
couleur: "grey",
chaine_can: "CAN 1",
nomdetrame: "rRX",
nondusignal: "1.5",
valeurDec: "CAN 4",
valeurHex: "rRX",
TxouRx: "Rx"
,
teta:"+",
visibilite: true,
couleur: "black",
chaine_can: "CAN 2",
nomdetrame: "rRX",
nondusignal: "1",
valeurDec: "CAN 4",
valeurHex: "RXE",
TxouRx: "Tx"
]
delegate: DelegateChooser
DelegateChoice
column: 0
//width: 100
delegate:Button
id:teta
text:"+"
//anchors.fill: parent
onClicked:tableView.sourceModel.appendRow(
// Each property is one cell/column.
teta:"+",
visibilite: false,
couleur: "red",
chaine_can: "CAN 4",
nomdetrame: "rRX",
nondusignal: "1.50",
valeurDec: "CAN 4",
valeurHex: "rRX",
TxouRx: "Tx"
)
//z: -1
DelegateChoice
column: 1
delegate:Rectangle
border.color: "black"
implicitWidth: 80
CheckBox
//anchors.fill: parent
anchors.centerIn: parent
checked: model.display
DelegateChoice
column: 2
delegate:Rectangle
implicitWidth: 80
//anchors.fill: parent
border.color: "black"
color: model.display
//z: -1
DelegateChoice
column: 3
delegate:Rectangle
border.color:"black"
implicitWidth: 80
Button
anchors.fill: parent
onClicked: console.log(currentIndex)
// TextInput
// //textRole: "display"
// anchors.fill: parent
// text:model.display
// //z: -1
//
DelegateChoice
column: 4
delegate:Rectangle
border.color: "black"
implicitWidth: 80
TextInput
//anchors.fill: parent
anchors.centerIn: parent
text:model.display
//z: -1
DelegateChoice
column: 5
delegate:Rectangle
border.color: "black"
implicitWidth: 80
TextInput
//anchors.fill: parent
anchors.centerIn: parent
text:model.display
//z: -1
DelegateChoice
column: 6
delegate:Rectangle
implicitWidth: 80
border.color: "black"
TextInput
// anchors.fill: parent
anchors.centerIn: parent
text:model.display
//z: -1
DelegateChoice
column: 7
delegate:Rectangle
implicitWidth: 80
border.color: "black"
TextInput
//anchors.fill: parent
anchors.centerIn: parent
text:model.display
//z: -1
DelegateChoice
column: 8
delegate:Rectangle
implicitWidth: 80
border.color: "black"
TextInput
//anchors.fill: parent
anchors.centerIn: parent
text:model.display
//z: -1
Component.onCompleted:
console.log(searchBox.text)
//console.log(tableView.model.getRow(0).couleur)
HorizontalHeaderView
id:headerView
anchors.left: tableView.left
syncView: tableView
model:[" ","Visible","Couleur","Chaine_Can","NomTrame","NomSignal","ValeurDec","ValeurHex","TX/RX"]
MouseArea
id:ms
anchors.fill: parent
hoverEnabled: true
c++代码:
include "sortfilterproxymodel.h"
#include <QtDebug>
#include <QtQml>
SortFilterProxyModel::SortFilterProxyModel(QObject *parent) : QSortFilterProxyModel(parent), m_complete(false)
connect(this, &QSortFilterProxyModel::rowsInserted, this, &SortFilterProxyModel::countChanged);
connect(this, &QSortFilterProxyModel::rowsRemoved, this, &SortFilterProxyModel::countChanged);
qDebug()<<"je suis entré chez moi";
int SortFilterProxyModel::count() const
return rowCount();
QObject *SortFilterProxyModel::source() const
return sourceModel();
void SortFilterProxyModel::setSource(QObject *source)
setSourceModel(qobject_cast<QAbstractItemModel *>(source));
emit sourceChanged();
QByteArray SortFilterProxyModel::sortRole() const
return m_sortRole;
void SortFilterProxyModel::setSortRole(const QByteArray &role)
if (m_sortRole != role)
m_sortRole = role;
if (m_complete)
QSortFilterProxyModel::setSortRole(roleKey(role));
void SortFilterProxyModel::setSortOrder(Qt::SortOrder order)
QSortFilterProxyModel::sort(0, order);
QByteArray SortFilterProxyModel::filterRole() const
return m_filterRole;
void SortFilterProxyModel::setFilterRole(const QByteArray &role)
if (m_filterRole != role)
m_filterRole = role;
if (m_complete)
QSortFilterProxyModel::setFilterRole(roleKey(role));
QString SortFilterProxyModel::filterString() const
return filterRegExp().pattern();
void SortFilterProxyModel::setFilterString(const QString &filter)
setFilterRegExp(QRegExp(filter, filterCaseSensitivity(), static_cast<QRegExp::PatternSyntax>(filterSyntax())));
emit filterStringChanged();
SortFilterProxyModel::FilterSyntax SortFilterProxyModel::filterSyntax() const
return static_cast<FilterSyntax>(filterRegExp().patternSyntax());
void SortFilterProxyModel::setFilterSyntax(SortFilterProxyModel::FilterSyntax syntax)
setFilterRegExp(QRegExp(filterString(), filterCaseSensitivity(), static_cast<QRegExp::PatternSyntax>(syntax)));
QJSValue SortFilterProxyModel::get(int idx) const
QJSEngine *engine = qmlEngine(this);
QJSValue value = engine->newObject();
if (idx >= 0 && idx < count())
QHash<int, QByteArray> roles = roleNames();
for (auto it = roles.cbegin(), end = roles.cend(); it != end; ++it)
value.setProperty(QString::fromUtf8(it.value()), data(index(idx, 0), it.key()).toString());
return value;
void SortFilterProxyModel::classBegin()
void SortFilterProxyModel::componentComplete()
m_complete = true;
if (!m_sortRole.isEmpty())
QSortFilterProxyModel::setSortRole(roleKey(m_sortRole));
if (!m_filterRole.isEmpty())
QSortFilterProxyModel::setFilterRole(roleKey(m_filterRole));
int SortFilterProxyModel::roleKey(const QByteArray &role) const
return roleNames().key(role, -1);
QHash<int, QByteArray> SortFilterProxyModel::roleNames() const
qDebug()<<"RoleNames";
if (QAbstractItemModel *source = sourceModel())
qDebug()<<"RoleNames";
//qDebug()<< source->roleNames();
//qDebug()<<roleNames().key(0)<< " keys";
return source->roleNames();
return QHash<int, QByteArray>();
bool SortFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
QRegExp rx = filterRegExp();
if (rx.isEmpty())
return true;
QAbstractItemModel *model = sourceModel();
if (filterRole().isEmpty())
QHash<int, QByteArray> roles = roleNames();
for (auto it = roles.cbegin(), end = roles.cend(); it != end; ++it)
QModelIndex sourceIndex = model->index(sourceRow, 0, sourceParent);
QString key = model->data(sourceIndex, it.key()).toString();
if (key.contains(rx))
return true;
return false;
QModelIndex sourceIndex = model->index(sourceRow, 0, sourceParent);
if (!sourceIndex.isValid())
return true;
QString key = model->data(sourceIndex, roleKey(filterRole())).toString();
qDebug()<<rx;
return key.contains(rx);
【问题讨论】:
需要帮助 【参考方案1】:我无法运行您的代码。因为我使用的是旧版本的 Qt。所以我用重新实现的 QSortFilterProxyModel 类制作了一个简单的工作原型,并在 qml 中使用它进行过滤和排序。我的源模型是一个列表视图,在你的情况下是一个表格视图。其他的都一样。
代码的可能部分需要检查。
1. 重新实现filterAcceptsRow
2.重新实现lessThan
3.确保在更改搜索文本时拨打invalidateFilter
4. 确保在更改 sortOrder 时调用默认的sort
函数
============ 这里的示例代码 ============
************** main.qml **************
import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 2.2
import SortFilter 1.0
Window
id: rootId
width: 320
height: 568
visible: true
SortFilterProxy
id: sortFilterProxyModelId
sourceModel: fruitModel
sortRole: Qt.DisplayRole
searchString: ""
sortOrder: Qt.AscendingOrder
ListModel
id: fruitModel
ListElement name: "Apple"
ListElement name: "Orange"
ListElement name: "Banana"
Column
anchors.fill: parent
TextField
id: searchIpId
height: 40
width: parent.width
focus: true
placeholderText: "Enter search text"
onTextChanged: sortFilterProxyModelId.searchString = text
Button
id: sortButtonId
height: parent.height - 10
width: 60
text: "sort"
anchors.rightMargin: 10
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
onClicked:
// call proxy
if(sortFilterProxyModelId.sortOrder == Qt.AscendingOrder)
sortFilterProxyModelId.sortOrder = Qt.DescendingOrder
else
sortFilterProxyModelId.sortOrder = Qt.AscendingOrder
searchIpId.forceActiveFocus()
ListView
width: parent.width
height: parent.height - searchIpId.height
model: sortFilterProxyModelId // change to proxy output
delegate: Rectangle
width: parent.width
height: 40
color: index % 2 == 0 ? "white" : "#C0C0C0"
Label
anchors.fill: parent
anchors.margins: 10
text: name
************** sortfilterproxymodel.h **************
#ifndef SORTPROXYMODEL_H
#define SORTPROXYMODEL_H
#include <QSortFilterProxyModel>
class SortFilterProxyModel : public QSortFilterProxyModel
Q_OBJECT
Q_PROPERTY(QString searchString READ searchString WRITE setSearchString NOTIFY searchStringChanged)
Q_PROPERTY(Qt::SortOrder sortOrder READ sortOrder WRITE setSortOrder NOTIFY sortOrderChanged)
public:
explicit SortFilterProxyModel(QObject* parent = nullptr);
QString searchString() const
return _searchString;
Qt::SortOrder sortOrder() const
return _sortOrder;
void setSearchString(const QString &searchString);
void setSortOrder(const Qt::SortOrder &sortOrder);
signals:
void searchStringChanged(QString searchString);
void sortOrderChanged(Qt::SortOrder sortOrder);
protected:
bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const; // custom sort logic
bool filterAcceptsRow(int sourceRow,const QModelIndex &sourceParent) const; // custom filter logic
private:
QString _searchString;
Qt::SortOrder _sortOrder;
;
#endif // SORTPROXYMODEL_H
************** sortfilterproxymodel.cpp **************
#include "sortfilterproxymodel.h"
SortFilterProxyModel::SortFilterProxyModel(QObject* parent) :
QSortFilterProxyModel(parent)
connect(this, &SortFilterProxyModel::searchStringChanged, this, &SortFilterProxyModel::invalidate); //
void SortFilterProxyModel::setSearchString(const QString &searchString)
if (_searchString == searchString)
return;
_searchString = searchString;
emit searchStringChanged(searchString); // connected with invalidateFilter, internally invalidateFilter makes call to filterAcceptsRow function
void SortFilterProxyModel::setSortOrder(const Qt::SortOrder &sortOrder)
if(_sortOrder == sortOrder)
return ;
_sortOrder = sortOrder;
sort(0, sortOrder); // responsible call to make sorting, internally it will make a call to lessthan function
emit sortOrderChanged(sortOrder);
bool SortFilterProxyModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const
QVariant left = sourceModel()->data(source_left);
QVariant right = sourceModel()->data(source_right);
if(left.isValid() && right.isValid())
return left.toString() > right.toString();
else
return false;
bool SortFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
QString data = sourceModel()->data(index, Qt::DisplayRole).value<QString>();
if(_searchString.isEmpty() || _searchString.isNull())
return true;
if(data.contains(_searchString, Qt::CaseInsensitive))
return true;
return false;
【讨论】:
以上是关于QML如何通过单击列的标题对tableView进行排序的主要内容,如果未能解决你的问题,请参考以下文章