PyQt4 不可见 C++ 实例化的 QApplication
Posted
技术标签:
【中文标题】PyQt4 不可见 C++ 实例化的 QApplication【英文标题】:C++-instantiated QApplication not visible by PyQt4 【发布时间】:2013-05-24 20:52:57 【问题描述】:我有一个 C++/Qt 应用程序,它使用 QPluginLoader 工具加载插件 (.dll/.so)。 这个插件基本上是一个嵌入式 python 解释器,它允许通过 PyQt4 模块检查主应用程序中的 Qt 对象。
问题是命令 PyQt4.QtCore.QCoreApplication.instance(),从插入的 python 解释器执行,即使 C++ 应用程序创建了 QCoreApplication 实例,也返回 None。
这仅适用于处于调试模式的窗口。
在 linux 或 Windows 的发布模式下,命令 PyQt4.QtCore.QCoreApplication.instance() 正确返回由 C++ 应用程序创建的 QCoreApplication 实例。
以下是一些显示问题的极简代码。
在发布模式下编译时:
$ ./a.out
1+1
2
import PyQt4
import PyQt4.QtCore
PyQt4.QtCore.QCoreApplication.instance()
<PyQt4.QtCore.QCoreApplication object at 0x00C69198>
=> 好的
在调试模式下编译时:
$ ./a.out
import PyQt4
import PyQt4.QtCore
PyQt4.QtCore.QCoreApplication.instance()
=> 不正常(返回无)
文件 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();
文件插件.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
文件 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);
文件生成文件
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)
【问题讨论】:
您是否尝试过一种解决方法,例如在加载/初始化时将 Qapp 实例从您的主代码传递给您的插件? 或多或少。确实有获取 QCoreApplication 实例的解决方法。但是我还没有提到的根本问题是,如果 PyQt 本身看不到 QApplication 实例,则无法从 PyQt 执行某些需要 QApplication 的操作(例如创建 QPixmap)。这些操作可以在自定义模块中从 C++ 包装到 python,但这会重复 PyQt 应该做的事情。 问题仅在调试模式下发生。在发布模式下没问题。 会不会是(CoreApplication)符号在(调试)Qt 库和(非调试)PyQt4 模块之间的名称略有不同,这会使 PyQt4 看不到“C++ QCoreApplication”? 可能的解释是插件的调试版本链接到QtCore4d.dll,而PyQt4链接到QtCore4.dll,因此app+plugin和PyQt4分别引用了两个不同的QtCore库 【参考方案1】:解释如下。
在调试版本中,用于调试 Qt 库(QtCored4.dll 等)的 C++ 应用程序和插件链接 而安装的 PyQt4 模块(QtCore.pyd 等)链接到发布 Qt 库(QtCore4.dll 等)
因此,C++ 应用程序和 PyQt4 模块每个都看到一个 QCoreApplication 实例,但每个看到一个不同的实例,该实例位于不同的库中(分别是 Qt 库的调试版本和发布版本)。
由此可见,PyQt4模块中的实例在C++应用初始化时并未初始化,因此为null。
这可以通过编译 PyQt4 模块来验证,指定它们应该链接到调试 Qt 库:随着调试模式 C++ 应用程序和 PyQt4 模块链接到同一个 Qt 库,问题就会消失。
【讨论】:
以上是关于PyQt4 不可见 C++ 实例化的 QApplication的主要内容,如果未能解决你的问题,请参考以下文章
PyQt4:如何获取 QlistWidget 的可见项目列表?
由非托管 (C++) COM 服务器实例化的托管 (C#) 控件在 Windows 更新后中断