Solved PyQt loading libraries, what is wrong there?
-
Hello, I am still trying to figure out how to load a library in that
PyQt
thing. So in short, I have a widget, that is a library:Here is the header:
#ifndef INTERFACE_H #define INTERFACE_H #define MY_EXPORT #ifdef __cplusplus extern "C" { #endif struct QWidget; QWidget *getWidget(void); #ifdef __cplusplus }; #endif
and the implementation:
#include "interface.h" #include "testwidget.h" #include <iostream> #include <QtWidgets/qwidget.h> #include <QObject> extern "C" MY_EXPORT QWidget *getWidget(void) { QWidget* w = new QWidget; w->setMinimumSize(200, 200); w->setMaximumSize(200, 200); return w; }
Now from the
C++
perespective the followingmain.cpp
is legit and working:#include <QApplication> #include <QtCore> #include <iostream> #include <QtWidgets/QWidget> typedef QWidget* (*fncall)(void); int main(int argc, char *argv[]) { QApplication app(argc, argv); QLibrary lib("/home/ilian/git-projects/build-testpyqtlib-Desktop_Qt_5_7_1_GCC_64bit-Debug/libtestpyqtlib.so"); bool res = lib.load(); if (res) { std::cout << "LOAD OK" << std::endl; fncall f = (fncall)lib.resolve("getWidget"); if (f) { std::cout << "Calling f\n"; QWidget* w = f(); w->show(); } else { //exit(1); } } else { std::cout << "LOAD FAILED" << std::endl; std::cout << lib.errorString().toStdString() << std::endl; } app.exec(); }
The bad things get in the
PyQt
loading the libraries. Ok, I succeeded with loading the lib. But... How do I call the functiongetWidget()
? Here is in detail what is going on:import sys from ctypes import * from PyQt5 import QtCore from PyQt5 import QtGui from PyQt5 import QtWidgets from PyQt5.QtCore import QLibrary from sip import voidptr libc = CDLL('/home/ilian/git-projects/build-testpyqtlib-Desktop_Qt_5_7_1_GCC_64bit-Debug/libtestpyqtlib.so') def foo(): pass def main(*args, **kwargs): app = QtWidgets.QApplication(sys.argv) w = libc.getWidget() print(w) app.exec() if __name__ == "__main__": main(sys.argv)
Consider the above python code: the function
getWidget
is called, but the return type is always anint
. I don't want it to beint
. I saw a reference that tells: you can specify the return type however adding the line: (you can somehow specify the return type, assuming you have declaration of the type in your python app)... libc.getWidget.restype = QtWidgets.QWidget w = libc.getWidget() # Crash! w.show()
I got a program crash which I can't trace in python. The error on the call is:
Traceback (most recent call last):File "/home/ilian/git-projects/pyqtlibtest/pyqtloadlibtest.py", line 24, in <module> main(sys.argv) File "/home/ilian/git-projects/pyqtlibtest/pyqtloadlibtest.py", line 18, in main w = libc.getWidget() TypeError: QWidget(parent: QWidget = None, flags: Union[Qt.WindowFlags, Qt.WindowType] = Qt.WindowFlags()): argument 1 has unexpected type 'int'
Now I am kind of totally stuck with
PyQt
stuff and I can't seem how to load aQWidget
as a library and to be able to connect that object to the program that loads the library.Any help here?
#endif // INTERFACE_H
-
Hi,
Not a direct answer but wouldn't it be simpler to create bindings the same way PyQt does for your custom set of widgets ?
-
@SGaist I am really not a python/PyQt expert, so I have no idea about how to do that, but I will do some research, thanks.
-
Take a look here. PyQt uses sip to create the bindings. At the bottom of the page you can find an Qt example.
-
@SGaist I don't want to deal with that SIP thing, I want to keep as Qt as possible for the other team members. I was able to use
QPluginLoader
and get aQObject
instance in the damnedPyQt
, however I am stuck with the lacking ofqobject_cast<>
which can cast to the interface, and I have no idea how to implement the classicC++
interface in thePyQt
thing. Also the internet lacks any sophisticated info :( -
What I came into my mind, which can be considered an ugly hack, it to dump a
QWidget
to a char array, then cast it toQWidget
again usingC
unionunion WidgetData { QWidget w; char data[sizeof(QWidget)]; };
but even then, I can't cast anything ... Really, I don't want to bother with that SIP thing, I want to keep it as simple as possible, and there must be some way, I'll try with
Python.h
to see if cant be done there, but this is really frustrating fromPyQt
side, not to have a simple example for theQLibrary
andQPLuginLoader
.... -
@ilian "I don't want to deal with that SIP thing" - do you think it is better to hack around with manual library loading and some dirty hacks like the union? PyQt already provides nice Qt integration in Python using SIP - it would be better to do it in the same way.
-
@jsulm It's a huge task I can't handle the whole task writing over 200 classes in that SIP modules. What I want is just to bridge existing slots in a C++ program to a PyQt based program, so the PyQto to be able to send signal/slots to the C++ program. That's why I want to be able to extract an Qt stuff from the library, which is C++. If I go into the SIP thing I will be totally lost.
-
Also the examples are all for
PyQt4
, and I am usingPyQt5
that leads me to even further obfuscation. -
I am trying
PyQt4
example in the SIP site, it fails me building a Qt module. Even with a copy/pasted code it gives me missingsbf
files and cannot findQtGui\QtGuimod.sip
. I don't know how people deal with this thing anymore. -
I was able to fight trough the SIP, if somebody needs an example: here it is:
https://github.com/heatblazer/pyqtlibtest/tree/master/sip@SGaist thanks for the referal, it was a hard task but there is no way around.
@jsulm Seems like I could not avoid SIP :(