How to avoid to delete treemodel info when editing?
Good morning. I have finally created a treeconfig program to read a txt, then edit it in the interface, and then save it, but I have a problem.
I know that there is a treemodel example that is editable (http://doc.qt.io/qt-5/qtwidgets-itemviews-editabletreemodel-example.html), but this one is not using libconfig.h++
I decided to use libconfig.h++ in my linux because I can filter which kind of information is appearing in the values (int/string/...), because in the other example without libconfig, it uses qVariant, and accept all the types of inputs.
So even comparing with the other example, I am not able to make the following work:
My problem is that when I try to edit one value, the information inside dissapears, and if I click outside the value, it becomes 0. How can I avoid this both things? I want to edit a string in the middle for example, or just not to delete then info when missclicking or something.
The images below show an attempt at editing the value for confTimeout. Note that the text inside disappears when it is clicked into edit-mode and that the text sets to 0 when it is clicked out of focus.
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
EDIT:::
First of all, thanks @vahancho and @trebuchetMS
.
I have tried with vahancho example, but it throws an issue
Also I tried with with other combinations, but he idea is not to allow for example a "string" where a "int" should be placed.
I have also checked again the editableTreeModel of QtExamples, but it allows a string where a int should be placed, and I do not want this
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());
}
Any idea?
c++ qt qt5 qtreeview libconfig
add a comment |
Good morning. I have finally created a treeconfig program to read a txt, then edit it in the interface, and then save it, but I have a problem.
I know that there is a treemodel example that is editable (http://doc.qt.io/qt-5/qtwidgets-itemviews-editabletreemodel-example.html), but this one is not using libconfig.h++
I decided to use libconfig.h++ in my linux because I can filter which kind of information is appearing in the values (int/string/...), because in the other example without libconfig, it uses qVariant, and accept all the types of inputs.
So even comparing with the other example, I am not able to make the following work:
My problem is that when I try to edit one value, the information inside dissapears, and if I click outside the value, it becomes 0. How can I avoid this both things? I want to edit a string in the middle for example, or just not to delete then info when missclicking or something.
The images below show an attempt at editing the value for confTimeout. Note that the text inside disappears when it is clicked into edit-mode and that the text sets to 0 when it is clicked out of focus.
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
EDIT:::
First of all, thanks @vahancho and @trebuchetMS
.
I have tried with vahancho example, but it throws an issue
Also I tried with with other combinations, but he idea is not to allow for example a "string" where a "int" should be placed.
I have also checked again the editableTreeModel of QtExamples, but it allows a string where a int should be placed, and I do not want this
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());
}
Any idea?
c++ qt qt5 qtreeview libconfig
QVariant... can also filter which type is being used.
– TrebuchetMS
Nov 14 '18 at 11:55
May I ask what is the use ofif (role != Qt::EditRole) return false;
inTreeModel::setData()
? Also the example provided usesif (role != Qt::DisplayRole && role != Qt::EditRole) return QVariant();
. In yourTreeModel::data()
,role != Qt::EditRole
was removed. Is there explanation for this as well?
– TrebuchetMS
Nov 14 '18 at 12:05
you could publish your project on github and thus be able to test your code easily
– eyllanesc
Nov 15 '18 at 17:41
I have tried you example @vahancho , but it is still not working. I have updated the main comment showing the problem.
– Minikornio
Nov 16 '18 at 11:46
add a comment |
Good morning. I have finally created a treeconfig program to read a txt, then edit it in the interface, and then save it, but I have a problem.
I know that there is a treemodel example that is editable (http://doc.qt.io/qt-5/qtwidgets-itemviews-editabletreemodel-example.html), but this one is not using libconfig.h++
I decided to use libconfig.h++ in my linux because I can filter which kind of information is appearing in the values (int/string/...), because in the other example without libconfig, it uses qVariant, and accept all the types of inputs.
So even comparing with the other example, I am not able to make the following work:
My problem is that when I try to edit one value, the information inside dissapears, and if I click outside the value, it becomes 0. How can I avoid this both things? I want to edit a string in the middle for example, or just not to delete then info when missclicking or something.
The images below show an attempt at editing the value for confTimeout. Note that the text inside disappears when it is clicked into edit-mode and that the text sets to 0 when it is clicked out of focus.
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
EDIT:::
First of all, thanks @vahancho and @trebuchetMS
.
I have tried with vahancho example, but it throws an issue
Also I tried with with other combinations, but he idea is not to allow for example a "string" where a "int" should be placed.
I have also checked again the editableTreeModel of QtExamples, but it allows a string where a int should be placed, and I do not want this
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());
}
Any idea?
c++ qt qt5 qtreeview libconfig
Good morning. I have finally created a treeconfig program to read a txt, then edit it in the interface, and then save it, but I have a problem.
I know that there is a treemodel example that is editable (http://doc.qt.io/qt-5/qtwidgets-itemviews-editabletreemodel-example.html), but this one is not using libconfig.h++
I decided to use libconfig.h++ in my linux because I can filter which kind of information is appearing in the values (int/string/...), because in the other example without libconfig, it uses qVariant, and accept all the types of inputs.
So even comparing with the other example, I am not able to make the following work:
My problem is that when I try to edit one value, the information inside dissapears, and if I click outside the value, it becomes 0. How can I avoid this both things? I want to edit a string in the middle for example, or just not to delete then info when missclicking or something.
The images below show an attempt at editing the value for confTimeout. Note that the text inside disappears when it is clicked into edit-mode and that the text sets to 0 when it is clicked out of focus.
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
EDIT:::
First of all, thanks @vahancho and @trebuchetMS
.
I have tried with vahancho example, but it throws an issue
Also I tried with with other combinations, but he idea is not to allow for example a "string" where a "int" should be placed.
I have also checked again the editableTreeModel of QtExamples, but it allows a string where a int should be placed, and I do not want this
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());
}
Any idea?
c++ qt qt5 qtreeview libconfig
c++ qt qt5 qtreeview libconfig
edited Nov 16 '18 at 11:44
Minikornio
asked Nov 14 '18 at 11:28
MinikornioMinikornio
172
172
QVariant... can also filter which type is being used.
– TrebuchetMS
Nov 14 '18 at 11:55
May I ask what is the use ofif (role != Qt::EditRole) return false;
inTreeModel::setData()
? Also the example provided usesif (role != Qt::DisplayRole && role != Qt::EditRole) return QVariant();
. In yourTreeModel::data()
,role != Qt::EditRole
was removed. Is there explanation for this as well?
– TrebuchetMS
Nov 14 '18 at 12:05
you could publish your project on github and thus be able to test your code easily
– eyllanesc
Nov 15 '18 at 17:41
I have tried you example @vahancho , but it is still not working. I have updated the main comment showing the problem.
– Minikornio
Nov 16 '18 at 11:46
add a comment |
QVariant... can also filter which type is being used.
– TrebuchetMS
Nov 14 '18 at 11:55
May I ask what is the use ofif (role != Qt::EditRole) return false;
inTreeModel::setData()
? Also the example provided usesif (role != Qt::DisplayRole && role != Qt::EditRole) return QVariant();
. In yourTreeModel::data()
,role != Qt::EditRole
was removed. Is there explanation for this as well?
– TrebuchetMS
Nov 14 '18 at 12:05
you could publish your project on github and thus be able to test your code easily
– eyllanesc
Nov 15 '18 at 17:41
I have tried you example @vahancho , but it is still not working. I have updated the main comment showing the problem.
– Minikornio
Nov 16 '18 at 11:46
QVariant... can also filter which type is being used.
– TrebuchetMS
Nov 14 '18 at 11:55
QVariant... can also filter which type is being used.
– TrebuchetMS
Nov 14 '18 at 11:55
May I ask what is the use of
if (role != Qt::EditRole) return false;
in TreeModel::setData()
? Also the example provided uses if (role != Qt::DisplayRole && role != Qt::EditRole) return QVariant();
. In your TreeModel::data()
, role != Qt::EditRole
was removed. Is there explanation for this as well?– TrebuchetMS
Nov 14 '18 at 12:05
May I ask what is the use of
if (role != Qt::EditRole) return false;
in TreeModel::setData()
? Also the example provided uses if (role != Qt::DisplayRole && role != Qt::EditRole) return QVariant();
. In your TreeModel::data()
, role != Qt::EditRole
was removed. Is there explanation for this as well?– TrebuchetMS
Nov 14 '18 at 12:05
you could publish your project on github and thus be able to test your code easily
– eyllanesc
Nov 15 '18 at 17:41
you could publish your project on github and thus be able to test your code easily
– eyllanesc
Nov 15 '18 at 17:41
I have tried you example @vahancho , but it is still not working. I have updated the main comment showing the problem.
– Minikornio
Nov 16 '18 at 11:46
I have tried you example @vahancho , but it is still not working. I have updated the main comment showing the problem.
– Minikornio
Nov 16 '18 at 11:46
add a comment |
1 Answer
1
active
oldest
votes
I think the problem is that your TreeModel::data()
function, according to the code you provided, always returns an empty data when requested role is not display role. This means that if you bring a node into edit mode the editor (line edit) shows nothing. When you move the focus, the editor closes and sets its empty value to the model. That's why you get this '0'.
To fix this behavior you need to expose the same data in edit mode as in display mode, i.e. you code should look like:
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);
}
it should have been && instead of this || !! now it works
– Minikornio
Nov 30 '18 at 14:42
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53299167%2fhow-to-avoid-to-delete-treemodel-info-when-editing%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
I think the problem is that your TreeModel::data()
function, according to the code you provided, always returns an empty data when requested role is not display role. This means that if you bring a node into edit mode the editor (line edit) shows nothing. When you move the focus, the editor closes and sets its empty value to the model. That's why you get this '0'.
To fix this behavior you need to expose the same data in edit mode as in display mode, i.e. you code should look like:
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);
}
it should have been && instead of this || !! now it works
– Minikornio
Nov 30 '18 at 14:42
add a comment |
I think the problem is that your TreeModel::data()
function, according to the code you provided, always returns an empty data when requested role is not display role. This means that if you bring a node into edit mode the editor (line edit) shows nothing. When you move the focus, the editor closes and sets its empty value to the model. That's why you get this '0'.
To fix this behavior you need to expose the same data in edit mode as in display mode, i.e. you code should look like:
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);
}
it should have been && instead of this || !! now it works
– Minikornio
Nov 30 '18 at 14:42
add a comment |
I think the problem is that your TreeModel::data()
function, according to the code you provided, always returns an empty data when requested role is not display role. This means that if you bring a node into edit mode the editor (line edit) shows nothing. When you move the focus, the editor closes and sets its empty value to the model. That's why you get this '0'.
To fix this behavior you need to expose the same data in edit mode as in display mode, i.e. you code should look like:
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);
}
I think the problem is that your TreeModel::data()
function, according to the code you provided, always returns an empty data when requested role is not display role. This means that if you bring a node into edit mode the editor (line edit) shows nothing. When you move the focus, the editor closes and sets its empty value to the model. That's why you get this '0'.
To fix this behavior you need to expose the same data in edit mode as in display mode, i.e. you code should look like:
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);
}
answered Nov 15 '18 at 7:31
vahanchovahancho
15.5k32430
15.5k32430
it should have been && instead of this || !! now it works
– Minikornio
Nov 30 '18 at 14:42
add a comment |
it should have been && instead of this || !! now it works
– Minikornio
Nov 30 '18 at 14:42
it should have been && instead of this || !! now it works
– Minikornio
Nov 30 '18 at 14:42
it should have been && instead of this || !! now it works
– Minikornio
Nov 30 '18 at 14:42
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53299167%2fhow-to-avoid-to-delete-treemodel-info-when-editing%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
QVariant... can also filter which type is being used.
– TrebuchetMS
Nov 14 '18 at 11:55
May I ask what is the use of
if (role != Qt::EditRole) return false;
inTreeModel::setData()
? Also the example provided usesif (role != Qt::DisplayRole && role != Qt::EditRole) return QVariant();
. In yourTreeModel::data()
,role != Qt::EditRole
was removed. Is there explanation for this as well?– TrebuchetMS
Nov 14 '18 at 12:05
you could publish your project on github and thus be able to test your code easily
– eyllanesc
Nov 15 '18 at 17:41
I have tried you example @vahancho , but it is still not working. I have updated the main comment showing the problem.
– Minikornio
Nov 16 '18 at 11:46