10

私は Qt が初めてなので、ご容赦ください。

StringList と Object* の QList から ListView を作成することに成功しました

私が今苦労しているのは、QAbstractListModel を派生させる C++ で定義されたクラスを使用して QML に ListView を設定することです。

これが私の CPP クラスのプロトタイプです:

class MessageListEntryModel : public QAbstractListModel
{

Q_OBJECT
public:

enum eMLERoleTypes
{
    MLERT_MSG = Qt::UserRole+1,
    MLERT_COLOR
};

                                MessageListEntryModel(QObject* parent=0);
        virtual                 ~MessageListEntryModel();

        void                    AddEntry(QString aMessage, QColor aColor);

        // pure virtuals implementations
        QVariant                data(const QModelIndex &index, int role = Qt::DisplayRole) const;
        int                     rowCount(const QModelIndex &parent = QModelIndex()) const ;
        int                     columnCount(const QModelIndex &parent = QModelIndex()) const ;
        QModelIndex             index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
        QModelIndex             parent(const QModelIndex &child) const ;

        QHash<int,QByteArray>   roleNames();
private:
 QList<MessageEntry*> m_vpMessages;

MessageEntry は、QColor と QString の 2 つのメンバーを含む単純なクラスです (このクラスは QObject を拡張しません)。

上記のすべての関数は、基礎となるクラスで純粋な仮想であるため、実装する必要がありました (これは正常ですか? これまでのところ、チュートリアル/サンプルでは、​​roleNames とデータについてのみ言及されています)。

roleNames と data の実装は次のとおりです。

QHash<int,QByteArray>  MessageListEntryModel::roleNames()
{
    QHash<int,QByteArray> rez;
    rez[MLERT_MSG]="message";
    rez[MLERT_COLOR]="messagecolor";
    return rez;
}

QVariant MessageListEntryModel::data(const QModelIndex &index, int role) const
{
    qDebug()<<" Data asked for "<<index.row()<<" and role "<<role;
    if (index.row()<0 || index.row()>=m_vpMessages.size())
    {
        return QVariant();
    }
    MessageEntry* entry = m_vpMessages[index.row()];
    if (role == MLERT_MSG)
    {
        return QVariant::fromValue(entry->message);
    } else if (role == MLERT_COLOR)
    {
        return QVariant::fromValue(entry->messageColor);
    }
    // should be unreachable code
    return QVariant();
}

リスト ビューの QML 部分は次のようなものです。

 ListView {
    id: quickMessageListdata
    model: quickListModel
    delegate: Rectangle {

        width: 400
        height: 25
        color:"#000000"
        Text{
            text: model.message
            color: model.messagecolor
        }
    }

これまでのところ、これは CPP と QML で物事を実装する方法についての私の理解です。これら 2 つをリンクするには、次のコードを使用します。

MessageListEntryModel* model =new MessageListEntryModel();
// Add various entries
...
// assign model in QML
m_pViewRef->rootContext()->setContextProperty("quickListModel",model);

上記のコードでは、実行時に ListView に何も表示されず、次のエラーが発生します。

Unable to assign [undefined] to QString

Unable to assign [undefined] to QColor

QMLにエクスポートするモデルクラスも登録しています(これが必要かどうかはわかりません):

qmlRegisterType<MessageListEntryModel> ("dlti.exported",1,0,"MessageListEntryModel");

したがって、QAbstractListItem 派生クラスの適切な使用法を誤解したか、単純な重要なキー情報を見逃していることは明らかです。

関連するいくつかのサンプル/チュートリアルへのポインタをいただければ幸いです(CPPではデータ関数を決して通過しないことに気付いたので、QMLでモデルからデータに適切にアクセスする方法も示しています)。

また、私は qt5 を使用しているため、qt4.8 サンプルではうまくいかないことに注意してください。

編集

何時間もフラストレーションを感じた後、私はついに何が問題だったのかを突き止めました。

私の roleNames 関数の署名が間違っていました! オーバーロードの正しい署名は次のとおりです。

protected :
      QHash<int,QByteArray> roleNames() const;

protected および const 修飾子に注意してください。

関数を正しい方法で宣言した後、すべて正常に機能しました。

さらに注意するには、 data と rowCount を実装するだけで十分でした:)。

助けてくれてありがとう。例のコードを調べた後にこれを理解できただけなので、BaCaRoZzoの回答を受け入れます。

補足として、これは message と model.message の両方でうまく機能します。

4

3 に答える 3

9

追加メソッドをどのように実装しますか? 私のコメントで提供されている例のような方法を使用する必要があります。

ドキュメントから:

insertRows() 実装は、新しい行をデータ構造に挿入する前に beginInsertRows() を呼び出す必要があり、その直後に endInsertRows() を呼び出す必要があります

次のようなものが必要です。

void MessageListEntryModel::add(params...)
{
    beginInsertRows(QModelIndex(), rowCount(), rowCount());   // kindly provided by superclass
    // object creation based on params...
    m_vpMessages << objectCreated;
    endInsertRows();                                          // kindly provided by superclass
} 

int MessageListEntryModel::rowCount(const QModelIndex & parent) const {
    Q_UNUSED(parent);
    return m_vpMessages.count();
}

また、@Jonathan Mee のコメントは正しいです。モデルで定義したように、デリゲート内のロール名だけを使用してください。他のすべてが正しければ、それがデータにアクセスする方法です。


C++ モデルの実装と使用法を理解するのに最適なドキュメントの 1 つは、Model subclassing referenceです。このドキュメントでは、サブクラス化する最も重要なメソッドとその目的を明確に示しています。

実装する方法に関しては、実際にはニーズに依存します。モデルで可能なアクションに応じて、さまざまな方法を実装する必要があります (詳細については、上記のリンクを参照してください)。ListViewアイテムを追加/削除できるのモデルは、QAbstractListModelほとんどの関数のデフォルトの実装から継承し、それに依存することができます。ほとんどの例ですでに見たように、必要なのは と だけdata()ですroleNames()rowCount()

代わりに、データを追加/削除するだけでなく、データを編集setData()する必要がある場合は、他の機能、特に. で発生したモデルの変更を添付ビューに通知することもsetData()シグナルを介して行う必要がありますdataChanged()。上記のサブクラス化リファレンスを再度参照してください。

addメソッドが修飾子で変更されている場合Q_INVOKABLE、つまり次のように宣言されていることにも注意してください。

Q_INVOKABLE void add(params...);

モデル ヘッダーでは、QML から呼び出すこともでき (モデルはコンテキスト プロパティとして設定されているため)、たとえば次のように記述できます。

ListView {
    id: quickMessageListdata
    model: quickListModel
    delegate: Rectangle {

        width: 400
        height: 25
        color:"#000000"
        Text{
            text: model.message
            color: model.messagecolor
        }
    }

    Component.onCompleted: {
        quickListModel.add(params)
        quickListModel.add(params)      
    }
}

ビューが作成されるとすぐにビューに項目を挿入します。明らかに、同じアプローチを他の QML シグナルに適用して、QML イベントに反応し、追加/削除動作をトリガーすることができます。

最後に、モデルを に登録する必要はありませんqmlRegisterType。現在の要件では、それは不要です。

于 2014-12-11T10:44:10.817 に答える