QtQuick TableView CheckBox 委托调用 QAbstractTableModel 的 setData 函数

Posted

技术标签:

【中文标题】QtQuick TableView CheckBox 委托调用 QAbstractTableModel 的 setData 函数【英文标题】:QtQuick TableView CheckBox delegate calling setData function of QAbstractTableModel 【发布时间】:2014-06-16 11:40:36 【问题描述】:

我无法连接 qml 中的 TableView 和 QT 中 QAbstractTableModel 的 setData 函数。我的想法是能够通过 CkeckBox 委托将活动检查为“已完成”。我尝试覆盖 setData 函数以使用 row 而不是 QmodelIndex 并将其 view.currentrow 作为来自 qml 文件的参数发送。但它不起作用(currentrow 总是发送默认的 -1 值)。

main.qml

import QtQuick 2.0
import QtQuick.Window 2.1
import QtQuick.Controls 1.1
import QtQuick.Dialogs 1.0
import TodoM 1.0

Rectangle
width: 600
height: 400

TextField
    id:activityDescriptionTextEdit
    anchors.top: parent.top
    width: 500
    height: 50

Button
    id: saveActivityButton
    text: "Save Activity"
    anchors.left: activityDescriptionTextEdit.right
    onClicked: myModel.appendTodoFromQtQuick ( activityDescriptionTextEdit.text )


TextField
    id: filePathDisplay
    anchors.top: activityDescriptionTextEdit.bottom
    width: 500
    height: 50

Button
    text: "Save File"
    anchors.left: filePathDisplay.right
    anchors.top: activityDescriptionTextEdit.bottom
    onClicked: saveFileDialog.open()


TableView
id:view
    anchors.top: filePathDisplay.bottom
    width: 500
    height: 400

    TableViewColumn
        id: firstColumn
        title: "Is Done"
        role: "isDoneStateCheckState"
        width:100;
        delegate: CheckBox 
            id: checkBox
             onCheckedChanged: 
                 //Here is where I want to call setData
             
        
    

    TableViewColumn

         title: "Activity"
         role: "activityDescriptionState"
         width:200
    

   TableViewColumn
       role: "timeStampState"
       width:200
   
   model: myModel

FileDialog
    id: saveFileDialog
    title: "Save File As"
    selectExisting: false
    selectMultiple: false
    nameFilters: "*txt"
    onAccepted: 
        _ft.saveFile( saveFileDialog.fileUrl, myModel )
    

    onRejected: 
        console.log("Canceled")
    

TodoModel.cpp

    #include "TodoModel.h"
    #include "QModelIndex"
    #include "QDebug"

    TodoModel::TodoModel( QObject *parent )
     : QAbstractTableModel( parent )

     

     

     TodoModel::~TodoModel()
     
      

    QModelIndex TodoModel::parent( const QModelIndex& child ) const
    
    Q_UNUSED( child )

    return QModelIndex();
    

    int TodoModel::rowCount( const QModelIndex& parent ) const
    
    Q_UNUSED( parent )

    return m_todos.count();
    

    int TodoModel::columnCount( const QModelIndex& parent ) const
    
    Q_UNUSED( parent )

    return ColumnsCount;
    

    QVariant TodoModel::data( const QModelIndex& index, int role ) const
    
    int columnIndex = index.column();
    const int rowIndex = index.row();
    switch ( role )
    
        case IsDoneRole:
        case IsDoneCheckStateRole:
            columnIndex = ColumnIndexIsDone;
            break;
        case ActivityDesctriptionRole:
            columnIndex = ColumnIndexActivityDescription;
            break;
        case TimeStampRole:
            columnIndex = ColumnIndexTimestamp;
            break;
        default:
            break;
    
    if ( ! this->isValidColumnIndex( columnIndex )
         || ! this->isValidRowIndex( rowIndex ) )
    
        return QVariant();
    
    const Todo& todo = m_todos[ rowIndex ];
    switch ( columnIndex )
    

        case  ColumnIndexIsDone:
            if ( role == Qt::CheckStateRole
                 || role == IsDoneCheckStateRole )
            
                return todo.isDone()
                       ? Qt::Checked
                       : Qt::Unchecked;
            
            else if ( role == Qt::UserRole
                      || role == IsDoneRole )
            
                return todo.isDone();
            

            break;

        case ColumnIndexActivityDescription:
            if ( role == Qt::DisplayRole )
            

                return todo.activityDescription();
            
            else if ( role == Qt::UserRole
                      || role == ActivityDesctriptionRole )
            

                return todo.activityDescription();
            
            //Maham Brake-ovete i stava o.O

            break;

        case ColumnIndexTimestamp:
            if ( role == Qt::DisplayRole )
            
                return todo.addedTimestamp().toString( "dd/MM/yyyy hh:mm:ss.zzz" );
            
            else if ( role == Qt::UserRole
                      || role == TimeStampRole )
            
                return todo.addedTimestamp();
            

            break;

        default:
            break;
    

    return QVariant();
    

    QVariant TodoModel::headerData( int section, Qt::Orientation orientation, int role )        const
    
    if ( ! this->isValidColumnIndex( section )
         || orientation != Qt::Horizontal
         || role != Qt::DisplayRole )
    
        return QVariant();
    

    switch ( section )
    
        case ColumnIndexIsDone:
            return tr( "Is Done" );
        case ColumnIndexActivityDescription:
            return tr( "Activity Description" );
        case ColumnIndexTimestamp:
            return tr( "Timestamp" );
        default:
            break;
    

    return QVariant();
   

   Qt::ItemFlags TodoModel::flags( const QModelIndex& index ) const
   
    Qt::ItemFlags finalFlags = QAbstractTableModel::flags( index );
    if ( index.column() == ColumnIndexIsDone )
    
        finalFlags |= Qt::ItemIsUserCheckable;
    

    return finalFlags;
    
    bool TodoModel::setData( const QModelIndex& index, const QVariant& value, int role )
    

    const int rowIndex = index.row();
    const int columnIndex = index.column();
    if ( ! this->isValidRowIndex( rowIndex )
         || ! this->isValidColumnIndex( columnIndex ) )
    
        return false;
    

    Todo& todo = m_todos[ rowIndex ];

    switch ( columnIndex )
    
        case ColumnIndexIsDone:
        
            if ( role != Qt::CheckStateRole
                 && role != IsDoneRole
                 && role != IsDoneCheckStateRole )
            
                return false;
            

            bool converted = false;
            const Qt::CheckState checkState = static_cast< Qt::CheckState > ( value.toInt( & converted ) );
            const bool isChecked = checkState == Qt::Checked;
            if ( ! isChecked
                 && checkState != Qt::Unchecked )
            
                return false;
            

            if ( todo.isDone() == isChecked )
            
                return false;
            

            todo.setIsDone( isChecked );
            QModelIndex index;
            index = index.child( rowIndex, 0 );
            emit dataChanged( index, index );

            break;
        
        default:
            break;
    

    return true;
   

    void TodoModel::appendTodo( const Todo& aTodo )
    
    const int previousRowsCount = this->rowCount();
    this->beginInsertRows( QModelIndex(), previousRowsCount, previousRowsCount );
    m_todos.append( aTodo );

    this->endInsertRows();


   void TodoModel::clear()
   
    const int rowsCount = this->rowCount();
    if ( rowsCount <= 0 )
    
        return;
    

    this->beginRemoveRows( QModelIndex(), 0, rowsCount - 1 );
    m_todos.clear();
    this->endRemoveRows();
   

   bool TodoModel::isValidColumnIndex(const int columnIndex) const
   
    return 0 <= columnIndex && columnIndex < this->columnCount();
   

       bool TodoModel::isValidRowIndex( const int rowIndex ) const
       
        return 0 <= rowIndex && rowIndex < this->rowCount();
       
       QList<Todo> TodoModel::todos() const
       
        return m_todos;
        


       void TodoModel::appendTodoFromQtQuick(QString aActivityDescription)
       
        Todo todo;
        todo.setIsDone( false );
        todo.setActivityDescription( aActivityDescription );
        todo.setAddedTimestamp( QDateTime::currentDateTime() );
        appendTodo(todo);
       

       QHash<int, QByteArray> TodoModel::roleNames() const
       
        QHash<int, QByteArray> roles;
        roles[IsDoneRole] = "isDoneState";
        roles[IsDoneCheckStateRole] = "isDoneStateCheckState";
        roles[ActivityDesctriptionRole] = "activityDescriptionState";
        roles[TimeStampRole] = "timeStampState";
        return roles;
       

TodoModel.h

#ifndef TODOMODEL_H
#define TODOMODEL_H

#include "Todo.h"

#include <QAbstractTableModel>
#include <QList>

enum ColumnIndex

    ColumnIndexIsDone              = 0,
    ColumnIndexActivityDescription = 1,
    ColumnIndexTimestamp           = 2,
    ColumnsCount                   = 3
;



class TodoModel : public QAbstractTableModel

    Q_OBJECT

public:
    explicit TodoModel( QObject* parent = 0 );
    virtual ~TodoModel();

    enum TodoColumnRoles 
        IsDoneRole               = Qt::UserRole + 1,
        IsDoneCheckStateRole     = Qt::UserRole + 2,
        ActivityDesctriptionRole = Qt::UserRole + 3,
        TimeStampRole            = Qt::UserRole + 4
    ;

    virtual QModelIndex parent( const QModelIndex& child ) const;
    virtual int rowCount( const QModelIndex& parent = QModelIndex() ) const;
    virtual int columnCount( const QModelIndex& parent = QModelIndex() ) const;
    virtual QVariant data( const QModelIndex& index, int role = Qt::DisplayRole ) const;
    virtual QVariant headerData( int section, Qt::Orientation orientation,
                                 int role = Qt::DisplayRole ) const;
    // https://Radost@bitbucket.org/Radost/qtquickcontrols.git
    Qt::ItemFlags flags( const QModelIndex& index ) const;
    Q_INVOKABLE virtual bool setData( const QModelIndex& index, const QVariant &value, int role = Qt::EditRole );

    void appendTodo( const Todo& aTodo );
    void clear();

    bool isValidColumnIndex( const int columnIndex ) const;
    bool isValidRowIndex( const int rowIndex ) const;

    Q_INVOKABLE QList<Todo> todos() const;
     //Q_INVOKABLE QList<Todo*> ptodos() const;

public slots:

    Q_INVOKABLE void appendTodoFromQtQuick( QString aActivityDescription);
protected:
    QHash<int, QByteArray> roleNames() const;
private:
    QList< Todo > m_todos;
    //Q_QList< Todo* > m_ptodos;

;

#endif // TODOMODEL_H

知道我该怎么做吗?

【问题讨论】:

【参考方案1】:

您的代码是阅读和维护的噩梦。请注意制表符和空白。

您通过在委托中设置变量(称为角色名称)隐式调用setData

TableViewColumn
    id: firstColumn
    title: "Is Done"
    role: "isDoneStateCheckState"
    width:100;
    delegate: CheckBox 
        id: checkBox
        onCheckedChanged: 
            isDoneState = checked
        
    

枚举是自动枚举的,去吧:

enum TodoColumnRoles 
    IsDoneRole = Qt::UserRole,
    IsDoneCheckStateRole,
    ActivityDesctriptionRole,
    TimeStampRole
;

setData 中应该只有一个大的 switch 语句来查找 role 的不同值。

为dataChanged()创建新索引是没有意义的:

QModelIndex index;
index = index.child( rowIndex, 0 );
emit dataChanged( index, index );

您应该重用setData( const QModelIndex&amp; index ... 中的参数,因为它具有唯一可能的正确值。

【讨论】:

以上是关于QtQuick TableView CheckBox 委托调用 QAbstractTableModel 的 setData 函数的主要内容,如果未能解决你的问题,请参考以下文章

来自 C++ 的 QStandardItemModel 在 QtQuick / QML TableView 中不可见

QtQuick Controls 2 中的新 TableView 是不是支持不同的“角色”

QtQuick TableView CheckBox 委托调用 QAbstractTableModel 的 setData 函数

将 QStandardItemModel 从 C++ 传递到 QtQuick / QML TableView 并显示它

如何使用基于字段值选择的异构委托制作 QtQuick TableView / TreeView

如何在 QtQuickControls2 中使用 TableView 和 ListModel 数据?