Redefining QTreeWidgetItem::operator< - c++

My main goal here is to redefine operator< so that I can sort my columns numerically instead of alphabetically. The code I have so far:
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
//bunch of includes...
#include <QTreeWidgetItem>
#include <QTreeWidget>
extern QSqlDatabase db;
extern QString prefix;
extern QString site;
extern QString dbname;
extern QString user;
namespace Ui {
class mainwindow;
}
class clientinfo;
class mainwindow : public QMainWindow
{
Q_OBJECT
public:
explicit mainwindow(QWidget *parent = 0);
void rPopulate();
void rbookingdisplay();
QPushButton *button;
~mainwindow();
public slots:
//slots...
private:
Ui::mainwindow *ui;
void closeEvent(QCloseEvent *close);
};
class TreeWidgetItem : public QTreeWidgetItem
{
public:
TreeWidgetItem(QTreeWidget *tree) : QTreeWidgetItem(tree) {}
TreeWidgetItem(QTreeWidget * parent, const QStringList & strings)
: QTreeWidgetItem (parent,strings) {}
bool operator< (const QTreeWidgetItem &other) const
{
int sortCol = treeWidget()->sortColumn();
int myNumber = text(sortCol).toInt();
int otherNumber = other.text(sortCol).toInt();
return myNumber < otherNumber;
}
};
#endif // MAINWINDOW_H
and in mainwindow.cpp I have ui->_display->setSortingEnabled(true);
somehow it doesn't use the redefined operator< (the redefined function is never called, it uses the predefined one). Please help.
ui->_abooking->clear();
ui->_abooking->setSortingEnabled(false);
QSqlQuery query;
query.prepare(" SELECT shownumdays, shownumpastdays FROM setting_"+ user +
" WHERE id = 1; ");
query.exec();
query.first();
int days = query.record().value("shownumdays").toInt();
int pastdays = query.record().value("shownumpastdays").toInt();
query.prepare(" SELECT `"+Columns.join("`, `")+
"`,`Currency`, `# of Room` "
" FROM abooking "
" WHERE (DATE_ADD(`Arrival Date`,INTERVAL `Nights` - 1 DAY) >= (CURRENT_DATE - "+ QString::number(pastdays) +") AND "
" (TO_DAYS(`Arrival Date`) + `Nights` - 1 - TO_DAYS(NOW())) <= "+ QString::number(days) +") ");
query.exec();
QString confirm_num = "";
bool flip = true;
while (query.next()){
if (!(confirm_num == query.record().value("Confirmation #").toString())) {
flip = (!flip);
}
QTreeWidgetItem *item = new QTreeWidgetItem();
for (int i = 0; i < Columns.length(); i++) {
if (Columns.at(i) == "Arrival Date") {
item->setText(i, query.record().value(Columns.at(i)).toDate().toString("dd-MM-yyyy"));
} else if ((Columns.at(i) == "Amount Due" || Columns.at(i) == "Paid") && (confirm_num == query.record().value("Confirmation #").toString())) {
item->setText(i, "");
} else if ((Columns.at(i) == "Arrival Time")){
item->setText(i, " " + query.record().value(Columns.at(i)).toTime().toString("hh:mm"));
} else {
item->setText(i, query.record().value(Columns.at(i)).toString());
}
if (Columns.at(i) == "Amount Due" && (!(item->text(i) == ""))) {
item->setTextColor(i, Qt::darkRed);
item->setText(i, item->text(i) + " " + query.record().value("Currency").toString());
} else if (Columns.at(i) == "Room") {
item->setText(i, query.record().value("# of Room").toString() + " " + item->text(i));
}
if (flip) {
item->setBackground(i , Qt::gray);
}
}
if ((!(confirm_num == query.record().value("Confirmation #").toString()))) {
confirm_num = query.record().value("Confirmation #").toString();
ui->_abooking->addTopLevelItem(item);
} else {
ui->_abooking->topLevelItem(ui->_abooking->topLevelItemCount() - 1)->addChild(item);
ui->_abooking->topLevelItem(ui->_abooking->topLevelItemCount() - 1)->setExpanded(true);
}
}
ui->_abooking->setSortingEnabled(true);

You're reimplementing QTreeWidgetItem with a custom class, but then you don't use it when populating the QTreeWidget.
Instead of
QTreeWidgetItem *item = new QTreeWidgetItem();
this should be:
TreeWidgetItem *item = new TreeWidgetItem();
Other than that, your code for operator < looks fine. I'm using the same and it works for me.

bool operator< (const QTreeWidgetItem &other) const
{
int sortCol = treeWidget()->sortColumn();
int myNumber = text(sortCol).toInt();
int otherNumber = other.text(sortCol).toInt();
return myNumber < otherNumber;
}
With reference to your code here above:
I think your problem is that the sort column on the widget remains constant for all QTreeWidgetItems. You have to sort on the value of the item (not the column of the widget):
Therefore the code should look like this:
bool operator< (const QTreeWidgetItem &other) const
{
Q_ASSERT( other.treeWidget() == treeWidget() );
const int col = treeWidget()->sortColumn();
const int role = Qt::DisplayRole;
return( data( col, role ).toInt() < other.data( col, role ).toInt() );
}

The cells are sorted according to the type of data you store in them. You don't need to redefine an operator for that, because QVariant will take care of the comparison for you.
For example, you should use:
item−>setData(0, `Qt::EditRole`, 10);
instead of:
item->setText(0, "10");

Related

Last character LineEdit

I've two list of value. the first is list of integer and second is a list of strings. i want to display these different lists based on the last content of lineEdit. For Example when the user enter A => QCompleter show me list of strings. If the user enter A1 => QCompleter show me list of integer because the last character of input is 1.
I try like this :
void QtGuiApplication1::maFonction(QString text)
{
QString lastCaractor = text.mid(text.length() - 1, 1);
if (is_number(lastCaractor.toStdString()) == true)
{
QStringList list = { "1","2","7" };
StringCompleter->setModel(new QStringListModel(list, StringCompleter));
StringCompleter->setCompletionPrefix(lastCaractor);
}
else
{
QStringList list = { "AAAA","AA","BB","AC" };
StringCompleter->setModel(new QStringListModel(list, StringCompleter));
StringCompleter->setCompletionPrefix(lastCaractor);
}
}
bool QtGuiApplication1::is_number(const std::string& s)
{
std::string::const_iterator it = s.begin();
while (it != s.end() && std::isdigit(*it)) ++it;
return !s.empty() && it == s.end();
}
If The last character is number => QCompleter show me list = { "1","2","7" };
Else => list = { "AAAA","AA","BB","AC" };
Subclass your QLineEdit with 2 customs QCompleter
ExtendedLineEdit.h
class ExtendedLineEdit : public QLineEdit
{
Q_OBJECT
public:
explicit ExtendedLineEdit(QWidget *parent = nullptr);
void setWordCompleter(QCompleter* c);
void setNumberCompleter(QCompleter* c);
protected:
void keyPressEvent(QKeyEvent *e);
private slots:
void insertCompletionWord(const QString& txtComp);
void insertCompletionNumber(const QString& txtComp);
private:
QCompleter* m_completerWord;
QCompleter* m_completerNumber;
void showCustomCompleter(QCompleter* completer);
};
ExtendedLineEdit.cpp
ExtendedLineEdit::ExtendedLineEdit(QWidget *parent) :
QLineEdit(parent)
{
}
void ExtendedLineEdit::setWordCompleter(QCompleter *c)
{
m_completerWord = c;
m_completerWord->setWidget(this);
connect(m_completerWord, SIGNAL(activated(QString)),
this, SLOT(insertCompletionWord(QString)));
}
void ExtendedLineEdit::setNumberCompleter(QCompleter *c)
{
m_completerNumber = c;
m_completerNumber->setWidget(this);
connect(m_completerNumber, SIGNAL(activated(QString)),
this, SLOT(insertCompletionNumber(QString)));
}
void ExtendedLineEdit::keyPressEvent(QKeyEvent *e)
{
QLineEdit::keyPressEvent(e);
if (!m_completerWord || !m_completerNumber)
return;
QString lastCaractor = text().mid(text().length() - 1, 1);
bool okConvertion = false;
lastCaractor.toInt(&okConvertion);
if (okConvertion)
{
//show number completer
m_completerWord->popup()->hide();
m_completerNumber->setCompletionPrefix(lastCaractor);
showCustomCompleter(m_completerNumber);
}
else
{
//show word completer
m_completerNumber->popup()->hide();
m_completerWord->setCompletionPrefix(this->text());
showCustomCompleter(m_completerWord);
}
}
void ExtendedLineEdit::insertCompletionWord(const QString &txtComp)
{
setText(txtComp);
}
void ExtendedLineEdit::insertCompletionNumber(const QString &txtComp)
{
setText(text().mid(0, text().length() - 1) + txtComp);
}
void ExtendedLineEdit::showCustomCompleter(QCompleter *completer)
{
if (completer->completionPrefix().length() < 1)
{
completer->popup()->hide();
return;
}
QRect cr = cursorRect();
cr.setWidth(completer->popup()->sizeHintForColumn(0) + completer->popup()->verticalScrollBar()->sizeHint().width());
completer->complete(cr);
}
And using
QStringList list = { "AAAA","AA","BB","AC" };
m_wordCompleter = new QCompleter(list, this);
QStringList numbers = { "1","2","7", "15" };
m_numberCompleter = new QCompleter(numbers, this);
ui->lineEdit->setWordCompleter(m_wordCompleter);
ui->lineEdit->setNumberCompleter(m_numberCompleter);

What to use instead of QStringList?

I'm new to Qt, so I'm not sure what to use.
I thought I would have a QStringList to give to my QStringListModel and display it in a ListView.
Now, however, I need to divide QStringList in the values of 2 types. So, I need to have string + some typeId, not just one string, but QStringList is for one-dimensional list only.
Anyone could give an advice on what is the best way to try to implement this?
The solution is to use QAbstractListModel subclass as a Qt Quick model. An example of base class for a models (I use it for convenience):
// abstractobjectlistmodel.h
#pragma once
#include <QtCore>
struct AbstractObjectListModel
: public QAbstractListModel
{
explicit AbstractObjectListModel(QObject * const parent = Q_NULLPTR)
: QAbstractListModel{parent}
{ ; }
int rowCount(QModelIndex const & parent = {}) const Q_DECL_OVERRIDE Q_DECL_FINAL
{
Q_UNUSED(parent);
return items.count();
}
QVariant data(QModelIndex const & index, const int role = Qt::DisplayRole) const Q_DECL_OVERRIDE Q_DECL_FINAL
{
if (!index.isValid()) {
return {};
}
switch (role) {
case Qt::UserRole : {
return QVariant::fromValue(items[index.row()].data());
}
default : {
return {};
}
}
}
QHash< int, QByteArray > roleNames() const Q_DECL_OVERRIDE Q_DECL_FINAL
{
auto roleNames = QAbstractListModel::roleNames();
roleNames.insert(Qt::UserRole, "modelData");
return roleNames;
}
Q_INVOKABLE
virtual
QObject * get(int row) const
{
if (row < 0) {
return {};
}
if (row >= rowCount()) {
return {};
}
return items[row];
}
void remove(int row, int count = 1)
{
Q_ASSERT(count > 0);
Q_ASSERT(row >= 0);
Q_ASSERT(row + count <= rowCount());
beginRemoveRows({}, row, row + count - 1);
while (0 < count) {
items.takeAt(row)->deleteLater();
--count;
}
endRemoveRows();
}
void clear()
{
if (!items.isEmpty()) {
remove(0, rowCount());
}
}
protected :
~AbstractObjectListModel() Q_DECL_OVERRIDE Q_DECL_EQ_DEFAULT; // derived classes should not meant to be manipulated polymorphically
QList< QPointer< QObject > > items;
void insert(int row, QObject * const item)
{
item->setParent(this);
beginInsertRows({}, row, row);
items.insert(row, item);
endInsertRows();
}
void append(QObject * const item)
{
insert(rowCount(), item);
}
};
But one need to override get to access items' Q_PROPERTY properties (in addition to dynamic ones):
// type of element
class Project
: public QObject
{
Q_OBJECT
Q_PROPERTY(QString name MEMBER name NOTIFY nameChanged)
Q_PROPERTY(QString path MEMBER path NOTIFY pathChanged)
public :
Project(QString name, QString path,
QObject * const parent = Q_NULLPTR)
: QObject{parent}
, name{name}
, path{path}
{ ; }
Q_SIGNALS :
void nameChanged(QString name);
void pathChanged(QString path);
private :
QString name;
QString path;
};
// custom model
class ProjectsListModel
: public AbstractObjectListModel
{
Q_OBJECT
public :
explicit ProjectsListModel(QObject * const parent = Q_NULLPTR)
: AbstractObjectListModel{parent}
{ ; }
void appendProject(QString name, QString path)
{
AbstractObjectListModel::append(::new Project{name, path});
}
Q_INVOKABLE
Project *
get(int row) const Q_DECL_OVERRIDE
{
return qobject_cast< Project * >(AbstractObjectListModel::get(row));
}
};
Before use one need to register concrete model with qmlRegisterType< ProjectsListModel >();. Properties of Project class are avaliable in delegate and highlight by means of members of modelData.
Another example:
struct TimeZoneModel Q_DECL_FINAL
: public QAbstractListModel
{
Q_OBJECT
public :
explicit TimeZoneModel(QObject * const parent = Q_NULLPTR)
: QAbstractListModel{parent}
{ ; }
int rowCount(QModelIndex const & parent = {}) const Q_DECL_OVERRIDE
{
Q_UNUSED(parent);
return timeZoneIds.count();
}
QVariant data(QModelIndex const & index, const int role = Qt::DisplayRole) const Q_DECL_OVERRIDE
{
if (!index.isValid() || (role > Qt::UserRole + 4)) {
return {};
}
QTimeZone timeZone{timeZoneIds[index.row()]};
if (!timeZone.isValid()) {
return {};
}
return roleData(timeZone, role);
}
QHash< int, QByteArray > roleNames() const Q_DECL_OVERRIDE
{
auto roleNames = QAbstractListModel::roleNames();
int i = Qt::UserRole;
for (const auto role : {"modelData", "id", "comment", "name", "country"}) {
roleNames.insert(i++, role);
}
return roleNames;
}
Q_INVOKABLE
QByteArray get(int row) const
{
if (row < 0) {
return {};
}
if (row >= rowCount()) {
return {};
}
return timeZoneIds[row];
}
private :
QVariant roleData(QTimeZone const & timeZone, int role = Qt::UserRole) const
{
switch (role) {
case Qt::UserRole : {
QVariantMap modelData;
const auto names = roleNames();
while (++role < Qt::UserRole + 5) {
modelData.insert(QString::fromUtf8(names[role]), roleData(timeZone, role));
}
return modelData;
}
case Qt::UserRole + 1: {
return QString::fromUtf8(timeZone.id());
}
case Qt::UserRole + 2 : {
return timeZone.comment();
}
case Qt::UserRole + 3 : {
return timeZone.displayName(QTimeZone::StandardTime);
}
case Qt::UserRole + 4 : {
return QLocale::countryToString(timeZone.country());
}
default : {
return {};
}
}
}
const QByteArrayList timeZoneIds = QTimeZone::availableTimeZoneIds();
};
In addition to access via modelData's fields (modelData.id, modelData.comment etc) all the symbols are accessible directly (i.e. id, comment etc) in delegate and highlight contexts of the ListView.
Model TimeZoneModel is const and can be injected into global scope directly without any performance drawbacks:
QQmlApplicationEngine engine;
TimeZoneModel timeZoneModel;
Q_SET_OBJECT_NAME(timeZoneModel);
qmlRegisterType< TimeZoneModel >();
const auto rootContext = engine.rootContext();
rootContext->setContextProperty(timeZoneModel.objectName(), &timeZoneModel);
If you need dictionary that contains QString and any other type I suggest you to use
QMap<QString, YourType> myMap;
Here you have some example of usage:
QMap<int, QString> myMap;
myMap.insert(1,"A");
myMap.insert(2,"B");
myMap[3] = "C";
foreach(int i, myMap.keys()) qDebug() << myMap[i];

Auto completion based on regex

I have a QLineEdit with a QRegularExpressionValidator where the allowed input is:
^(?<sign>[<>=]|>=|<=)(?<value>\d+\.?\d*)(?<unit>[mc]{0,1}m[²2]\/s|St|cSt)$
So for example:
"<15m²/s" // good
">=3.14cSt" // good
"27mm2/s" // bad
I search a way to fill a QCompleter based on this regex.
So if the cursor is on the empty QLineEdit the completer proposes:
>, <, =, >= or <=.
After the sign, propose nothing and after the last number, propose:
mm²/s, cm²/s, m²/s, St or cSt
My need is to create a QStringList by reading the allowed sign and unit part of the regex and insert this QStringList in the QCompleter because it is based on a QAbstractItemModel.
I found a workaround by subclassing QLineEdit but it is not the best solution. If someone has better, I take.
lineeditregexgroup.h:
#ifndef LINEEDITREGEXGROUP_H
#define LINEEDITREGEXGROUP_H
#include <QLineEdit>
#include <QMap>
class QCompleter;
class QStringListModel;
class QRegularExpression;
class QRegularExpressionValidator;
class LineEditRegexGroup : public QLineEdit
{
Q_OBJECT
public:
LineEditRegexGroup(const QString pattern, QWidget *parent = Q_NULLPTR);
~LineEditRegexGroup();
static QMap<QString, QStringList> mapCompleter;
public slots:
void checkValidity(const QString &text);
protected:
virtual void mouseReleaseEvent(QMouseEvent *e);
private:
QString curGroup;
QCompleter *completer;
QStringListModel *listCompleter;
QRegularExpression *regex;
QRegularExpressionValidator *validator;
};
#endif // LINEEDITREGEXGROUP_H
lineeditregexgroup.cpp:
#include "lineeditregexgroup.h"
#include <QCompleter>
#include <QStringListModel>
#include <QRegularExpression>
#include <QRegularExpressionValidator>
#include <QAbstractItemView>
QMap<QString, QStringList> LineEditRegexGroup::mapCompleter = {
{ "sign", QStringList() << "<" << ">" << "=" << "<=" << ">=" },
{ "unit", QStringList() << "mm²/s" << "cm²/s" << "m²/s" << "St" << "cSt" }
};
LineEditRegexGroup::LineEditRegexGroup(const QString pattern, QWidget *parent)
: QLineEdit(parent)
{
completer = new QCompleter(this);
listCompleter = new QStringListModel(completer);
regex = new QRegularExpression(pattern, QRegularExpression::NoPatternOption);
validator = new QRegularExpressionValidator(*regex, this);
completer->setModel(listCompleter);
completer->setCompletionMode(QCompleter::UnfilteredPopupCompletion);
setCompleter(completer);
setValidator(validator);
curGroup = regex->namedCaptureGroups().at(1);
connect(this, SIGNAL(textEdited(QString)), this, SLOT(checkValidity(QString)));
}
LineEditRegexGroup::~LineEditRegexGroup()
{
// dtor ...
}
void LineEditRegexGroup::checkValidity(const QString &text)
{
bool valid = true;
int nbCapture = 0;
QRegularExpressionMatch match = regex->match(text);
for (int i=1; i<=regex->captureCount() && valid; i++){
/* +1 to check only groups, not the global string */
valid &= !match.captured(i).isEmpty();
if (valid)
nbCapture++;
curGroup = regex->namedCaptureGroups().at(i);
if (curGroup == "value")
curGroup = regex->namedCaptureGroups().at(i-1);
}
if (nbCapture < regex->captureCount()){
QStringList new_model = mapCompleter.value(curGroup);
if (curGroup == regex->namedCaptureGroups().at(regex->captureCount())){
new_model.replaceInStrings(QRegularExpression("^(.*)$"), text+"\\1");
}
listCompleter->setStringList(new_model);
completer->complete();
}
}
void LineEditRegexGroup::mouseReleaseEvent(QMouseEvent *e)
{
QLineEdit::mouseReleaseEvent(e);
if (text().isEmpty())
checkValidity("");
}
And call it like this:
new LineEditRegexGroup(
"^(?:(?<sign>[<>=]|>=|<=|)"
"(?:(?<value>\\d+\\.?\\d*)"
"(?:(?<unit>[mc]{0,1}m[²2]\\/s|St|cSt))?)?)?$",
parent
);
Result:

QSortFilterProxyModel not showing 2nd column in QTreeView

I have inherited a class from QSortFilterProxyModel to support filtering of a hierarchical tree in my code.
I have added code below of what I have done. After filtering is done, data in the 2nd column is NOT shown...
I am not able to understand why is that...
Can anyone help me on that?
Also, when filtering is completed, the tree is collapsed... I want to call expandAll on the tree when the filtering is completed. Is there some signal emitted or some function called where I know that the filtering is done?
Class Declaration
class MySortFilterProxyModel : public QSortFilterProxyModel
{
Q_OBJECT
public:
MySortFilterProxyModel(QObject *parent = 0);
protected:
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
bool ShowThis(const QModelIndex index) const;
private:
};
USAGE:
_proxyModel = new MySortFilterProxyModel(this);
_proxyModel->setFilterKeyColumn(-1);
_proxyModel->setSourceModel(_directiveTreeModel);
DEFINITION:
bool MySortFilterProxyModel::filterAcceptsRow(int sourceRow,
const QModelIndex &sourceParent) const
{
QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
return ShowThis(index);
}
bool MySortFilterProxyModel::ShowThis(const QModelIndex index) const
{
bool retVal = false;
//Gives you the info for number of childs with a parent
if ( sourceModel()->rowCount(index) > 0 )
{
for( int nChild = 0; nChild < sourceModel()->rowCount(index); nChild++)
{
QModelIndex childIndex = sourceModel()->index(nChild,0,index);
if ( ! childIndex.isValid() )
break;
retVal = ShowThis(childIndex);
if (retVal)
{
break;
}
}
}
else
{
QModelIndex useIndex0 = sourceModel()->index(index.row(), 0, index.parent());
QString name = sourceModel()->data(useIndex0, Qt::DisplayRole).toString();
QModelIndex useIndex1 = sourceModel()->index(index.row(), 1, index.parent());
QString value = sourceModel()->data(useIndex1, Qt::DisplayRole).toString();
std::cout << "name : " << name.toStdString() << ", value : " << value.toStdString() << "\n";// , filterRegExp : " << filterRegExp() << "\n";
if ( (name.contains(filterRegExp()) || value.contains(filterRegExp())) )
{
retVal = true;
}
else
retVal = false;
}`enter code here`
return retVal;
}
OUTPUT : (Data in the 2nd column is missing)
I figured out the issue...
I was using QStyledItemDelegate and I had derived a class from it and overridden the paint function.
In the pain function, I was referring to my original model .. But, in case of filtering, that model is NULL and I should have used the proxy model that I had created.

How do I know the values on Qt property browser changed?

I'm using a Qt property browser widget. I'm creating all the values of the property grid automatically using the moc but I didn't find how to make the values entered in the property grid be set automatically in my class instance? is there any sginal where I can know that?
I creating the property grid like this:
QWidget *w = new QWidget();
Foo *o = new Foo();
QtBoolPropertyManager *boolManager = new QtBoolPropertyManager(w);
QtIntPropertyManager *intManager = new QtIntPropertyManager(w);
QtStringPropertyManager *stringManager = new QtStringPropertyManager(w);
QtGroupPropertyManager *groupManager = new QtGroupPropertyManager(w);
const QMetaObject *meta = o->metaObject();
const QString className = meta->className();
QMap<QString, PropManager*> dic;
QtProperty *root = groupManager->addProperty(className);
for(int i = meta->propertyOffset(); i < meta->propertyCount(); ++i)
{
QMetaProperty metaProp = meta->property(i);
const QString name = metaProp.name();
QVariant value = metaProp.read(o);
QVariant::Type t = metaProp.type();
QtProperty *prop = NULL;
PropManager *propMan = NULL;
switch(t)
{
case QVariant::Int:
{
prop = intManager->addProperty(name);
root->addSubProperty(prop);
intManager->setValue(prop, value.toInt());
propMan = new PropManager(prop, intManager, t);
break;
}
case QVariant::String:
{
prop = stringManager->addProperty(name);
root->addSubProperty(prop);
stringManager->setValue(prop, value.toString());
propMan = new PropManager(prop, stringManager, t);
break;
}
default:
throw std::invalid_argument("unknow type");
}
if(prop != NULL)
dic.insert(name, propMan);
}
QtCheckBoxFactory *checkBoxFactory = new QtCheckBoxFactory(w);
QtSpinBoxFactory *spinBoxFactory = new QtSpinBoxFactory(w);
QtLineEditFactory *lineEditFactory = new QtLineEditFactory(w);
QtAbstractPropertyBrowser *editor = new QtTreePropertyBrowser();
editor->setFactoryForManager(boolManager, checkBoxFactory);
editor->setFactoryForManager(intManager, spinBoxFactory);
editor->setFactoryForManager(stringManager, lineEditFactory);
editor->addProperty(root);
QGridLayout *layout = new QGridLayout(w);
layout->addWidget(editor, 1, 0);
w->show();
Foo.h is defined like this:
class Foo : public QObject
{
Q_OBJECT
public:
explicit Foo() { }
~Foo() { }
Q_PROPERTY(QString name READ getA WRITE setA)
Q_PROPERTY(int age READ getNum WRITE setNum)
QString name;
int age;
QString getA() const { return name; }
int getNum() const { return age; }
void setA(QString a) { this->name = a; }
void setNum(int n) { this->age = n; }
};
Partial solution:
I found propertyChanged() from QtAbstractPropertyManager but this does raise every time a single character is edited. I'd like to have an slot where this is fired when the user is done with the editing.