Как избежать удаления информации о древовидной модели при редактировании? - PullRequest
0 голосов
/ 14 ноября 2018

Доброе утро.Наконец-то я создал программу treeconfig для чтения txt, затем отредактировал ее в интерфейсе и сохранил, но у меня возникла проблема.

Я знаю, что есть пример модели дерева, который можно редактировать (http://doc.qt.io/qt-5/qtwidgets-itemviews-editabletreemodel-example.html),, но этот не использует libconfig.h ++

Я решил использовать libconfig.h ++ в моем Linux, потому что я могу фильтровать, какая информация отображается в значениях (int / string / ...), потому что в другом примере без libconfig он использует qVariant и принимает все типы входных данных.

Так что даже по сравнению с другим примером я не могу заставить работать следующее: Моя проблема в том, чтокогда я пытаюсь отредактировать одно значение, информация внутри исчезает, и если я щелкаю за пределами значения, оно становится равным 0. Как можно избежать обеих этих вещей? Я хочу, например, редактировать строку в середине или просто не удалятьзатем информация при неправильном нажатии или что-то в этом роде.

На изображениях ниже показана попытка редактирования значения для confTimeout. Обратите внимание, что текст внутри исчезаетпри нажатии в режиме редактирования и текст устанавливается в 0, если щелкнуть не в фокусе.

mainwindow.cpp

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

#include <QTextStream>

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

void MainWindow::setConfig(libconfig::Config *config)
{
    tm = std::make_unique<TreeModel>(config, this);
    ui->treeView->setModel(tm.get());
}

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

/*
void MainWindow::on_treeView_activated(const QModelIndex &index)
{
    QString val = ui->treeView->model()->data(index).toString();
    ui->lineEdit->setText(val);
}

*/

void MainWindow::on_pushButton_clicked()
{
    tm->saveSettings();
}

treeitem.cpp

#include "treeitem.h"
#include <libconfig.h++>

static QVariant getIndexOrName(const libconfig::Setting &setting)
{
    if (!setting.isRoot()) {
        const auto &parent = setting.getParent();
        if (parent.isArray() || parent.isList())
            return setting.getIndex();
    }

    return setting.getName();
}

static QVariant getValueOrSize(const libconfig::Setting &setting)
{
    using namespace libconfig;
    switch (setting.getType()) {
    // scalar types
    case Setting::TypeInt:
        return setting.operator int();

    case Setting::TypeInt64:
        return setting.operator long long();

    case Setting::TypeFloat:
        return setting.operator double();

    case Setting::TypeString:
        return setting.c_str();

    case Setting::TypeBoolean:
        return setting.operator bool();


    // aggregate types
    case Setting::TypeGroup:
        return QString{"Group. Size: %1"}.arg(setting.getLength());

    case Setting::TypeArray:
        return QString{"Array. Size: %1"}.arg(setting.getLength());

    case Setting::TypeList:
        return QString{"List. Size: %1"}.arg(setting.getLength());


    // not used
    case Setting::TypeNone:
        break;
    }

    return QVariant{};
}

static bool setValue(libconfig::Setting &setting, const QVariant &value)
{
    using namespace libconfig;
    switch (setting.getType()) {
    // scalar types
    case Setting::TypeInt:
        if (value.canConvert(QVariant::Int)) {
            setting = value.toInt();
            return true;
        }
    case Setting::TypeInt64:
        if (value.canConvert(QVariant::LongLong)) {
            setting = value.toLongLong();
            return true;
        }
    case Setting::TypeFloat:
        if (value.canConvert(QVariant::Double)) {
            setting = value.toFloat();
            return true;
        }
    case Setting::TypeString:
        if (value.canConvert(QVariant::String)) {
            setting = value.toString().toStdString();
            return true;
        }
    case Setting::TypeBoolean:
        if (value.canConvert(QVariant::Bool)) {
            setting = value.toBool();
            return true;
        }
    default:
        break;
    }

    return false;
}

TreeItem::TreeItem(libconfig::Setting *setting, TreeItem *parentItem)
    : m_setting{setting}, m_parentItem{parentItem}
{
    if (setting->isAggregate()) {
        for (auto &setting : *setting) {
            m_subSettings.push_back(new TreeItem(&setting, this));
        }
    }
}

TreeItem::~TreeItem() { qDeleteAll(m_subSettings); }

TreeItem *TreeItem::child(int row) { return m_subSettings.at(row); }

int TreeItem::childCount() const { return m_subSettings.size(); }

int TreeItem::columnCount() const { return 2; }

QVariant TreeItem::data(int column) const
{
    switch (column) {
    case 0:
        return getIndexOrName(*m_setting);
    case 1:
        return getValueOrSize(*m_setting);
    default:
        return QVariant{};
    }
}

bool TreeItem::setData(const QVariant &value)
{
    if (m_setting->isAggregate())
        return false;

    return setValue(*m_setting, value);
}

int TreeItem::row() const
{
    if (!m_parentItem)
        return 0;

    return m_parentItem->m_subSettings.indexOf(const_cast<TreeItem *>(this));
}

TreeItem *TreeItem::parentItem() { return m_parentItem; }

treemodel

    #include "treemodel.h"
    #include "treeitem.h"

    #include <QFile>
    #include <libconfig.h++>
    #include <QDateTime>

    TreeModel::TreeModel(libconfig::Config *config, QObject *parent)
        : QAbstractItemModel{parent}, m_rootSetting{std::make_unique<TreeItem>(
                                                        &(config->getRoot()), nullptr)}, m_config{config}
    {
    }

    TreeModel::~TreeModel()
    {
    }

    QVariant TreeModel::data(const QModelIndex &index, int role) const
    {
        if (!index.isValid())
            return QVariant();

        if (role != Qt::DisplayRole)
            return QVariant();

        TreeItem *item = static_cast<TreeItem*>(index.internalPointer());

        return item->data(index.column());
    }

    bool TreeModel::setData(const QModelIndex &index, const QVariant &value, int role)
    {
        if (!index.isValid())
            return false;

        if (role != Qt::EditRole)
            return false;

        TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
        return item->setData(value);
    }

    Qt::ItemFlags TreeModel::flags(const QModelIndex &index) const
    {

        if (!index.isValid())
            //return Qt::NoItemFlags;
            return 0;

        //return QAbstractItemModel::flags(index);
        return Qt::ItemIsEditable | QAbstractItemModel::flags(index);
    }

    QVariant TreeModel::headerData(int section, Qt::Orientation orientation,
                                   int role) const
    {
        if (orientation != Qt::Horizontal || role != Qt::DisplayRole)
            return QVariant{};

        switch (section) {
        case 0:
            return "Name";
        case 1:
            return "Value";
        default:
            return QVariant{};
        }
    }

QModelIndex TreeModel::index(int row, int column,
                             const QModelIndex &parent) const
{
    if (!hasIndex(row, column, parent))
        return QModelIndex();

    TreeItem *parentItem;

    if (!parent.isValid())
        parentItem = m_rootSetting.get();
    else
        parentItem = static_cast<TreeItem*>(parent.internalPointer());

    TreeItem *childItem = parentItem->child(row);
    if (childItem)
        return createIndex(row, column, childItem);
    else
        return QModelIndex();
}

QModelIndex TreeModel::parent(const QModelIndex &index) const
{
    if (!index.isValid())
        return QModelIndex();

    TreeItem *childItem = static_cast<TreeItem *>(index.internalPointer());
    TreeItem *parentItem = childItem->parentItem();

    if (parentItem == m_rootSetting.get())
        return QModelIndex();

    return createIndex(parentItem->row(), 0, parentItem);
}

int TreeModel::rowCount(const QModelIndex &parent) const
{
    TreeItem *parentItem;
    if (parent.column() > 0)
        return 0;

    if (!parent.isValid())
        parentItem = m_rootSetting.get();
    else
        parentItem = static_cast<TreeItem*>(parent.internalPointer());

    return parentItem->childCount();
}

int TreeModel::columnCount(const QModelIndex &parent) const
{
    if (parent.isValid())
        return static_cast<TreeItem*>(parent.internalPointer())->columnCount();
    else
        return m_rootSetting->columnCount();
}

bool TreeModel::saveSettings(QString filename) const
{
    if (filename.isEmpty())
        filename = QString::fromLocal8Bit(m_config->getRoot().getSourceFile());
    QString today = QDateTime::currentDateTime().toString("_yyyy.MM.dd_hh:mm");
    QFile::copy(filename, filename+today+".backup");
    try {
        m_config->writeFile(filename.toLocal8Bit().constData());
    } catch (...) {
        return false;
    }

    return true;
}

o

o

o

o

РЕДАКТИРОВАНИЕ :::

Прежде всего, спасибо @vahancho и @trebuchetMS.Я попытался с примером Vahancho, но он бросает проблему

enter image description here

Также я пытался с другими комбинациями, но он идея не разрешать, например,"string", где должно быть помещено "int".

Я также еще раз проверил editableTreeModel из QtExamples, но он разрешает строку, в которой должен быть помещен int, и я не хочу этого

QVariant TreeModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid())
        return QVariant();

    if (role != Qt::DisplayRole && role != Qt::EditRole)
        return QVariant();

    TreeItem *item = getItem(index);

    return item->data(index.column());
}

Есть идеи?

1 Ответ

0 голосов
/ 15 ноября 2018

Мне кажется, проблема в том, что ваша TreeModel::data() функция, согласно предоставленному вами коду, всегда возвращает пустые данные, когда запрошенная роль не отображает роль.Это означает, что если вы переводите узел в режим редактирования, редактор (редактирование строки) ничего не показывает.Когда вы перемещаете фокус, редактор закрывается и устанавливает его пустое значение для модели.Вот почему вы получаете это '0'.

Чтобы исправить это поведение, вам нужно выставить те же данные в режиме редактирования, что и в режиме отображения, т.е. ваш код должен выглядеть следующим образом:

QVariant TreeModel::data(const QModelIndex &index, int role) const
{
  if (!index.isValid())
    return QVariant();

  // Returns the same data both in display and edit modes.
  if (role == Qt::DisplayRole || role == Qt::EditRole)
  {
    TreeItem *item = static_cast<TreeItem *>(index.internalPointer());
    return item->data(index.column());
  }
  return QAbstractItemModel::data(index, role);
}
...