早上好。我终于创建了一个treeconfig程序来读取txt,然后在界面中对其进行编辑,然后保存它,但是我遇到了问题。
我知道有一个可编辑(http://doc.qt.io/qt-5/qtwidgets-itemviews-editabletreemodel-example.html)的树模型示例,但是此示例未使用libconfig.h ++
我决定在Linux中使用libconfig.h ++,因为我可以过滤值(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示例,但是它引发了问题
我也尝试过使用其他组合,但是他的想法是不允许在“ int”中放置“ int”。
我也再次检查了QtExamples的editableTreeModel,但是它允许在应该放置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());
}
有什么主意吗?
答案 0 :(得分:0)
我认为问题在于,根据您提供的代码,您的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);
}