首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >QItemSelection::indexes()返回错误

QItemSelection::indexes()返回错误
EN

Stack Overflow用户
提问于 2014-10-14 13:11:01
回答 1查看 3K关注 0票数 2

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

我的QAbstractItemModel不是小部件,也不是显示的,只管理层次结构。当选择更改时,QItemSelection模型发出选择更改信号,选择和取消选择的QItemSelections似乎包含正确的数据。

当我调用它们的:: indexes ()函数来获取所选项的索引时,就会出现问题,它不返回任何项,即使这样,我也知道项是被选中的,并且:width()和::height()函数返回正确的值。

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

代码语言:javascript
复制
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并在根项(根)下保存两个项(A和B)。按一个按钮表示QItemSelectionModel选择/取消选择A或B。如果在模型"Found :)“中找到该项目,则该项目将被打印出来,显示该项目存在并可供模型使用。QGraphicsView保存一个场景(源自QGraphicsScene)。该场景是空的,并且只表示接收来自选择模型的selectionChange信号的对象。当它接收到该信号时,它会打印“场景接收项选择更改”,这样我们就可以看到信号已经过去了。然后是真正的东西:

  1. 我们计算出传入的"selected“变量中有多少QItemRanges是正确的。
  2. 我们得到在传递的"selected“变量(selected.indexes())中返回0的所有范围内有多少个索引,这是错误的,我们很快就会看到
  3. 我们手动访问"selected“变量(selected.value(0).topLeft())中第一个范围内的第一个索引,并看到它确实包含指向正确项的索引,显示了问题所在。

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

Linux Manjaro Gcc 4.9.1 Qt5.3

衍生模型h:

代码语言:javascript
复制
#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

代码语言:javascript
复制
#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:

代码语言:javascript
复制
#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

史景天:

代码语言:javascript
复制
#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:

代码语言:javascript
复制
#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

代码语言:javascript
复制
#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:

代码语言:javascript
复制
#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);
    }
}
EN

回答 1

Stack Overflow用户

发布于 2014-10-16 10:15:09

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

如果其他人有同样的问题,我的错误出现在派生QAbstractItemModel类的::标志()函数中:在定义中,我没有调用基类QAbstractItemModel::error (索引)函数,一旦我调用它,而不是自己返回标志,一切都进行得很顺利。

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

似乎模型是通过QModelIndex::seems ()函数来查询标志的。

感谢你们"Ezee“和"Kuba”愿意提供帮助。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26361727

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档