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进行排序的主要内容,如果未能解决你的问题,请参考以下文章

如何在 2 个 qml 窗口之间进行通信

通过 C++ 单击按钮后更新 QML TableView

TableView在按钮上滚动单击Qml

具有动态列数的 QML TableView

如何通过单击列的标题按列对 QTableWidget 进行排序?

单击列时在 Qml TableView Header 中查找单击事件