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 following main.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 function getWidget() ? 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 an int . I don't want it to be int. 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 a QWidget as a library and to be able to connect that object to the program that loads the library.

    Any help here?

    #endif // INTERFACE_H


  • Lifetime Qt Champion

    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.


  • Lifetime Qt Champion

    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 a QObject instance in the damned PyQt, however I am stuck with the lacking of qobject_cast<> which can cast to the interface, and I have no idea how to implement the classic C++ interface in the PyQt 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 to QWidget again using C union

    union 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 from PyQt side, not to have a simple example for the QLibrary and QPLuginLoader....


  • Moderators

    @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 using PyQt5 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 missing sbf files and cannot find QtGui\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 :(


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.