在QTableView上插入QSortFilterProxyModel意外崩溃

时间:2018-06-08 11:08:21

标签: qt

我写了一个小Qt原型,其中包含QTreeView,我插入QStandardItemModel。从那里,我希望能够在QTableView中查看我的树的最后一级,我希望它是可排序的,为什么不可以过滤。这似乎是使用QSortFilterProxyModel的完美场景。实施后,全局视图看起来像我想要的左侧是QTreeView,右侧是QTableView(见附图)。enter image description here

但是,我面临两个问题:

  • 只有第一列可以排序
  • 更糟糕的是,如果我选择一个不在第一列中的项目,然后单击其中一个水平标题,应用程序会意外崩溃,而我的任何实现方法都没有任何调试回溯。

我可能误解了有关Qt代理模型的使用但不知道什么,我在堆栈或其他地方找不到任何明确的提示。

这是我的原型cpp文件:

#include <string>
#include <vector>

#include <QDebug>
#include <QAbstractProxyModel>
#include <QSortFilterProxyModel>
#include <QStandardItem>
#include <QStandardItemModel>

#include "mainwindow.h"
#include "ui_mainwindow.h"

struct Peak {
    Peak(const std::string& name, int index, double qx, double qy, double qz);

    std::string _name;

    int _index;

    double _qx;
    double _qy;
    double _qz;

};

Peak::Peak(const std::string& name, int index, double qx, double qy, double qz)
: _name(name),
  _index(index),
  _qx(qx),
  _qy(qy),
  _qz(qz)
{

}

struct PeakItem : public QStandardItem
{
    PeakItem(const Peak& peak);

    Peak _peak;

};

PeakItem::PeakItem(const Peak& peak)
: _peak(peak)
{
    setText(QString::fromStdString(_peak._name));

    appendRow(new QStandardItem(QString::number(_peak._index)));
    appendRow(new QStandardItem(QString::number(_peak._qx)));
    appendRow(new QStandardItem(QString::number(_peak._qy)));
    appendRow(new QStandardItem(QString::number(_peak._qz)));
}

struct PeakListItem : public QStandardItem
{
    PeakListItem(const std::vector<Peak>& peaks);

    std::vector<Peak> _peaks;
};

PeakListItem::PeakListItem(const std::vector<Peak>& peaks)
: _peaks(peaks)
{
    setText("Peaks");
    setCheckable(true);

    for (size_t r=0; r < _peaks.size(); ++r) {
        auto item = new PeakItem(_peaks[r]);
        appendRow(item);
    }
}

struct PeakListProxyModel : public QSortFilterProxyModel {

    PeakListProxyModel(PeakListItem* peak_list_item);

    virtual QModelIndex mapFromSource(const QModelIndex &) const override;
    virtual QModelIndex mapToSource(const QModelIndex &) const override;

    virtual QModelIndex parent(const QModelIndex &) const override;
    virtual QModelIndex index(int, int, const QModelIndex & p = QModelIndex()) const override;

    virtual int rowCount(const QModelIndex & p = QModelIndex()) const override;
    virtual int columnCount(const QModelIndex & p = QModelIndex()) const override;

    virtual void sort(int column, Qt::SortOrder order) override;

    PeakListItem* _peak_list_item;

};

PeakListProxyModel::PeakListProxyModel(PeakListItem* peak_list_item)
: _peak_list_item(peak_list_item)
{
}

QModelIndex PeakListProxyModel::parent(const QModelIndex &) const
{
    return QModelIndex();
}

QModelIndex PeakListProxyModel::index(int row, int column, const QModelIndex& index) const
{
//    qDebug()<<"create index "<<row<<" --- "<<column<<" --- "<<index;
    return createIndex(row, column);
}

void PeakListProxyModel::sort(int column, Qt::SortOrder order)
{
    qDebug()<<"sort "<<column;
    QAbstractProxyModel::sort(column,order);
    layoutChanged();
}

QModelIndex PeakListProxyModel::mapFromSource(const QModelIndex& source_index) const
{
    if (!source_index.isValid()) {
        return QModelIndex();
    }

    auto model = dynamic_cast<QStandardItemModel*>(sourceModel());
    auto item = model->itemFromIndex(source_index);
    auto parent_item = item->parent();

    auto p = dynamic_cast<PeakItem*>(parent_item);

    if (!p) {
        return QModelIndex();
    }

    auto proxy_index = createIndex(parent_item->index().row(),item->index().row());
    qDebug()<<"map from source --- "<<source_index<<" --- "<<proxy_index;

    return proxy_index;
}

QModelIndex PeakListProxyModel::mapToSource(const QModelIndex& proxy_index) const
{
    if (!proxy_index.isValid()) {
        return QModelIndex();
    }

    auto peak_item = _peak_list_item->child(proxy_index.row());

    auto prop_item = peak_item->child(proxy_index.column());

    auto source_index = prop_item->index();

//    qDebug()<<"map to source "<<proxy_index<<"  ---  "<<source_index<<" ---- "<<prop_item;

    return source_index;
}

int PeakListProxyModel::rowCount(const QModelIndex& proxy_index) const
{
    if (proxy_index.isValid()) {
        return 0;
    } else {
        return _peak_list_item->rowCount();
    }
}

int PeakListProxyModel::columnCount(const QModelIndex& proxy_index) const
{
    if (proxy_index.isValid()) {
        return 0;
    } else {
        return 4;
    }
}


MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    QStandardItemModel* model = new  QStandardItemModel();

    QStandardItem* experiment = new QStandardItem("Experiment");

    QStandardItem* peaks_item = new QStandardItem("Peaks");

    std::vector<Peak> peaks;
    peaks.reserve(4);
    for (int i = 0; i < 4; ++i) {
        peaks.emplace_back("Peak"+std::to_string(i),i,i,i,i);
    }

//    PeakListItem* peak_list_item1 = new PeakListItem(peaks);
//    peaks_item->appendRow(peak_list_item1);

    PeakListItem* peak_list_item2 = new PeakListItem(peaks);
    peaks_item->appendRow(peak_list_item2);

    experiment->appendRow(peaks_item);

    model->appendRow(experiment);

    ui->treeView->setModel(model);

    PeakListProxyModel* proxy_model = new PeakListProxyModel(peak_list_item2);
    proxy_model->setSourceModel(model);

    ui->tableView->setModel(proxy_model);
    ui->tableView->setSortingEnabled(true);

    for (int i = 0; i < peaks.size(); ++i) {
//        ui->treeView->setRowHidden(i,peak_list_item1->index(),true);
//        ui->treeView->setRowHidden(i,peak_list_item2->index(),true);
    }
}

MainWindow::~MainWindow()
{
    delete ui;
}

1 个答案:

答案 0 :(得分:1)

深入挖掘后,我发现link

基本上解释了如何解决我的问题。为了完成这项工作,我们必须管道两个模型,一个执行从QAbstractProxyModel派生的映射,另一个执行排序/文件串,可以是标准QSortFilterProxyModel