简体   繁体   English

C ++ - PyQt4不能看到实例化的QApplication

[英]C++-instantiated QApplication not visible by PyQt4

I have a C++/Qt application which loads a plugin (.dll/.so) using QPluginLoader facilities. 我有一个C ++ / Qt应用程序,它使用QPluginLoader工具加载一个插件(.dll / .so)。 This plugin is basically an embedded python interpreter which allows to inspect Qt objects in the main application via the PyQt4 module. 这个插件基本上是一个嵌入式python解释器,它允许通过PyQt4模块检查主应用程序中的Qt对象。

Problem is the command PyQt4.QtCore.QCoreApplication.instance(), executed from the plugged-in python interpreter, returns None even though the QCoreApplication instance has been created by the C++ application. 问题是从插件python解释器执行的命令PyQt4.QtCore.QCoreApplication.instance(),即使QCoreApplication实例已由C ++应用程序创建,也返回None。

This is only on windows in debug mode. 这仅适用于调试模式下的Windows。

On linux or on release mode on windows, the command PyQt4.QtCore.QCoreApplication.instance() correctly returns the QCoreApplication instance that was created by the C++ application. 在Linux上或在Windows上的发布模式下,命令PyQt4.QtCore.QCoreApplication.instance()正确返回由C ++应用程序创建的QCoreApplication实例。

Following is some minimalist code showing the problem. 以下是一些显示问题的极简主义代码。

When compiled in release mode: 在发布模式下编译时:

$ ./a.out
1+1
2
import PyQt4
import PyQt4.QtCore
PyQt4.QtCore.QCoreApplication.instance()
<PyQt4.QtCore.QCoreApplication object at 0x00C69198>

=> Ok =>好的

When compiled in debug mode: 在调试模式下编译时:

$ ./a.out
import PyQt4
import PyQt4.QtCore
PyQt4.QtCore.QCoreApplication.instance()

=> Not ok (returned None) =>不行(返回无)

File main.cpp 文件main.cpp

#include <QCoreApplication>
#include <QPluginLoader>
#include <QDebug>

int main(int argc, char **argv)
{
        QCoreApplication app(argc, argv);

        QPluginLoader loader("plugin.dll");
        loader.setLoadHints(QLibrary::ResolveAllSymbolsHint | QLibrary::ExportExternalSymbolsHint);
        loader.load();
        if(!loader.isLoaded()) {
                qDebug() << loader.errorString();
                return 1;
        }
        (void)loader.instance();

        return app.exec();
}

File plugin.h 文件plugin.h

#ifndef PLUGIN_H
#define PLUGIN_H

#include <QObject>
#include <Python.h>

class Plugin : public QObject
{
public:
        Plugin();
        ~Plugin();

private:
        PyThreadState *m_ts;
};

class InterpInput : public QObject
{
        Q_OBJECT
public:
        InterpInput(QObject *parent = 0) : QObject(parent) { }
public slots:
        void monitorInput();
signals:
        void done();
        void inputReady();
};

class InterpOutput : public QObject
{
        Q_OBJECT
public:
        InterpOutput(QObject *parent = 0) : QObject(parent) { }
public slots:
        void processLine();
public:
        PyThreadState *m_ts;
};

#endif

File plugin.cpp 文件plugin.cpp

#include "plugin.h"

#include <QCoreApplication>
#include <QThread>
#include <QtPlugin>
#include <QPluginLoader>

Q_EXPORT_PLUGIN2(Plugin, Plugin)

Plugin::Plugin()
{
        Py_Initialize();
        PyEval_InitThreads();

        InterpInput *in = new InterpInput();
        InterpOutput *out = new InterpOutput(this);
        in->connect(in, SIGNAL(inputReady()), out, SLOT(processLine()));
        in->connect(in, SIGNAL(done()), QCoreApplication::instance(), SLOT(quit()));

        QThread *thr = new QThread(this);
        in->moveToThread(thr);
        thr->connect(thr, SIGNAL(started()), in, SLOT(monitorInput()));

        m_ts = PyEval_SaveThread();
        out->m_ts = m_ts;

        thr->start();
}

Plugin::~Plugin()
{
        PyEval_RestoreThread(m_ts);
        Py_Finalize();
}

void InterpInput::monitorInput()
{
        PyGILState_STATE gstate;
        gstate = PyGILState_Ensure();

        int ret = PyRun_SimpleString("import sys\nimport code\nic = code.InteractiveConsole()");
        assert(ret == 0);
        while(true) {
                ret = PyRun_SimpleString("line = ic.raw_input()");
                if(ret) { break; }
                inputReady();
        }
        done();

        PyGILState_Release(gstate);
}

void InterpOutput::processLine()
{
        PyEval_RestoreThread(m_ts);
        int ret = PyRun_SimpleString("ic.push(line)");
        PyRun_SimpleString("sys.stdout.flush()");
        PyRun_SimpleString("sys.stderr.flush()");
        (void)PyEval_SaveThread();
        assert(ret == 0);
}

File Makefile 文件Makefile

MOC=/cygdrive/c/Qt/4.8.4/bin/moc
GCC=/cygdrive/c/MinGW/bin/mingw32-g++.exe
FLAGS=-Ic:/Qt/4.8.4/include -Ic:/Qt/4.8.4/include/QtCore -Lc:/Qt/4.8.4/lib -Lc:/Qt/4.8.4/bin -lQtCore4 -Lc:/Python27/libs -lpython27 -Ic:/Python27/include -DQT_NO_DEBUG
#FLAGS=-Ic:/Qt/4.8.4/include -Ic:/Qt/4.8.4/include/QtCore -Lc:/Qt/4.8.4/bin -lQtCored4 -Lc:/Python27/libs -lpython27 -Ic:/Python27/include -g
LIBFLAGS=-shared

all:
        $(MOC) plugin.h > plugin_moc.cpp
        $(GCC) -o a.out main.cpp $(FLAGS)
        $(GCC) -o plugin.dll $(LIBFLAGS) plugin.cpp plugin_moc.cpp $(FLAGS)

The explanation is the following. 解释如下。

In debug version, the C++ application and plugin link to debug Qt libraries (QtCored4.dll, etc.) Whereas the installed PyQt4 modules (QtCore.pyd, etc.) link to release Qt libraries (QtCore4.dll, etc.) 在调试版本中,C ++应用程序和插件链接调试Qt库(QtCored4.dll等)而安装的PyQt4模块(QtCore.pyd等)链接释放Qt库(QtCore4.dll等)

It follows that the C++ application, and the PyQt4 module, each see a QCoreApplication instance but each see a different one, which lives in a different library (respectively the debug, and the release, version of the Qt library). 因此,C ++应用程序和PyQt4模块每个都看到一个QCoreApplication实例,但每个实例都看到一个不同的实例,它们位于不同的库中(分别是调试版和Qt库的版本)。

It follows that the instance living in the PyQt4 module is not initialized when the C++ application is initialized, and is thus null. 因此,当C ++应用程序初始化时,生成在PyQt4模块中的实例未初始化,因此为空。

This is verified by compiling the PyQt4 modules specifying that they should be linked to the debug Qt libraries: the problem then disappears as the debug-mode C++ application and the PyQt4 modules link to the same Qt library. 这是通过编译PyQt4模块来验证的,这些模块指定它们应该链接到调试Qt库:当调试模式C ++应用程序和PyQt4模块链接到同一个Qt库时,问题就会消失。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM