在 C++ 中嵌入 Python。使用 Boost Python 和 GTK+ 的示例
在本教程中,我们将学习如何在 C++ 应用程序中嵌入 Python。特别是,我们将看到一个示例,其中我们将能够与 GUI(使用 GTK+ 构建)进行交互。
引言
在本教程中,我们将学习如何在 C++ 应用程序中嵌入 Python。特别是,我们将看到一个示例,其中我们将能够与 GUI(使用 GTK+ 构建)进行交互。
所以结果会是这样的
有一个标签,我们可以将其设置为任何值。还有一个文本输入框,您可以在其中输入您的 Python 命令。
背景
我假设您了解 C++ 和一些 Python。
指南
首先,让我们创建界面。
#include <gtk/gtk.h>
#include <iostream>
#include <boost/python.hpp>
#include <Python.h>
using namespace std;
GtkWidget *window;
GtkWidget *layout;
GtkWidget *label;
GtkWidget *entry;
void command( GtkWidget* widget, gpointer data );
void setLabelText(const char* text);
int main( int argc, char *argv[])
{
// Initialize GTK
gtk_init(&argc, &argv);
// create window
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
// set vertical layout
layout = gtk_vbox_new( TRUE, 1 );
gtk_container_add(GTK_CONTAINER(window), layout);
// create a label and a text entry
label = gtk_label_new("nothing");
entry = gtk_entry_new();
// put the label and the entry in the layout
gtk_box_pack_start( GTK_BOX(layout), label, TRUE, TRUE, 0 );
gtk_box_pack_start( GTK_BOX(layout), entry, TRUE, TRUE, 0 );
// connect the destroy signal so when you click "the cross" the
// window closes
g_signal_connect_swapped
(
G_OBJECT(window),
"destroy",
G_CALLBACK(gtk_main_quit),
G_OBJECT(window)
);
// when enter is pressed in the text entry call "command"
g_signal_connect
(
G_OBJECT(entry),
"activate",
G_CALLBACK(command),
NULL
);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
void command( GtkWidget* widget, gpointer data )
{
// we will change this line by the python interpreter
setLabelText( gtk_entry_get_text( GTK_ENTRY(widget) ) );
}
// set the value of the label
void setLabelText(const char* text)
{
gtk_label_set_text
(
GTK_LABEL( label ),
text
);
}
如果您编译前面的代码,您会看到当您按下 Enter 键时,输入框的内容将被复制到标签中。
如果您在 Linux 上编译此代码,此命令可能有效
g++ window.cpp `pkg-config --libs --cflags gtk+-2.0` -I /usr/include/python2.7/
-lpython2.7 -lboost_python-py27 -o window
./window
现在让我们嵌入 Python。
您需要做的第一件事是初始化 Python 解释器。
Py_Initialize();
完成解释器后,您必须释放它。
Py_Finalize();
为了从 Python 解释器访问 C 函数,我们必须声明一个 Python 模块。
BOOST_PYTHON_MODULE( label_module )
{
using namespace boost::python;
def( "setLabelText", setLabelText );
}
所以从现在开始,我们可以从 Python 访问“setLabelText
”。好吧,还不行,我们必须首先在 main
中初始化并导入模块。
object main_module = import("__main__");
object main_namespace = main_module.attr("__dict__");
initlabel_module();
exec( "from label_module import *", main_namespace );
我们已将模块的所有变量导入到 main
命名空间中。您可能会问自己 initlabel_module
定义在哪里。该函数的定义是在 BOOST_PYTHON_MODULE
宏定义模块时自动生成的。因此,此宏通过获取模块名称并添加前缀“init”(init
+ label_module
)来声明一个函数。
最后,当按下 Enter 键时,我们编写在文本输入框中的内容必须转发到解释器。如果发生错误,我们希望处理它(我们只是打印错误)。
void command( GtkWidget* widget, gpointer data )
{
using namespace boost::python;
object main_module = import("__main__");
object main_namespace = main_module.attr("__dict__");
try
{
object obj =
exec
(
gtk_entry_get_text( GTK_ENTRY(widget) ),
main_namespace
);
}
catch(error_already_set)
{
PyErr_Print();
}
}
就这样。您可以在文本输入框中编写命令并设置标签文本。
这里,您拥有完整的代码
#include <gtk/gtk.h>
#include <iostream>
#include <boost/python.hpp>
#include <Python.h>
using namespace std;
GtkWidget *window;
GtkWidget *layout;
GtkWidget *label;
GtkWidget *entry;
void command( GtkWidget* widget, gpointer data );
void setLabelText(const char* text)
{
gtk_label_set_text
(
GTK_LABEL( label ),
text
);
}
BOOST_PYTHON_MODULE( label_module )
{
using namespace boost::python;
def( "setLabelText", setLabelText );
}
int main( int argc, char *argv[])
{
gtk_init(&argc, &argv);
Py_Initialize();
using namespace boost::python;
object main_module = import("__main__");
object main_namespace = main_module.attr("__dict__");
initlabel_module();
exec( "from label_module import *", main_namespace );
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
layout = gtk_vbox_new( TRUE, 1 );
gtk_container_add(GTK_CONTAINER(window), layout);
label = gtk_label_new("nothing");
entry = gtk_entry_new();
gtk_box_pack_start( GTK_BOX(layout), label, TRUE, TRUE, 0 );
gtk_box_pack_start( GTK_BOX(layout), entry, TRUE, TRUE, 0 );
g_signal_connect_swapped
(
G_OBJECT(window),
"destroy",
G_CALLBACK(gtk_main_quit),
G_OBJECT(window)
);
g_signal_connect
(
G_OBJECT(entry),
"activate",
G_CALLBACK(command),
label
);
gtk_widget_show_all(window);
gtk_main();
Py_Finalize();
return 0;
}
void command( GtkWidget* widget, gpointer data )
{
using namespace boost::python;
object main_module = import("__main__");
object main_namespace = main_module.attr("__dict__");
try
{
object obj =
exec
(
gtk_entry_get_text( GTK_ENTRY(widget) ),
main_namespace
);
}
catch(error_already_set)
{
PyErr_Print();
}
}