3

I'm have created GridView, which delegates custom objects (Item) and its model is derived from QSortFilterProxyModel. Currently, whenever I click on an item in GridView, it show some info about it, but currently I am trying to control it with keyboard arrows, so I need to help with function, which gets next/previous item.

I have managed to think out some solutions:

  • Get index of currently selected item in GridView, which I managed to do with:

    console.log(slabItemContainer.contentItem.data[index]), but I didn't manage out how to get delegate back from index (because I don't need QQuickItem, but I need pointer to Item). I have set role name for Item as a "item", so whenever I write line by console.log(item), it shows me right object, but I didn't manage to get it from QQuickItem by index.

  • Get custom object from model derived by QSortFilterProxyModel

I have tried to get some kind of QList from my model, but I don't know how to access data. My model contains pointer to currently selected Item, so I've tried to get whole list from my model, then find currently selected item and then set next, but I didn't even created list, because I don't know, how to access it. I have tried to use mapToSource(), but it didn't worked out.

QModelIndex modelIndex = this->index(0,0, QModelIndex()); qDebug() << mapToSource(modelIndex);

Clicking on Item in GridView prints Item(0x2d508408), this prints me QModelIndex(0,0,0x0,ItemModel(0x2d528210)), but again, I don't know how to get data from it.

Does anyone have experience with it? How should I get next item by current item?

Thanks for your help!

//EDIT:

Filter.h

#include <QSortFilterProxyModel>
#include "Item.h"

class MyModel : public QSortFilterProxyModel
{
    Q_OBJECT
    Q_PROPERTY(Item* currentDetailView READ currentDetailView WRITE setFilterCurrentDetailView NOTIFY currentDetailViewChanged)

public:
    ItemFilterSortModel(QObject *parent = 0);

    //! Return true, if entity matches with filter conditions
    bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const;

    //! Returns Item to load into view
    Item * currentDetailView() const {return currentDetailView_;}

    //! Set up currently showing detail of Item
    Q_INVOKABLE void setFilterCurrentDetailView(Item *ItemToView);

    Q_INVOKABLE Item * getFilterNextDetailView();

    Q_INVOKABLE Item * getFilterPrevDetailView();

signals:
    currentDetailViewChanged();

private:
    Item *currentDetailView_;
};

Filter.cpp

#include "MyModel.h"

ItemFilterSortModel::ItemFilterSortModel(QObject *parent)
    : QSortFilterProxyModel(parent)
{

}

bool ItemFilterSortModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
{
    QModelIndex modelIndex = sourceModel()->index(source_row, 0, source_parent);

    //Checking conditions for displaying Item into gridview
    return (foo(sourceModel()->data(modelIndex,confidenceRole).toDouble()));
}

Item *ItemFilterSortModel::getFilterNextDetailView()
{
    QModelIndex modelIndex = this->index(0,0, QModelIndex());
    qDebug() << mapToSource(modelIndex);
}

Item *ItemFilterSortModel::getFilterPrevDetailView()
{

}

GridView.qml

GridView {    
            model: slabGridModel.filterModel
            delegate: Item{
                height: slabItemContainer.cellHeight - 15
                width: slabItemContainer.cellWidth - 15
            }
            Action {
                 shortcut: "Right"
                 onTriggered: model.getFilterNextDetailView()
            }
        }

//EDIT:

This happen to screen when right arrow key is pressed What happens to screen when right arrow key is pressed

//EDIT:

ItemModel.h

#include "Item.h"
#include <QAbstractListModel>
#include <QSortFilterProxyModel>

class ItemModel : public QAbstractListModel
{
    Q_OBJECT

public:
    // ---- PUBLIC METHODS ----
    //! Deletes items in list
    ~ItemModel();

    //! Returns number of items in list
    int rowCount(const QModelIndex &parent = QModelIndex()) const override;

    //! Exposes data of Items to QML by their roles
    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;

    //! Appends the Item into Item list
    void appendItem(Item * Item);

    //! Sets up role names for exposing them to QML
    QHash<int, QByteArray> roleNames() const;

    //! Returns list of all available Items
    QList<Item *> getItemList() const { return ItemList_; }

private:
    // ---- PRIVATE ATTRIBUTES ----
    QList<Item *> ItemList_;
};

ItemModel.cpp

#include "ItemModel.h"

ItemModel::~ItemModel(){
    qDeleteAll(ItemList_);
    ItemList_.clear();
}

int ItemModel::rowCount(const QModelIndex &parent) const{
    return parent.isValid() ? 0 : ItemList_.size();
}

QVariant ItemModel::data(const QModelIndex &index, int role) const{
    switch (role) {
    case Qt::UserRole:
        {
            Item *Item =  ItemList_[index.row()];
            return QVariant::fromValue(Item);
        }
        break;
    default:
        return QVariant();
        break;
    }
}

void ItemModel::appendItem(Item *Item)
{
    ItemList_.append(Item);
}

QHash<int, QByteArray> ItemModel::roleNames() const{
    QHash<int, QByteArray> roles;
    roles[Qt::UserRole] = "item";
    return roles;
}
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
Brykyz
  • 587
  • 4
  • 30

1 Answers1

3

Using my previous answer since I think you're using it as the basis of your code , we can obtain the following element in QML since as you use a proxy the following is relative on the model side, since as you indicate in the figure the following is a visual concept:

itemfiltersortmodel.h

#ifndef FILTERPROXYMODEL_H
#define FILTERPROXYMODEL_H

#include "item.h"

#include <QSortFilterProxyModel>
#include <QDebug>

class ItemFilterProxyModel : public QSortFilterProxyModel
{
    Q_OBJECT
    Q_PROPERTY(Item* currentItem READ currentItem WRITE setCurrentItem NOTIFY currentItemChanged)
public:
    using QSortFilterProxyModel::QSortFilterProxyModel;
    Item *currentItem()
    {
        return mCurrentItem;
    }
    void setCurrentItem(Item *currentItem)
    {
        qDebug()<<currentItem;
        if(mCurrentItem == currentItem)
            return;
        mCurrentItem = currentItem;
        emit currentItemChanged();
    }
    bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
    {
        // foo process
        return true;
    }
signals:
    void currentItemChanged();
private:
    Item *mCurrentItem;
};

#endif // FILTERPROXYMODEL_H

main.qml

import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 1.4
Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    GridView {
        id: gv
        anchors.fill: parent
        model: manager.filterModel
        property int nextIndex : mod(currentIndex+1, count)
        property int previousIndex : mod(currentIndex-1, count)
        property var currentModelItem
        onCurrentModelItemChanged: model.currentItem = currentModelItem
        delegate:
            Rectangle {
            width: 100
            height: 100
            property var view: GridView.view
            property bool isCurrentItem: index === view.currentIndex
            property bool isPreviousItem : index === view.nextIndex
            property bool isNextItem : index === view.previousIndex
            color: isCurrentItem ? "red" : isNextItem ? "green"  : isPreviousItem ? "blue" : "yellow"
            rotation: isCurrentItem ? 180 : isNextItem ? 90  : isPreviousItem? -90  : 0
            onIsNextItemChanged: if(isNextItem) view.currentModelItem = modelData
            Text {
                text: modelData.getVar
                anchors.centerIn: parent
            }
        }
    }
    // https://stackoverflow.com/a/50770689/6622587
    function mod(n, p){
        var r = n % p;
        return r < 0 ? r + p : r;
    }
    Action {
        shortcut: "Right"
        onTriggered: gv.currentIndex = mod(gv.currentIndex + 1, gv.count)

    }
    Action {
        shortcut: "Left"
        onTriggered: gv.currentIndex = mod(gv.currentIndex - 1, gv.count)
    }
}

enter image description here

Colors:

  • previous: blue
  • current: red
  • next: green

You can find the complete code in the following link.

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • That's good, but I want to change it in C++ too - set currently viewing item (pointer at it) to filter attribute, as I want to move only in filtered list. Something like setFilterCurrentDetailView(index + 1) in GridView, but setFilterCurrentDetailView have Item * as parameter. – Brykyz Jul 16 '18 at 16:02