Trying to implement an ObjectPool design pattern with a TabBarLayout
-
wrote on 27 Mar 2012, 17:05 last edited by
I have (one part) of my calculator object working fine as a single instance. My next step is to use a TabBarLayout to quickly compare different sets of equation values; 5 in my case.
My approach is to create an object pool class with an array of 5 pointers to previously instantiated calcXY objects. As the user swipes left-to-right or selects a TabButton, I would like the displayed QML to get its values from the appropriate calcXY object, the currXYObject being set by a call to the calcXYPool object. Since the public slots are in the individual calcXY objects, both the pool and calculator class are defined as subclasses of QObject:
@
class CalcXY : public QObject
{
Q_OBJECT
...
@I first tried to use the late instantiation "singleton":http://stackoverflow.com/questions/1008019/c-singleton-design-pattern#1008289 pattern. But that give me a slew of compile errors which I wasn't able to resolve. So I reverted back to the simpler template of a Q_OBJECT class, since the class instance is controlled by the following in any case. I'll leave the singleton implementation until later:
@
viewer.rootContext()->setContextProperty("calcXYPoolObject", &calcXYPool);
@So then the TabButton event call would be something like this:
@
TabButton { tab: aModel; text: "A"; onClicked: calcXYPoolObject.setCurrCalcXY(0) }
TabButton { tab: bModel; text: "B"; onClicked: calcXYPoolObject.setCurrCalcXY(1) }
...
@The CalcXYPool class is quite simple:
@
CalcXYPool::CalcXYPool(QObject *parent) :
QObject(parent)
{
int i;// Set up instances of CalcXY. for (i=0; i<NUMCALCS; i++) { calcXYs[i] = new CalcXY((QObject *)0); // I don't know if this is correct. I was trying to cast the parent as per the declaration is the .h file }
}
void CalcXYPool::setCurrCalcXY(int calcIndex) {
currCalcXY = calcXYs[calcIndex];
}CalcXY CalcXYPool::getCurrCalcXY(void) {
return currCalcXY;
}
@However, I continue to get errors that I am not able to understand:
@
error: no match for 'operator=' in '((CalcXYPool*)this)->CalcXYPool::calcXYs[i] = (operator new(36u), (<statement>, ((CalcXYPool*)<anonymous>)))'
@and the following:
@
error: 'QObject::QObject(const QObject&)' is private
error: within this context
In member function 'CalcXY CalcXYPool::getCurrCalcXY()':
@Any help that could be provided would be much appreciated. Or if there is a better way of doing what I want to do, I would be grateful for some pointers.
advTHANKSance.
-
wrote on 27 Mar 2012, 17:18 last edited by
Why are you not using QList<CalcXY*> instead ?
Do the calcXY constructor like this :@class CalcXY : public QObject
{
Q_OBJECT
public:
CalcXY(QObject * parent = 0);}@
And then :
@
for (i=0; i<NUMCALCS; i++) {
calcXYList.append(new CalcXY);
}
@ -
wrote on 27 Mar 2012, 17:43 last edited by
I attempted to do what you suggested, although initially I had:
@
public:
explicit CalcXY(QObject *parent = 0);
@When I use void in the constructor, I get:
@
error: return type specification for constructor invalid
@That aside, when I use the QList approach, I get the following error:
@
error: no matching function for call to 'QList<CalcXY>::append(CalcXY*)'
@in response to the line:
@
calcXYList.append(new CalcXY);
@My CalcXYPool has the following:
@
class ScreenRatioCalcPool : public QObject
{
Q_OBJECTprivate: QList<CalcXY> calcXYList; CalcXY currCalcXY;
@
I must be missing something obvious?
-
wrote on 27 Mar 2012, 18:05 last edited by
The error message
@
error: no matching function for call to 'QList<CalcXY>::append(CalcXY*)'
@
tells all.Your QList is a list of CalcXY objects. Trying to append "new CalcXY()" is trying to append a pointer to CalcXY (thus the CalcXY*).
If you look at dridk's example, you'll see that he has a QList<CalcXY*> which is a list of CalcXY pointers, which is what you need if you want to append an object created via new.
There's a big difference between an object and a pointer to an object. :-)
-
wrote on 27 Mar 2012, 18:58 last edited by
And there is no "void" in the constructor. this is a mistake from me..
-
wrote on 27 Mar 2012, 19:05 last edited by
[quote author="mlong" date="1332871529"]
If you look at dridk's example, you'll see that he has a QList<CalcXY*> which is a list of CalcXY pointers, which is what you need if you want to append an object created via new.
[/quote]
Perfect. I missed that. Thanks.
-
wrote on 27 Mar 2012, 19:23 last edited by
And, I'm guessing that currCalcXY should be a CalcXY* too instead of a CalcXY, or perhaps you should just keep track of an integer which is an index into your QList of CalcXY pointers.
Then you could simplify things with an accessor method
@
CalcXY* CalcXYPool::current()
{
if (currCalcXY >= 0 && currCalcXY < calcXYList.count()) {
return calcXYList.at(currCalcXY);
} else {
qWarning("Current CalcXY item is invalid! Returning 0.");
return 0;
}
}
@
(Brain to terminal; ymmv) -
wrote on 27 Mar 2012, 19:41 last edited by
That is much cleaner! Ultimately, I need to get the QML to point to the currCalcXY.
So something like this I am guessing?
@
// Ignore the exitingField toggle. I'll incorporate dridk's template shortly.
onActiveFocusChanged: {calcXYObject.toggleExitingField();
calcXYPoolObject.current().setX(x.text)}
@to set the x-value of the current calculator.
Still in the process of mapping my decades old experience in NeXTSTEP programming to Qt (and C++) ;).
Cheers.
-
wrote on 27 Mar 2012, 20:41 last edited by
As expected, I am still short on some QML subtleties ;).
Using the above example I get the following error:
@
Result of expression 'calcXYPoolObject.getCurrCalc().setX' [undefined] is not a function.
@So I am guessing that I need to cast 'calcXYPoolObject.getCurrCalc()' to (CalcXY *) because QML doesn't know the interface to the CalcXY class, but how to do that in QML. Any suggestions? I hope that I don't need to promote the entire interface of CalcXY into CalcXYPool.
BTW, I have confirmed using qDebug() that both the calcXYList is populated, and that in the snippet provided by mlong that we are returning a valid calcXY from the calcXYList.
Thanks.
-
wrote on 28 Mar 2012, 13:46 last edited by
So, I have tried another approach, which I thought might work, but still no success.
Following mlong's suggestion, I only keep track of the integer value of the currCalcXY. But since I don't know how to cast back to the calcXYObject in QML, I am trying to set/reset the calcXYObject inside C++ (but not in main). That way the QML can remain simple.
@
// Store the pointer to the viewer so that CalcXYPool can setContextProperty
void CalcXYPool::setAppViewer(QmlApplicationViewer *viewer) {
appViewer=viewer;
}
@@
void CalcXYPool::setCurrCalcXY(int calcIndex) {
currCalcXY = calcIndex;
(*appViewer).rootContext()->setContextProperty("calcXYObject", calcXYList.at(currCalcXY));
}
@In main, I call:
@
QmlApplicationViewer viewer;calcXYPool.setAppViewer(&viewer);
@
and in the QML, I can just go back to:
@
// Now we should be able to directly reference calcXYObject rather
// than having to cast calcXYObjectPool.current()
onActiveFocusChanged: {calcXYObject.toggleExitingField();
calcXYObject.setX(x.text)}
@I thought that it was a good idea. Unfortunately, it didn't work :(.
@
calcxy.qml:52: ReferenceError: Can't find variable: calcXYObject
@Any thoughts or suggestions?
Thanks.
1/10