How to override a virtual C++ function with PythonQt
Dynamic Python binding for Qt Applications
Brought to you by:
florianlink,
marcusbarann
I am trying to add Python scripting capability to my Qt application. So far, I have been able to write wrappers for many classes. However, one class has a virtual 'init()' function which can be overridden by a derived class if necessary.
// Qt C++ class:
The problem is that the print statement (and the following code) is never executing. The init() function is not being overridden by the PythonQt code.
Last edit: Allen C Kempe 2015-09-26
PythonQt can unfortunately not do 'magic'... If you want to override a virtual method from Python, then you need a shell class which derives the base C++ class and forwards the virtual method call to Python.
the pythonqt_generator can do this, but it is not as easy to use as writing your own wrappers. You need to create an xml file that defines your typesystem and there is no good documentation about this. There are typesystems for the whole qt library, so you can copy from that.
Thanks! I'm not sure what you mean by 'shell class'. I have found some posts related to
'pythonqt_generator' so I'll continue my investigation there.
A shell class is an extra class which derives from a C++ class and overrides all virtual methods and redirects them to Python. This is the only way to allow inheritance of Python classes from C++ classes, at least I don't know any other way this could be done. The pythonqt generator will generate such shell classes for any wrapped class that is in the typesystem and has virtual methods.
OK: I'm sort of hung up on creating the typesystem file. I found this QtJambi doc: http://qtjambi.org/doc/generator_typesystem which explains the use in the QtJambi package. I'm assuming that you robbed the code from tje QtJambi product to create Python code instead of Java code from Qt classes.
So far, I've gotten this output but there don't seem to be any files generated:
allen@ubuntu:~/Projects/DecoderPro/fossil/DecoderPro_app/LayoutEditor$ ../../../../PythonQt3.0/generator/pythonqt_generator --include-paths=/home/allen/Projects/DecoderPro/fossil/DecoderPro_app/libPr3/ abstractautomaton.h typesystem_abstractautomat.xml
Please wait while source files are being generated...
Parsing typesystem file [typesystem_abstractautomat.xml]
PreProcessing - Generate [.preprocessed.tmp] using [abstractautomaton.h] and include-paths [/home/allen/Projects/DecoderPro/fossil/DecoderPro_app/libPr3/]
Using QT at: /usr/local/Trolltech/Qt-4.8.3
Building model using [.preprocessed.tmp]
WARNING(MetaJavaBuilder) :: enum 'QMetaType::Type' does not have a type entry or is not an enum
WARNING(MetaJavaBuilder) :: unknown baseclass for 'Runnable': 'QThread'
QByteArray.contains(const char * a) const mostly equal to QByteArray.contains(char c) const
QByteArray.contains(char c) const mostly equal to QByteArray.contains(const char * a) const
WARNING(MetaJavaBuilder) :: signature 'hasRegisteredConverterFunction()' for function modification in 'QMetaType' not found. Possible candidates:
WARNING(MetaJavaBuilder) :: signature 'hasRegisteredDebugStreamOperator()' for function modification in 'QMetaType' not found. Possible candidates:
WARNING(MetaJavaBuilder) :: signature 'hasRegisteredComparators()' for function modification in 'QMetaType' not found. Possible candidates:
WARNING(MetaJavaBuilder) :: signature 'registerComparators()' for function modification in 'QMetaType' not found. Possible candidates:
WARNING(MetaJavaBuilder) :: signature 'registerConverter()' for function modification in 'QMetaType' not found. Possible candidates:
WARNING(MetaJavaBuilder) :: signature 'registerDebugStreamOperator()' for function modification in 'QMetaType' not found. Possible candidates:
Classes in typesystem: 86
Generated:
- header....: 2 (2)
- impl......: 2 (2)
- modules...: 0 (0)
- pri.......: 1 (0)
Done, 8 warnings (1011 known issues)
Apparently one must specify the --output-directory option for it to generate any output! So now I have to figure out what to do with the output.
OK, I've finally got the generator figured out and now I can override a virtual function. However there's another problem. The class cannot run in the GUI thread so the 'start' method moves it to another thread. This works fine for straighte C++ classes but now when the class is wrapped:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
include "myclass.h"
include <QDebug>
include <QThread>
MyClass::MyClass(QObject *parent) :
QObject(parent)
{
qDebug() << "MyClass constructor";
}
void MyClass::init()
{
qDebug() << "Init was not overridden";
}
void MyClass::start()
{
QThread* thread = new QThread;
connect(thread, SIGNAL(started()), this, SLOT(run()));
moveToThread(thread);
thread->start();
}
void MyClass::run()
{
init();
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
I'm thinking that I may have to run the python script interpretor in another thread.
What does "Post awaiting moderation." mean?
The solution to my problem is to use the PythonQt generator application to create the wrapper functions. I've created a small Qt project "TestPython" that should serve as an example on how to do it.