65.9K
CodeProject 正在变化。 阅读更多。
Home

在 C++ 中嵌入 Python。使用 Boost Python 和 GTK+ 的示例

starIconstarIconstarIconstarIconstarIcon

5.00/5 (1投票)

2015 年 6 月 3 日

MIT

2分钟阅读

viewsIcon

21534

downloadIcon

169

在本教程中,我们将学习如何在 C++ 应用程序中嵌入 Python。特别是,我们将看到一个示例,其中我们将能够与 GUI(使用 GTK+ 构建)进行交互。

引言

在本教程中,我们将学习如何在 C++ 应用程序中嵌入 Python。特别是,我们将看到一个示例,其中我们将能够与 GUI(使用 GTK+ 构建)进行交互。

所以结果会是这样的

IMG_HERE

有一个标签,我们可以将其设置为任何值。还有一个文本输入框,您可以在其中输入您的 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();
    }    
}
© . All rights reserved.