I created a QML object in C++. In my main method, I can set various properties that I have defined in my custom QML object. When set from the main method, the various properties are displayed as expected. When I set properties from within my update method, the display never updates. I have verified that the associated methods within my custom QML object are receiving the values that I am passing to it. Why wouldn't my display be updating?
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include "horizontalBarGraph.h"
#include "speedometer.h"
#include "test.h"
#include <QTimer>
#include <QDebug>
//QObject *item = NULL;
static HorizontalBarGraph *ptrOilTemp = nullptr;
static int value = 0;
int update()
{
//qInfo() << "update() called.";
if(value > ptrOilTemp->getMaxValue())
{
value = 0;
}
ptrOilTemp->setActualValue(value);
qInfo() << "value = " << value;
value++;
//ptrOilTemp->setUnits("Test");
return 0;
}
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
qmlRegisterType<Speedometer>("com.ulasdikme.speedometer",1,0,"Speedometer");
qmlRegisterType<HorizontalBarGraph>("com.kubie.horizontalBarGraph", 1, 0, "HorizontalBarGraph");
qmlRegisterType<Test>("com.kubie.test", 1, 0, "Test");
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
//item = engine.rootObjects().at(0)->findChild<QQuickItem*>("testing");
QObject *object = engine.rootObjects()[0];
QObject *oilTemp = object->findChild<QObject*>("oilTemp");
QObject *oilPressure = object->findChild<QObject*>("oilPressure");
QObject *coolantTemp = object->findChild<QObject*>("coolantTemp");
QObject *coolantPressure = object->findChild<QObject*>("coolantPressure");
QObject *intakeAirTemp = object->findChild<QObject*>("intakeAirTemp");
QObject *engineRPM = object->findChild<QObject*>("engineRPM");
//HorizontalBarGraph *ptrOilTemp = qobject_cast<HorizontalBarGraph*>(oilTemp);
ptrOilTemp = qobject_cast<HorizontalBarGraph*>(oilTemp);
HorizontalBarGraph *ptrOilPressure = qobject_cast<HorizontalBarGraph*>(oilPressure);
HorizontalBarGraph *ptrCoolantTemp = qobject_cast<HorizontalBarGraph*>(coolantTemp);
HorizontalBarGraph *ptrCoolantPressure = qobject_cast<HorizontalBarGraph*>(coolantPressure);
HorizontalBarGraph *ptrIntakeAirTemp = qobject_cast<HorizontalBarGraph*>(intakeAirTemp);
HorizontalBarGraph *ptrEngineRPM = qobject_cast<HorizontalBarGraph*>(engineRPM);
qreal val1 = 0;
//qreal val2 = 25;
qreal val3 = 100;
QString degF(QChar(0x00b0));
degF += "F";
ptrOilTemp->setSensorName("Oil Temp");
ptrOilTemp->setUnits(degF);
ptrOilTemp->setMinValue(val1);
ptrOilTemp->setMaxValue(val3);
//ptrOilTemp->setActualValue(val2);
ptrOilPressure->setSensorName("Oil Press");
ptrOilPressure->setUnits("PSI");
ptrCoolantTemp->setSensorName("Coolant Temp");
ptrCoolantTemp->setUnits(degF);
ptrCoolantPressure->setSensorName("Coolant Press");
ptrCoolantPressure->setUnits("PSI");
ptrIntakeAirTemp->setSensorName("Intake Air Temp");
ptrIntakeAirTemp->setUnits(degF);
ptrEngineRPM->setSensorName("");
ptrEngineRPM->setUnits("RPM");
qInfo() << "Initializing timer.";
QTimer timer;// = new QTimer(this);
QObject::connect(&timer, &QTimer::timeout, update);
timer.start(100);
return app.exec();
}
horizontalBarGraph.cpp
#include <QPainter>
#include "horizontalBarGraph.h"
HorizontalBarGraph::HorizontalBarGraph(QQuickItem *parent)
:QQuickPaintedItem(parent),
_horizontalBarGraphWidth(260),
_horizontalBarGraphHeight(75),
_minValue(0),
_maxValue(0),
_actualValue(0),
_sensorName("Sensor Name"),
_units("Units")
{
}
void HorizontalBarGraph::paint(QPainter *painter)
{
QRectF rect = this->boundingRect();
painter->setRenderHint(QPainter::Antialiasing);
QPen pen = painter->pen();
pen.setCapStyle(Qt::FlatCap);
QFont bottomFont("Arial", 14, QFont::Bold);
QFont topFont("Arial", 16, QFont::Bold);
QColor gray1(225, 225, 225);
QColor gray2(200, 200, 200);
QColor gray3(175, 175, 175);
QColor gray4(100, 100, 100);
//minValue, actualValue, maxValue
painter->save();
painter->setFont(bottomFont);
pen.setColor(gray1);
painter->setPen(pen);
painter->drawText(rect.adjusted(0, 50, -210, 0), Qt::AlignHCenter | Qt::AlignBottom, QString::number((_minValue), 'f', 0)); //Draws minValue
painter->drawText(rect.adjusted(210, 50, 0, 0), Qt::AlignHCenter | Qt::AlignBottom, QString::number((_maxValue), 'f', 0)); //Draws maxValue
painter->drawText(rect.adjusted(0, 50, 0, 0), Qt::AlignHCenter | Qt::AlignBottom, QString::number((_actualValue), 'f', 1));
//pen.setStyle(Qt::DotLine); //Next 3 lines were used to show the bounding rectangle for a drawText object
//painter->setPen(pen);
//painter->drawRect(rect.adjusted(0, 50, -150, 0));
painter->restore();
//Bar chart background
painter->save();
painter->fillRect(rect.adjusted(25, 35, -25, -25), gray1);
painter->restore();
//Lo
painter->save();
painter->fillRect(rect.adjusted(25, 35, -185, -25), gray2);
painter->restore();
//LoLo
painter->save();
painter->fillRect(rect.adjusted(25, 35, -210, -25), gray3);
painter->restore();
//Hi
painter->save();
painter->fillRect(rect.adjusted(185, 35, -25, -25), gray2);
painter->restore();
//HiHi
painter->save();
painter->fillRect(rect.adjusted(210, 35, -25, -25), gray3);
painter->restore();
//Sensor name, Units
painter->save();
painter->setFont(topFont);
pen.setColor(gray1);
painter->setPen(pen);
painter->drawText(rect.adjusted(25, 0, -50, -40), Qt::AlignLeft | Qt::AlignTop, _sensorName); //Draws sensor name
painter->drawText(rect.adjusted(50, 0, -25, -40), Qt::AlignRight | Qt::AlignTop, _units); //Draws units
painter->restore();
//Arrow
// painter->save();
// static const QPointF points[3] = {
// QPointF(17.5, 27.5),
// QPointF(32.5, 27.5),
// QPointF(25.0, 42.5)
// };
// painter->drawPolygon(points, 3);
// painter->restore();
painter->save();
QPainterPath path;
qreal x = scale(_actualValue, _minValue, _maxValue, 25, 235);
//path.moveTo(17.5, 27.5);
//path.lineTo(32.5, 27.5);
//path.lineTo(25.0, 42.5);
path.moveTo(x - 7.5, 27.5);
path.lineTo(x + 7.5, 27.5);
path.lineTo(x, 42.5);
path.closeSubpath();
painter->fillPath(path, gray4);
painter->restore();
}
qreal HorizontalBarGraph::getHorizontalBarGraphWidth()
{
return _horizontalBarGraphWidth;
}
qreal HorizontalBarGraph::getHorizontalBarGraphHeight()
{
return _horizontalBarGraphHeight;
}
qreal HorizontalBarGraph::getMinValue()
{
return _minValue;
}
qreal HorizontalBarGraph::getMaxValue()
{
return _maxValue;
}
qreal HorizontalBarGraph::getActualValue()
{
return _actualValue;
}
QString HorizontalBarGraph::getSensorName()
{
return _sensorName;
}
QString HorizontalBarGraph::getUnits()
{
return _units;
}
void HorizontalBarGraph::setHorizontalBarGraphWidth(qreal width)
{
if(_horizontalBarGraphWidth == width)
return;
_horizontalBarGraphWidth = width;
emit widthChanged();
}
void HorizontalBarGraph::setHorizontalBarGraphHeight(qreal height)
{
if(_horizontalBarGraphHeight == height)
return;
_horizontalBarGraphHeight = height;
emit heightChanged();
}
void HorizontalBarGraph::setMinValue(qreal minValue)
{
if(_minValue == minValue)
return;
_minValue = minValue;
emit minValueChanged();
}
void HorizontalBarGraph::setMaxValue(qreal maxValue)
{
if(_maxValue == maxValue)
return;
_maxValue = maxValue;
emit maxValueChanged();
}
void HorizontalBarGraph::setActualValue(qreal actualValue)
{
if(_actualValue == actualValue)
return;
_actualValue = actualValue;
emit actualValueChanged();
}
void HorizontalBarGraph::setSensorName(QString sensorName)
{
if(_sensorName == sensorName)
return;
_sensorName = sensorName;
emit sensorNameChanged();
}
void HorizontalBarGraph::setUnits(QString units)
{
if(_units == units)
return;
_units = units;
emit unitsChanged();
}
qreal HorizontalBarGraph::scale(qreal input, qreal inputMin, qreal inputMax, qreal outputMin, qreal outputMax)
{
qreal output = (outputMax - outputMin) * (input - inputMin) / (inputMax - inputMin) + outputMin;
if(output > outputMax)
output = outputMax;
if(output < outputMin)
output = outputMin;
return output;
}
horizontalBarGraph.h
#ifndef HORIZONTALBARGRAPH_H
#define HORIZONTALBARGRAPH_H
#include <QObject>
#include <QQuickPaintedItem>
class HorizontalBarGraph : public QQuickPaintedItem
{
Q_OBJECT
Q_PROPERTY(qreal horizontalBarGraphWidth READ getHorizontalBarGraphWidth WRITE setHorizontalBarGraphWidth NOTIFY horizontalBarGraphWidthChanged)
Q_PROPERTY(qreal horizontalBarGraphHeight READ getHorizontalBarGraphHeight WRITE setHorizontalBarGraphHeight NOTIFY horizontalBarGraphHeightChanged)
Q_PROPERTY(qreal minValue READ getMinValue WRITE setMinValue NOTIFY minValueChanged)
Q_PROPERTY(qreal maxValue READ getMaxValue WRITE setMaxValue NOTIFY maxValueChanged)
Q_PROPERTY(qreal actualValue READ getActualValue WRITE setActualValue NOTIFY actualValueChanged)
Q_PROPERTY(QString sensorName READ getSensorName WRITE setSensorName NOTIFY sensorNameChanged)
Q_PROPERTY(QString units READ getUnits WRITE setUnits NOTIFY unitsChanged)
public:
HorizontalBarGraph(QQuickItem *parent = 0);
virtual void paint(QPainter *painter);
qreal getHorizontalBarGraphWidth();
qreal getHorizontalBarGraphHeight();
qreal getMinValue();
qreal getMaxValue();
qreal getActualValue();
QString getSensorName();
QString getUnits();
void setHorizontalBarGraphWidth(qreal width);
void setHorizontalBarGraphHeight(qreal height);
void setMinValue(qreal minValue);
void setMaxValue(qreal maxValue);
void setActualValue(qreal actualValue);
void setSensorName(QString sensorName);
void setUnits(QString units);
signals:
void horizontalBarGraphWidthChanged();
void horizontalBarGraphHeightChanged();
void minValueChanged();
void maxValueChanged();
void actualValueChanged();
void sensorNameChanged();
void unitsChanged();
private:
qreal _horizontalBarGraphWidth;
qreal _horizontalBarGraphHeight;
qreal _minValue;
qreal _maxValue;
qreal _actualValue;
QString _sensorName;
QString _units;
qreal scale(qreal input, qreal inputMin, qreal inputMax, qreal outputMin, qreal outputMax);
};
#endif // HORIZONTALBARGRAPH_H
main.qml
import QtQuick 2.11
import QtQuick.Window 2.11
import com.kubie.horizontalBarGraph 1.0
Window {
id: window
visible: true
width: 800
height: 480
title: qsTr("REDNEKSLDHLR")
color: "black"
// Rectangle
// {
// width: 260
// height: 75
// color: "#7a0505"
// anchors.bottom: parent.bottom
// anchors.bottomMargin: 0
// anchors.left: parent.left
// anchors.leftMargin: 0
// }
HorizontalBarGraph {
objectName: "oilTemp"
anchors.left: parent.left
anchors.leftMargin: 0
anchors.bottom: parent.bottom
anchors.bottomMargin: 0
width: horizontalBarGraphWidth
height: horizontalBarGraphHeight
}
HorizontalBarGraph {
objectName: "oilPressure"
anchors.left: parent.left
anchors.leftMargin: 0
anchors.bottom: parent.bottom
anchors.bottomMargin: 75
width: horizontalBarGraphWidth
height: horizontalBarGraphHeight
}
HorizontalBarGraph {
objectName: "coolantTemp"
anchors.right: parent.right
anchors.rightMargin: 0
anchors.bottom: parent.bottom
anchors.bottomMargin: 0
width: horizontalBarGraphWidth
height: horizontalBarGraphHeight
}
HorizontalBarGraph {
objectName: "coolantPressure"
anchors.right: parent.right
anchors.rightMargin: 0
anchors.bottom: parent.bottom
anchors.bottomMargin: 75
width: horizontalBarGraphWidth
height: horizontalBarGraphHeight
}
HorizontalBarGraph {
objectName: "intakeAirTemp"
anchors.left: parent.left
anchors.leftMargin: parent.width / 2 - width / 2;
anchors.bottom: parent.bottom
anchors.bottomMargin: 0
width: horizontalBarGraphWidth
height: horizontalBarGraphHeight
}
HorizontalBarGraph {
objectName: "engineRPM"
anchors.left: parent.left
anchors.leftMargin: parent.width / 2 - width / 2;
anchors.bottom: parent.bottom
anchors.bottomMargin: 75
width: horizontalBarGraphWidth
height: horizontalBarGraphHeight
}
}
You have to use the update() method so that the GUI is repainted, so you must invoke it every time a property that is used to do the painting is modified. By example:
void HorizontalBarGraph::setActualValue(qreal actualValue) {
if(_actualValue == actualValue)
return;
_actualValue = actualValue;
update();
emit actualValueChanged();
}
I came across QFontMetrics?
http://doc.qt.io/qt-5/qfontmetrics.html
This gives the height and width of the present font.
I need to run my application with full screen mode on on different monitors for which I am using Scale class. http://doc.qt.io/qt-5/qml-qtquick-scale.html
That returns the height and width of the current screen.
Is there a way to use QFontMetrics or anything else to change the font size according to the monitor size?
ApplicationWindow
{
id: head
visible: true
width: Screen.width
height: Screen.height
title: "Novus Pilot"
property var id: 0;
Draw_on_qimage
{
id: draw_on_qimage
anchors.fill: parent
parent: image
scaleX: head.width / 640
scaleY: head.height / 480
}
}
Draw_on_qimage is a cpp class.
The easiest way is to set QFont as Q_PROPERTY of your item so you can set it from QML:
#ifndef DRAWITEM_H
#define DRAWITEM_H
#include <QPainter>
#include <QQuickPaintedItem>
class DrawItem : public QQuickPaintedItem
{
Q_OBJECT
Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY fontChanged)
public:
DrawItem(QQuickItem *parent = Q_NULLPTR):QQuickPaintedItem(parent){}
void paint(QPainter *painter){
painter->setFont(mFont);
painter->drawText(boundingRect(), "Hello");
}
QFont font() const{
return mFont;
}
void setFont(const QFont &font){
if(mFont == font)
return;
mFont = font;
emit fontChanged();
update();
}
signals:
void fontChanged();
private:
QFont mFont;
};
#endif // DRAWITEM_H
To set its size we use the pointSize property of QFont:
DrawItem
{
id: draw_on_qimage
anchors.fill: parent
font.pointSize: some_function(head.width, head.height)
transform: Scale {
xScale: head.width / 640
yScale: head.height / 480
}
}
Where some_function is the function that establishes the relationship between the font size and the size of the window.
I've got class that inherits from QQuickItem and inside I'm operating on its width height properties. I'm also exposing my own properties.
class MyQQuickItem : public QQuickItem
{
Q_OBJECT
Q_PROPERTY(QUrl source MEMBER m_source NOTIFY sourceChanged)
public:
explicit MyQQuickItem(QQuickItem *a_parent = Q_NULLPTR);
~PDFPage();
signals:
void sourceChanged(const QUrl a_source);
private:
QUrl m_source;
};
In qml:
...
MyQQuickItem
{
width: parent.width / 2
height: parent.height
source: "someSource"
Component.onCompleted
{
console.log("component onCompleted");
}
}
When sourceChanged is emmited I'm working on width height properties, but with the first emit they are not initialized yet, and Component.onCompleted is called after my NOTIFY signal.
I can check if component is ready before getting width and height by calling isComponentComplete and execute my code when it is, but I can't find out when it happens and the initial value of source is skipped when it is not.
Of course I could create slot 'itemReady' and call it from Component.onCompleted, but I have many QMLs using my class and I will create more in the future, so I don't want to make copy-paste job.
I also do not want to set the source in Component.onCompleted.
Connecting to widthChanged, and heightChanged signals isn't also good idea, because I'm resizing my item very frequently, and I don't want to execute my code then.
Is there any way to get completed signal from C++?
EDIT:
I did as #Mitch said - overriten componentComplete method and inside, called it's base class equavilent. isComponentComplete() returns true, but I'm still getting 0 from width() and height() methods:
void MyQQuickItem::componentComplete()
{
QQuickItem::componentComplete();
if(isComponentComplete())
{
qDebug() << "c++: oncompleted, width,height: " << width() << height(); //gives 0,0
}
}
Actually I figured out that Component.onCompleted in QML prints 0's too:
...
MyQQuickItem
{
width: parent.width / 2
height: parent.height
source: "someSource"
Component.onCompleted
{
console.log("component onCompleted width, height: ", width, height); //it gives 0 too
}
}
#derM Component.onCompleted is not emmited by QQuickItem::componentComplete() directly, because it prints its log after the qDebug in c++ above.
So, although it is ready, properties are not initialized.
EDIT2:
Finally I've solved it. The Window was guilty, because it uses contentItem as the parent of his childrens, and in MyQQuickItem Component.onCompleted width and height of contentItem(his parent) are 0.
When I do so:
Window
{
id: wnd
width: 640
height: 480
Component.onCompleted:
{
console.log("Window completed: ", this, width, height);
console.log("windowContentItem: ", contentItem, width, height);
}
MyQQuickItem
{
width: parent.width
height: parent.height
Component.onCompleted:
{
console.log("MyQQuickItem completed: ", this, width, height);
console.log("MyQQuickItem parent: ", parent, parent.width, parent.height);
}
}
}
It prints:
qml: Window completed: QQuickWindowQmlImpl(0x345b5eb4d0) 640 480
qml: windowContentItem: QQuickRootItem(0x345e2cdec0) 640 480
qml: MyQQuickItem completed: MyQQuickItem(0x345b5b99e0) 0 0
qml: MyQQuickItem parent: QQuickRootItem(0x345e2cdec0) 0 0
So MyQQuickItem parent is Window's contentItem. When I replace
width: parent.width
height: parent.height
to:
width: wnd.width
height: wnd.height
It works perfectly, and in my void MyQQuickItem::componentComplete() I've got width and height initialized as expected.
One thing that I do not understand is why in Window onCompleted, contentItem size is correct, but in MyQQuickItem onCompleted the size is 0,0. If anyone could explain it to me, I would be grateful :P
Qt code uses componentComplete() like so:
void QQuickControl::componentComplete()
{
Q_D(QQuickControl);
QQuickItem::componentComplete();
d->resizeContent();
// ...
}
You can do something similar, replacing resizeContent() with your function that works on the width and height. Assuming that function is also called whenever source changes, you'd need the isComponentComplete() check. With this approach, you shouldn't have any issues.
You can inherit QQmlParserStatus and implement componentComplete().
class MyQQuickItem : public QQuickItem, public QQmlParserStatus
{
Q_OBJECT
Q_PROPERTY(QUrl source MEMBER m_source NOTIFY sourceChanged)
public:
explicit MyQQuickItem(QQuickItem *a_parent = Q_NULLPTR);
~PDFPage();
void classBegin();
void componentComplete();
signals:
void sourceChanged(const QUrl a_source);
private:
QUrl m_source;
};
componentComplete() will be called automatically by the QML-engine.
I have a problem with QQuickView instantiating components from C++... Here is my code:
Class definition (vviewerqml.h):
class VViewerQml : public QObject
{
Q_OBJECT
public:
explicit VViewerQml(QSettings &systemSettings, QObject *parent = 0);
~VViewerQml();
protected slots:
void onViewStatusChanged(QQuickView::Status status);
protected:
QString _qmlFolder;
QQuickView _view;
};
Class implementation (vviewerqml.cpp):
#include "vviewerqml.h"
VViewerQml::VViewerQml(QSettings &systemSettings, QObject *parent) :
QObject(parent)
{
// Initialize viewer reading from settings file
_qmlFolder = "/my/path/to/qml/files";
// Initialize the source
connect(&_view, SIGNAL(statusChanged(QQuickView::Status)),
this, SLOT(onViewStatusChanged(QQuickView::Status)));
_view.setSource(QUrl::fromLocalFile(QDir(_qmlFolder).filePath("Main.qml")));
// Show the viewer
_view.show();
}
VViewerQml::~VViewerQml()
{
// Close the viewer
_view.close();
}
void VViewerQml::onViewStatusChanged(QQuickView::Status status)
{
if(status == QQuickView::Ready)
{
QQmlComponent *c =
new QQmlComponent(_view.engine(),
QDir(_qmlFolder).filePath("TextLegacy.qml"));
QQuickItem *i = qobject_cast<QQuickItem*>(c->create());
QQmlEngine::setObjectOwnership(i, QQmlEngine::CppOwnership);
i->setParent(_view.rootObject());
i->setVisible(true);
}
}
Here is my Main.qml:
import QtQuick 2.0
Rectangle {
width: 1024
height: 768
color: "#000000"
Text {
x: 0
y: 0
color: "#ffffff"
text: "Main page"
}
}
And here is my TextLegacy.qml:
import QtQuick 2.0
Item {
Rectangle {
x: 0
y: 0
width: 100
height: 50
color: "#ff0000"
}
}
My code works fine until the load of Main.qml: the QML viewer opens on the screen and I can read the text "Main page" (white on black) on my screen... But unluckily I am not able to load the TextLegacy.qml... if I put a breakpoint in onViewStatusChanged function, the execution reaches that point... no visible errors are shown in the debug console... but I am not able to see on the screen the red rectangle provided by TextLegacy.qml...
What am I missing? Can somebody give some help?
Ok, I found the solution on my own: I have confused setParent with setParentItem... The correct code is:
void VViewerQml::onViewStatusChanged(QQuickView::Status status)
{
if(status == QQuickView::Ready)
{
QQmlComponent *c = new QQmlComponent(_view.engine(),
QUrl::fromLocalFile(QDir(_qmlFolder).filePath("TextLegacy.qml")));
QQuickItem *i = qobject_cast<QQuickItem*>(c->create());
QQmlEngine::setObjectOwnership(i, QQmlEngine::CppOwnership);
i->setParent(this);
i->setVisible(true);
i->setParentItem(_view.rootObject());
}
}
Actually i->setParent(this); defines the parent of i as a QObject (for deleting purposes, for example) while i->setParentItem(_view.rootObject()); actually adds the object to the scene, as a child of the scene root object.
I'm using a QML ListView with a SectionScroller & QAbstractListModel. I noticed that I get a segmentation fault in memcpy (never called explicitly) when I'm normally scrolling (without usage of SectionScroller)
Do you have any idea why it's happening?
I tried to reproduce it, and now the segmentation fault is
0x402f9c3a in ?? () from /usr/lib/libQtScript.so.4
0x402f9c3a: ldrh r1, [r7, r3]
The debug symbols are there, though no valuable info is dumped. The other time the Segfault was
0x0000cab8 in QBasicAtomicInt::ref (this=0x0)
at /usr/include/QtCore/qatomic_armv6.h: 119
It's strange since AFAIK N900's processor is armv7 /edit: on N950 it uses the same and in Qt sources are only for ARM qatomic_arm.h and qatomic_armv6.h so it should be ok.
ListView{
id: irrview
width: parent.width
model: irregulars
anchors.top: caption.bottom
anchors.bottom: parent.bottom
spacing: 5
clip: true
section.criteria: ViewSection.FirstCharacter
section.property: "form0"
delegate: Rectangle{
id: del
property int fontSize: 20
height: 60
width: parent.width
color: "#E0E1E2"
Row{
height: parent.height
width: parent.width - 10
anchors.horizontalCenter: parent.horizontalCenter
property real columnWidth: (width - 10) / 3
property int rad: 10
spacing: 5
Rectangle{
height: parent.height
width: parent.columnWidth
radius: parent.rad
color: "lightsteelblue"
Text{
anchors.centerIn: parent
text: form0
font.pointSize: del.fontSize
}
}
Rectangle{
height: parent.height
width: parent.columnWidth
radius: parent.rad
color: "lightsteelblue"
Text{
anchors.centerIn: parent
text: form1
font.pointSize: del.fontSize
}
}
Rectangle{
height: parent.height
width: parent.columnWidth
radius: parent.rad
color: "lightsteelblue"
Text{
anchors.centerIn: parent
text: form2
font.pointSize: del.fontSize
}
}
}
}
}
The model is:
#ifndef IRREGULARLISTWRAPPER_H
#define IRREGULARLISTWRAPPER_H
#include <QObject>
#include <QList>
#include <QAbstractListModel>
#include <QMap>
#include "IrregularVerb.h"
#include "AbstractIrregularList.h"
class IrregularListWrapper : public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(QString langName READ getLangName NOTIFY langChanged)
Q_PROPERTY(int count READ rowCount NOTIFY langChanged)
Q_ENUMS(Language)
public:
Q_INVOKABLE int rowCount(const QModelIndex& = QModelIndex()) const { return db->count(); }
Q_INVOKABLE QObject* get(int index) const {return db->at(index);}
QVariant data(const QModelIndex &index, int role) const;
enum Language
{
English = 0,
German = 1
};
enum IrregularVerbRoles
{
Form0Role = Qt::UserRole + 1,
Form1Role,
Form2Role
};
IrregularListWrapper();
// ~IrregularListWrapper() { delete db; }
// QList<QObject*> getdb() const { return *db; }
QString getLangName() const { return langName; }
Q_INVOKABLE void changeLang(Language l) { beginResetModel(); db = 0; /*QList<IrregularVerb*>();*/ setLang(l); endResetModel(); }
static QMap<Language, QString> plugins;
signals:
void langChanged();
protected:
void setLang(Language);
//QList<IrregularVerb*> db;
QString langName;
AbstractIrregularList * db;
};
#endif // IRREGULARLISTWRAPPER_H
QMap<IrregularListWrapper::Language, QString> IrregularListWrapper::plugins;
IrregularListWrapper::IrregularListWrapper()
{
QHash<int, QByteArray> roles;
roles[Form0Role] = "form0";
roles[Form1Role] = "form1";
roles[Form2Role] = "form2";
const QString pluginPath = "/opt/MeeIrregulars/share/lib%1.so";
plugins[English] = pluginPath.arg("english");
plugins[German] = pluginPath.arg("german");
setRoleNames(roles);
setLang(German);
}
QVariant IrregularListWrapper::data(const QModelIndex &index, int role) const
{
if (!index.isValid()) return QVariant();
const IrregularVerb* verb = db->at(index.row());
switch (role)
{
case Form0Role:
return verb->getForm0();
break;
case Form1Role:
return verb->getForm1();
break;
case Form2Role:
return verb->getForm2();
break;
}
return QVariant();
}
void IrregularListWrapper::setLang(Language l)
{
QPluginLoader loader(plugins[l]);
db = qobject_cast<AbstractIrregularList*>(loader.instance());
if (db == 0) db = new AbstractIrregularList;
switch (l)
{
case English:
langName = "English";
break;
case German:
langName = "German";
break;
}
emit langChanged();
}
class IrregularVerb : public QObject
{
Q_OBJECT
Q_PROPERTY(QString form0 READ getForm0 NOTIFY formChanged)
Q_PROPERTY(QString form1 READ getForm1 NOTIFY formChanged)
Q_PROPERTY(QString form2 READ getForm2 NOTIFY formChanged)
public:
QString forms[3];
QString getForm0() const { return forms[0]; }
QString getForm1() const { return forms[1]; }
QString getForm2() const { return forms[2]; }
IrregularVerb(QString a, QString b, QString c) { forms[0] = a; forms[1] = b; forms[2] = c; }
signals:
void formChanged();
};
Backtrace:
#0 QBasicAtomicInt::ref (this=0x18)
#1 QString (this=0xbe88d2a0, other=...)
#2 IrregularVerb::getForm2 (this=0x9e6de8)
#3 IrregularVerbWrapper::data(this=0x9e31b8, index=..., role=35) // the model// some calls to libQtDeclarative
Thanks.
It was a problem with ownership. The elements returned by get were owned by JS and automatically destroyed. See this answer for more information.