I instantiated dynamically an object in main() and set it on context like:
Controller *controller = new Controller();
engine.rootContext()->setContextProperty("controller", controller);
After this point I don't have access to the pointer in c++ only in QML. At the end of the application I want to release the pointer (more specific in Component.onDestruction). I couldn't figured out how to do it in QML.
I tried controller.destroy() but it returns : Error: Invalid attempt to destroy() an indestructible object.
Also tried controller.deleteLater() but it gave me: TypeError: Property 'deleteLater' of object Controller(0x4914028) is not a function.
delete controller does nothing.
I've searched the documentation but couldn't found what I was looking for. Anyone has any idea? Thanks!
You can try to use a smart pointer so that it gets destroyed when it goes out of scope.
//main.cpp
QSharedPointer<Controller> controller =
QSharedPointer<Controller>(new Controller(), &QObject::deleteLater);
engine.rootContext()->setContextProperty("controller", controller);
Related
I found an interesting article on how to impement QObject with dynamic properties (see C++ class DynamicObject). The code from the article works fine, the properties of DynamicObject are get and set successfully from both C++ and QML, but the only thing I cannot figure out is how to fire dynamic signals.
I tried to fire "nameChanged()" signal with the following code:
bool DynamicObject::emitDynamicSignal(char *signal, void **arguments)
{
QByteArray theSignal = QMetaObject::normalizedSignature(signal);
int signalId = metaObject()->indexOfSignal(theSignal);
if (signalId >= 0)
{
QMetaObject::activate(this, metaObject(), signalId, arguments);
return true;
}
return false;
}
myDynamicObject->emitDynamicSignal("nameChanged()", nullptr);
the index of the signal is found and signalId is assigned to 5, but the signal is not fired. But if I do, for example,
myDynamicObject->setProperty("name", "Botanik");
the property is changed and the signal is fired successfully.
What is wrong in my code? What should I pass as 'arguments' parameter of QMetaObject::activate ?
EDIT1:
The full source code is temporarily available here.
A signal is also a method. You can invoke it from the meta object.
So, replace your line QMetaObject::activate(...) by:
metaObject()->method(signalId).invoke(this);
And let Qt handles the call to activate().
There is also an issue in DynamicObject::qt_metacall(): you are handling only QMetaObject::ReadProperty and QMetaObject::WriteProperty calls.
You have to add QMetaObject::InvokeMetaMethod if you want to emit your signal.
Like the title,why the "q_ptr" pointer is assigned to "this" pointer of QObject? in source code.
QObject::QObject(QObjectPrivate &dd, QObject *parent)
: d_ptr(&dd)
{
>>Q_D(QObject);
>>d_ptr->q_ptr = this;/*question*/
.......
Then,when use Q_Q() macro in source code like blow:
Q_Q(QWidget)
It will return the q pointer handled by the function q_fun():
QWidget*q_func() {return static_cast<QWidget*>(q_ptr);}
As all we know,static_castis not safe when cast from parent to child.
I am very frustrated about /*question*/ ,can any guy tell me the secret?Thanks!
d_ptr->q_ptr = this;/*question*/
This is where the private implementation object (PIMPL idiom) is told about the object it is working for/with (the non-private QObject). Here's a good link for info about Qt and d pointers (d_ptr).
Q_Q macro returns the pointer to the QObject, so you can emit signals from it (among other things). As for the static_cast bit, that is safe because the macro is defined differently for each class created by the Q_DECLARE_PRIVATE and Q_DECLARE_PUBLIC macros: the result being, static_cast is always casting to the correct type. Again, I recommend reading the link.
I'm trying to pass an enum as a value to a slot in my program, but I'm having some problems. In my header file I've created the enum:
Q_ENUMS(button_type);
enum button_type {button_back, button_up, button_down, button_ok};
Q_DECLARE_METATYPE(button_type);
And in my .cpp file I'm trying to pass it to a slot:
QObject::connect(buttons->ui.pushButton_back, SIGNAL(clicked()), this, SLOT(input_handler(button_back)));
But when I compile the code I get:
Object::connect: No such slot main_application::input_handler(button_back) in main_application.cpp:44
Object::connect: (sender name: 'pushButton_back')
Object::connect: (receiver name: 'main_applicationClass')
It compiles and works fine if I don't pass an argument to input_handler.
I've also read that I should be calling qRegisterMetaType, but I can't seem to get the syntax correct. Here's what I tried:
qRegisterMetaType<button_type>("button_type");
but I get this error:
main_application.h:15:1: error: specializing member ‘::qRegisterMetaType<button_type>’ requires ‘template<>’ syntax
Can anyone shed some light on this for me?
Thanks!
Marlon
Signal and Slot need to have the same parameters. What you want is a QSignalMapper.
edit:
Here is an example from an application of mine. It creates 10 menu actions that each are connected to the same slot gotoHistoryPage but each called with a different int value.
m_forwardMenu = new QMenu();
for(int i = 1; i<=10; i++)
{
QAction* action = m_forwardMenu->addAction(QString("%1").arg(i));
m_forwardActions.push_back(action);
m_signalMapper->setMapping(action, i);
connect(action, SIGNAL(triggered()), m_signalMapper, SLOT(map()));
}
ui.forwardButton->setMenu(m_forwardMenu);
connect(m_signalMapper, SIGNAL(mapped(int)), this, SLOT(gotoHistoryPage(int)));
You're passing the SLOT() macro a value when it's expecting a type. More fundamentally this doesn't make much sense anyway as what you're struggling to achieve is to pass the slot a constant. Why not just use button_back in the slot function directly?
You can define a slot which takes a button_type value, but then you'd need to connect it to a signal that passes one as a parameter.
What are you actually trying to do?
Object::connect: No such slot main_application::input_handler(button_back)
Of course, there is, because signature is main_application::input_handler(button_type), and button_back is a value, not type. And even you make right signature, you will not be able to connect that signal and slot due to their signature mismatch.
Also, you can always use QObject::sender() function to get known, what button was pressed.
Im trying to connect a Flash client to BlazeDS. There has been some success with this from others using the vanilla BlazeDS setup. However I'm using the new Spring BlazeDS Integration from springsource and running aground.
The flash client actually seems to be working in that I can see the correct data in the body of the returned object, but for some reason unknown it fails casting as an IMessage. It fails in PollingChannel.as on this line with the subject line error
var messageList:Array = msg.body as Array;
for each (var message:IMessage in messageList) <--
On application load I register a whole bunch of classes like so
registerClassAlias( "flex.messaging.messages.RemotingMessage", RemotingMessage );
registerClassAlias("mx.messaging.messages.IMessage", IMessage);
etc..
my code is basically
var channelSet:mx.messaging.ChannelSet = new mx.messaging.ChannelSet();
var channel:mx.messaging.channels.AMFChannel = new AMFChannel("my-amf", "http://localhost:8400/SpringA/messagebroker/amf");
channelSet.addChannel(channel);
var consumer:mx.messaging.Consumer = new Consumer();
consumer.channelSet = channelSet;
consumer.destination = "simple-feed";
consumer.subscribe();
consumer.addEventListener(MessageEvent.MESSAGE, test);
private function test(event:IMessage)
{
trace("msg..");
// breakpoint never makes it here
}
I have a flex client which works 100% with same destination/channel.
The error in the title means that you, for some reason, got an object that is not implementing or extending the IMessage interface, therefore the loop can not cast it in this part:
for each (var message:IMessage in messageList){
Either you should somehow make sure that you don't add anything that is not extending or implementing IMessage, or check if the variable IS actually ext./imp. it. Also - if you want to do that, you will have to change the for each like this:
for each (var obj in messageList){
if (obj is IMessage){
var message:IMessage = obj as IMessage;
// DO STUFF HERE
}
}
Add this Object mapping:
registerClassAlias("flex.messaging.io.ObjectProxy", ObjectProxy);
If on your Java VO objects you have overridden the hashcode() method, this situation could happen.
Remove the hashcode() override (if you are able to).
See my blog for the backstory on how I discovered this. http://squaredi.blogspot.com/2013/12/remoting-landmine-without-stack-trace.html
I had the same error when trying to send an actionscript object to the backend. My problem was that my c# equivalent object was missing an public parameterless constructor.
I want to clone a Canvas object, which contains a Degrafa Surface with several Geometry shapes.
I tried the naive approach:
return ObjectUtil.copy(graph_area) as Canvas;
which resulted in errors:
TypeError: Error #1034: Type Coercion failed: cannot convert Object#63b1b51 to com.degrafa.geometry.Geometry.
TypeError: Error #1034: Type Coercion failed: cannot convert Object#63b1039 to com.degrafa.geometry.Geometry.
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at mx.core::Container/addChildAt()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\core\Container.as:2196]
at mx.core::Container/addChild()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\core\Container.as:2140] ...
What you want is called a deep copy, generate a new instance with the same information of the original.
The only way I know how to do it is using ByteArray as follows:
private function clone(source:Object):*
{
var buffer:ByteArray = new ByteArray();
buffer.writeObject(source);
buffer.position = 0;
return buffer.readObject();
}
AS3 is really lacking Object.clone()...
ObjectUtil
The static method ObjectUtil.copy() is AS3's "Object.clone()":
public static function copy(value:Object):Object
Copies the specified Object and
returns a reference to the copy. The
copy is made using a native
serialization technique. This means
that custom serialization will be
respected during the copy.
This method is designed for copying
data objects, such as elements of a
collection. It is not intended for
copying a UIComponent object, such as
a TextInput control. If you want to
create copies of specific UIComponent
objects, you can create a subclass of
the component and implement a clone()
method, or other method to perform the
copy.
I found myself trying something more like this alas it still doesn't seem to copy a TextArea (aka UI Object)...
public function duplicateObject(sourceObject:*, targetObject:*):void {
var buffer:ByteArray = new ByteArray();
buffer.writeObject(sourceObject);
buffer.position = 0;
targetObject = buffer.readObject();
}
i got the same problem (for a NamedEntity interface i created), looked for the answer here, but only got it working making a call to the registerClassAlias method (which i took from http://richapps.de/?p=34). Just like that:
public static function clone(namedEntity:NamedEntity):NamedEntity {
registerClassAlias('test',ReflectionUtil.classByObject(namedEntity));
var returnObject:NamedEntity = ObjectUtil.copy(namedEntity) as NamedEntity;
}
I don't think ObjectUtil.copy will work for cloning a canvas.
According to the flex doc :
Copy
This method is designed for copying data objects, such as elements of a collection. It is not intended for copying a UIComponent object, such as a TextInput control. If you want to create copies of specific UIComponent objects, you can create a subclass of the component and implement a clone() method, or other method to perform the copy.