我实现了一个从QAbstractItemModel派生的类,它似乎工作正常。
然后,我创建了一个QItemSelectionModel并将其分配给提到的QAbstractItemModel。

我的QAbstractItemModel不是窗口小部件,也不显示,仅管理层次结构。
当选择被改变,并且该模型QItemSelection发射选择改变信号选择和取消选择QItemSelections似乎包含正确的数据。

当我调用它们的:: indexes()函数以获取所选项目的索引时,就会出现问题,即使我知道已选择项目并且:: width()和:: height()函数返回正确的值,它也不会返回任何项目值(value)观。

基本示例代码:
(下面的工作示例和文件演示了该问题)

class DerivedModel : public QAbstractItemModel {
    DerivedModel(QObject* parent) : QAbstractItemModel(parent)
                                   ,m_selectionModel(nullptr)
    {
        //create the selection model and assign this model to it
        m_selectionModel = new QItemSelectionModel(this, this);
    }
...
//all needed overload functions
//the DerivedModel works great
...
private:
    QItemSelectionModel* m_selectionModel;
}

//in a different object called SceneModel (a QGraphicsScene which shows graphical items based on the DerivedModel) which is connected to the selection models selectionChanged() signal I query the new selection

SceneModel::setSelectedItems(const QItemSelection& selected, const QItemSelection& deselected){

int selectionSize_A = selected.size(); //this returns correct number of selected items
int selectionSize_B = selected.indexes().size(); //this returns 0 -> WRONG
int selectionSize_C = selected.value(0).indexes().size(); //this returns 0 -> WRONG
int selectionSize_CA = selected.value(0).width(); //this returns correct
int selectionSize_CB = selected.value(0).height(); //this returns correct

//if I purposefully try to access the 1st selected index via QItemSelectionRange::topLeft() all is good and I get the index:
QItemSelectionRange range = selected.value(0);
QModelIndex topLeft = range.topLeft(); //cool, i get the 1st selected index

//it seems there is a problem with the ::indexes function, so dived into the Qt5 source and basically implemented again whats done there and it works.
}

指向包含cmake构建文件的链接:
https://drive.google.com/file/d/0Bz03DnXr46WXYXRCeExtaHZadUU/view?usp=sharing

那里发生了什么:
创建一个DerivedModel并在根项(ROOT)下保存2个项(A和B)。
按下按钮将向QItemSelectionModel发出信号,以选择/取消选择A或B。
如果在模型“Found Item :)”中找到该项目,则表明该项目存在并且可用于模型。
QGraphicsView拥有一个场景(源自QGraphicsScene)。
该场景是空的,仅表示接收到来自选择模型的selectionChange信号的对象。
当它收到该信号时,它会打印“场景接收项目选择更改”,因此我们可以看到该信号已通过。
然后是真正的东西:
  • 我们可以计算传递的“selected”变量中有多少QItemRanges,这是正确的。
  • 我们得到传递的“selected”变量(selected.indexes())的所有范围内有多少索引的计数,该变量返回0,这是错误的,因为我们很快就会看到
  • 我们手动访问“selected”变量(selected.value(0).topLeft())中位于第1个范围内的第一个索引,并看到它确实包含指向正确项目的索引,从而显示了问题。

  • 如果有人知道某些事情,或者在我的方法中看到错误,请告诉我。
    谢谢!

    Linux Manjaro Gcc 4.9.1 Qt5.3

    DerivedModel.h:
    #ifndef DERIVEDMODEL_H
    #define DERIVEDMODEL_H
    
    #include <QAbstractItemModel>
    
    //fwd declaration
    QT_FORWARD_DECLARE_CLASS(QItemSelectionModel)
    
    class Item;
    
    class DerivedModel : public QAbstractItemModel{
        Q_OBJECT
    public:
        //model is a singleton, function to get instance
        static DerivedModel& instance();
    
        explicit DerivedModel(QObject* parent);
        virtual ~DerivedModel();
    
        /////////////////model overloads//////////////////////////////
        QVariant data(const QModelIndex& index, int role) const;
        Qt::ItemFlags flags(const QModelIndex& index) const;
        QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
        QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const;
        QModelIndex parent(const QModelIndex& index) const;
        int rowCount(const QModelIndex& parent = QModelIndex()) const;
        int columnCount(const QModelIndex& parent = QModelIndex()) const {Q_UNUSED(parent); return 1;}
        //////////////////////////////////////////////////////////////
    
        //get the item from an index
        Item* item(const QModelIndex& index) const { return static_cast<Item*>(index.internalPointer());}
    
        //get the index from an item name
        const QModelIndex indexFromName(const QString& name);
    
        //add an item
        void addItem(const QString& name, Item* parent=nullptr);
    
        //get the selection model
        QItemSelectionModel* selectionModel() const {return m_selectionModel;}
    
    private:
        //the instance of the singleton to return
        static DerivedModel* m_instance;
    
        //the root object for the model
        //never actually used
        Item* m_rootItem;
    
        //selection model for handeling selection
        QItemSelectionModel* m_selectionModel;
    };
    #endif
    

    DerivedModel.cpp
    #include "DerivedModel.h"
    
    #include "Item.h"
    
    #include <QItemSelectionModel>
    #include <QDebug>
    
    //init static member
    DerivedModel* DerivedModel::m_instance = nullptr;
    
    DerivedModel& DerivedModel::instance(){
        //check if set
        if(!m_instance){
            qDebug() << "ERROR model instance not set";
            std::abort();
        }
        return *m_instance;
    }
    
    DerivedModel::DerivedModel(QObject* parent):
                                QAbstractItemModel(parent)
                                ,m_rootItem(nullptr)
                                ,m_selectionModel(nullptr)
    {
        //set the instance
        m_instance = this;
    
        //creae root item
        m_rootItem = new Item("ROOT");
    
        //init selection model
        m_selectionModel = new QItemSelectionModel(this, this);
    }
    
    DerivedModel::~DerivedModel(){
        //selection model is child so gets deleted
    }
    
    QVariant DerivedModel::data(const QModelIndex& index, int role) const {
        //if the index is valid
        if(!index.isValid()) {
            qDebug() << "Index not valid!";
            return QVariant();
        }
    
        //switch role
        switch(role){
            case Qt::DisplayRole:{
                QString name = static_cast<Item*>(index.internalPointer())->name();
                return name;
                break;
             }
            default:
                return QVariant();
        }
    }
    
    Qt::ItemFlags DerivedModel::flags(const QModelIndex& index) const {
        //check valid
        if(!index.isValid()) return 0;
    
        return static_cast<Item*>(index.internalPointer())->flags();
    }
    
    QVariant DerivedModel::headerData(int section, Qt::Orientation orientation, int role) const {
        //unused for now
        Q_UNUSED(section);
        Q_UNUSED(orientation);
        if(role==Qt::DisplayRole) return QVariant("HeaderData");
        else return QVariant();
    }
    
    QModelIndex DerivedModel::index(int row, int column, const QModelIndex& parent) const {
    
        Item* parentItem(nullptr);
    
        //is valid?
        if(!parent.isValid()) {
            parentItem = m_rootItem;
        }
        else {
            parentItem = item(parent);
        }
    
        //child pointer holder
        Item* childItem = parentItem->children().value(row);
        //is null?
        if(childItem){
            return createIndex(row, column, childItem);
        }
        else {
            return QModelIndex();
        }
    }
    
    QModelIndex DerivedModel::parent(const QModelIndex& index) const {
        //check valid
        if(!index.isValid()) return QModelIndex();
    
        //get child
        Item* childItem = static_cast<Item*>(index.internalPointer());
    
        //find parent
        Item* parentItem = childItem->parent();
    
        //is null?
        if(parentItem == m_rootItem) return QModelIndex();
    
        return createIndex(parentItem->parent()->children().indexOf(parentItem), 0, parentItem);
    }
    
    int DerivedModel::rowCount(const QModelIndex& parent) const {
        //parent holder
        Item* parentItem;
    
        //check 0 column (not sure why, but is in example, maybe the model iterates also through different columns)
        if(parent.column()>0) return 0;
    
        //check valid
        if(!parent.isValid()) parentItem = m_rootItem;
        else parentItem = static_cast<Item*>(parent.internalPointer());
    
        return parentItem->children().length();
    }
    
    const QModelIndex DerivedModel::indexFromName(const QString& name){
        //make a match based on the name
        //and return 1st match
        QModelIndex index = match(DerivedModel::index(0,0,QModelIndex()),
                Qt::DisplayRole, name, 1,
                Qt::MatchFlags(Qt::MatchExactly|Qt::MatchRecursive))
                .value(0);
    
        return index;
    }
    
    void DerivedModel::addItem(const QString& name, Item* parent){
        //check parent
        if(!parent) parent = m_rootItem;
    
        //create the item
        //will be deleted once parent is deleted
        new Item(name, parent);
    }
    

    Item.h:
    #ifndef ITEM_H
    #define ITEM_H
    
    #include <QString>
    #include <QList>
    #include <QDebug>
    
    class Item {
    
    public:
        Item(const QString& name, Item* parent=nullptr) :
                                    m_name(name), m_parent(parent){
            //add as child to parent
            if(parent) parent->addChild(this);
    
            //set the flag to enable selection
            m_flags = Qt::ItemIsSelectable;
    
            qDebug() << "Created Item "+name;
        };
    
        ~Item(){
            //delete children
            for (auto& child : m_children){
                delete child;
            }
        };
    
        //get the name
        const QString& name() const {return m_name;}
    
        //get the flags
        const Qt::ItemFlags& flags() const {return m_flags;}
    
        //gte the parent
        Item* parent() const {return m_parent;}
    
        //get the children
        const QList<Item*>& children() {return m_children;}
    
        //add a child
        void addChild(Item* item) {m_children.append(item);}
    
    private:
        //name
        QString m_name;
    
        //flags
        Qt::ItemFlags m_flags;
    
        //parent
        Item* m_parent;
    
        //list og children
        QList<Item*> m_children;
    };
    
    
    #endif
    

    Scene.h:
    #ifndef GRAPHICSSCENE_H
    #define GRAPHICSSCENE_H
    
    #include <QGraphicsScene>
    
    //fwd dec
    QT_FORWARD_DECLARE_CLASS(QItemSelection)
    QT_FORWARD_DECLARE_CLASS(QGraphicsRectItem)
    
    class Scene : public QGraphicsScene {
    public:
        Scene(QObject* parent);
        virtual ~Scene(){}
    
    public slots:
        //pass the selection to the squares
        void setSelection(const QItemSelection& selected, const QItemSelection& deselected);
    };
    
    #endif
    

    Scene.cpp:
    #include "Scene.h"
    #include "DerivedModel.h"
    #include "Item.h"
    
    #include <QItemSelectionModel>
    #include <QGraphicsRectItem>
    #include <QRect>
    #include <QDebug>
    
    Scene::Scene(QObject* parent) : QGraphicsScene(parent)
    {
        //connect to the models selection change
        connect(DerivedModel::instance().selectionModel(), &QItemSelectionModel::selectionChanged,
                this, &Scene::setSelection);
    }
    
    void Scene::setSelection(const QItemSelection& selected, const QItemSelection& deselected){
        Q_UNUSED(deselected);
        //testing changes
        int A = selected.size();
        int B = selected.indexes().size();
    
        QModelIndex index = selected.value(0).topLeft();
        QString name = "";
        if(index.isValid()) name = static_cast<Item*>(index.internalPointer())->name();
    
        qDebug() << "Scene recieved item selection change";
        qDebug() << "Number of selected QItemRanges from source = "+QString::number(A);
        qDebug() << "Number of selected INDEXES from source = "+QString::number(B);
        qDebug() << "Manually accessd 1st index in 1st range returns item named: "+name;
    }
    

    Widget.h
    #ifndef WIDGET_H
    #define WIDGET_H
    
    #include <QWidget>
    
    //fwd dec
    QT_FORWARD_DECLARE_CLASS(QPushButton)
    QT_FORWARD_DECLARE_CLASS(QVBoxLayout)
    QT_FORWARD_DECLARE_CLASS(QHBoxLayout)
    QT_FORWARD_DECLARE_CLASS(QGraphicsView)
    
    class DerivedModel;
    class Scene;
    
    class Widget : public QWidget{
    
    public:
        Widget(QWidget* parent=nullptr);
        virtual ~Widget(){}
    
    private slots:
        //button toggle alot
        void toggle(bool state);
    
    private:
        //layout
        QVBoxLayout* m_mainVBLayout;
    
        //horizontal layout for the buttons
        QHBoxLayout* m_HBButtonsLayout;
    
        //GraphicsView widget for the scene
        QGraphicsView* m_graphicsView;
    
        //the graphics scene recieving the change event where the problem is
        Scene* m_scene;
    
        //push buttons
        QPushButton* m_button1;
        QPushButton* m_button2;
    
        //the DerivedModel
        DerivedModel* m_model;
    };
    
    
    #endif
    

    Widget.cpp:
    #include "Widget.h"
    #include "DerivedModel.h"
    #include "Scene.h"
    
    #include <QPushButton>
    #include <QVBoxLayout>
    #include <QHBoxLayout>
    #include <QGraphicsView>
    #include <QDebug>
    #include <QItemSelection>
    
    Widget::Widget(QWidget* parent) : QWidget(parent)
                                      ,m_mainVBLayout(nullptr)
                                      ,m_HBButtonsLayout(nullptr)
                                      ,m_graphicsView(nullptr)
                                      ,m_scene(nullptr)
                                      ,m_button1(nullptr)
                                      ,m_button2(nullptr)
                                      ,m_model(nullptr)
    {
        //init the DerivedModel
        m_model = new DerivedModel(this);
    
        //add two items to the model
        m_model->addItem("A");
        m_model->addItem("B");
    
        //create the main layout
        m_mainVBLayout = new QVBoxLayout(this);
    
        //create the buttons layout
        m_HBButtonsLayout = new QHBoxLayout;
    
        //add it to the main layout
        m_mainVBLayout->addLayout(m_HBButtonsLayout);
    
        //create the buttons
        m_button1 = new QPushButton("A", this);
        m_button2 = new QPushButton("B", this);
    
        //set them to be checkable
        m_button1->setCheckable(true);
        m_button2->setCheckable(true);
    
        //connect their signals
        connect(m_button1, &QPushButton::toggled, this, &Widget::toggle);
        connect(m_button2, &QPushButton::toggled, this, &Widget::toggle);
    
        //add them to the layout
        m_HBButtonsLayout->addWidget(m_button1);
        m_HBButtonsLayout->addWidget(m_button2);
    
        //create the graphics view
        m_graphicsView = new QGraphicsView(this);
    
        //create the scene
        m_scene = new Scene(this);
        m_scene->setSceneRect(QRect(0,0,50,25));
    
        //set its scene
        m_graphicsView->setScene(m_scene);
    
        //add the graphics view to the layout
        m_mainVBLayout->addWidget(m_graphicsView);
    }
    
    void Widget::toggle(bool state){
        //get the sender
        QPushButton* button(nullptr);
        if(sender()==m_button1) button = m_button1;
        else button = m_button2;
    
        //get the name of the item related to the button to change
        QString name = button->text();
    
        //get the index based on the name
        //im using the instance of the DerivedModel because this is how I implement it in my project;
        QModelIndex itemIndex = DerivedModel::instance().indexFromName(name);
    
        //check if index is valid
        if(!itemIndex.isValid()){
            qDebug() << "Index for item "+name+" not valid!";
            return;
        }
        else
            qDebug() << "Found Item :)";
    
        //create a QItemSelection as how it is in my project
        QItemSelection selection;
    
        //add the index to the selection
        selection.select(itemIndex, itemIndex);
    
        //check the state
        if(state){
            //add to the selection
            DerivedModel::instance().selectionModel()->select(selection, QItemSelectionModel::Select);
        }
        else{
            //remove from selection
            DerivedModel::instance().selectionModel()->select(selection, QItemSelectionModel::Deselect);
        }
    }
    

    最佳答案

    好的,所以我找到了罪魁祸首:)

    万一其他人有相同的问题,我的错误是在我派生的QAbstractItemModel类的:: flags()函数中:
    在定义内部,我没有调用基类QAbstractItemModel::flags(index)函数,一旦我调用了该方法而不是返回自己的标志,一切都很好。

    因此,我认为只要您的项目具有模型可以调用的Qt::flags flags()函数,您就不必重新实现QAbstractItemModel::flags()函数。

    无论如何,该模型似乎通过QModelIndex::flags()函数查询标志。

    谢谢“Ezee”和“Kuba Ober”的帮助。

    关于c++ - Qt QItemSelection::indexes()返回错误,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/26361727/

    10-10 21:37