【问题标题】:Vala to Python and back againVala 到 Python 又回来了
【发布时间】:2013-04-18 11:23:48
【问题描述】:

我一直试图从 Vala/C 向上摸索到 Python 并再次返回。我所有的 google-fu 都在引导我转圈。 我想使用 Vala 编写一个 API,然后从 Python(或者可能是 Gnome Javascript)中使用它。

以 Clutter 为例(它也可以是 GTK+3 小部件)这是我的问题:我该怎么做 —

去那里

编写一个自定义Actor,点击后会:

  1. 更改颜色 - NB:这是在 Vala 处理程序中完成的。即 vala 对象连接到“按钮释放”事件。该处理程序调用一个 vala 方法: this.set_col('blue');
  2. 让它继续将该事件连同一些数据一起输入到 Python 中 — 假设我想打印“我变蓝了!” - 所以我需要“蓝色”作为字符串。

在 Python 中,我将创建一个舞台并(不知何故 - 通过 GI 魔法)创建我的新 Actor。我做了所有的 Python 东西来设置它,我连接到同一个“按钮释放”事件(我猜..)

a) Vala 处理程序会运行,然后是 Python 处理程序吗? (按顺序,或根本没有。)

b) 我是否必须在 Vala 处理程序中做一些特别的事情——比如返回 true,或者发出一些新的信号让 Python 接收?

又回来了

假设演员叫 V。我如何:V.set_col('red')(在 Python 中)并让它运行 Vala set_col 方法,传递 Python 字符串? (我怀疑这是 GI 下的自动魔法,但我不确定。)

总之

Vala actor -- event --> handler (in Vala) --> handler (in Python) with data
Vala method <--- method call with args from Python 

感谢任何链接等,谢谢。

【问题讨论】:

  • 您希望我们回答的具体问题是什么?
  • jsalonen - 1) 如何获取 Vala 代码 Python 代码以在信号/事件上运行和 2) 如何从 Python 调用 Vala 代码。来来回回。
  • 好的,谢谢你澄清了一点!

标签: python c signals vala clutter


【解决方案1】:

我明白了。下面的代码是这样工作的:

  1. 在一个目录中创建三个文件。
  2. “build”是一个 bash 脚本。
  3. “redsquare.vala”是将成为库(.so 文件)的 Vala
  4. “test.py”是使用该库的 Python3 代码。
  5. 安装这些:(apt-get bias,抱歉)
    • apt-get install libgirepository1.0-dev
    • apt-get install gobject-introspection
    • valac 和公司
  6. 运行 ./build,它应该会磨练 voodoo 并运行 test.py 文件。

  7. 您应该会看到一个 Clutter 窗口。单击红色方块并观看控制台栏。

:-D

HTH。

构建

#!/bin/bash

#
# Script borrowed from Tal Liron at:
# https://github.com/tliron/pygobject-example
#
# I did these to get this script to work:
#
# apt-get install libgirepository1.0-dev
# apt-get install gobject-introspection
#


echo "Cleaning..."

rm -rf tmp
rm -rf lib
rm -rf type
rm -f test

mkdir tmp
mkdir lib
mkdir type

    echo "Building Vala library..."

    # Note 1: Ubuntu package for valac: valac-0.14
    # Note 2: Generates broken gir if --gir= has a directory prefixed to it
    # Note 3: The -X switches for gcc are necessary!
    # Note 4: The generated gir will include GObject-2.0. That gir is
    #         included in Ubuntu package: libgirepository1.0-dev

    valac \
  --pkg clutter-1.0 \
    --library=Palelib \
    --directory=tmp \
    --gir=Palelib-1.0.gir \
    --output=libpalelib.so \
    -X -shared \
    -X -fPIC \
    redsquare.vala

    mv tmp/libpalelib.so lib
    mv tmp/Palelib-1.0.gir type

    # Note: We cannot generate C code and compile in the same call
    #       (We don't need the C code to run the test, but we are curious
    #       as to what Vala is generating. The resulting code will be in
    #       logging.c)
    #valac \
    #--ccode \
    #redsquare.vala


echo "Building typelib..."

# Note 1: Ubuntu package for g-ir-compiler: gobject-introspection
# Note 2: The --shared-library switch is really only necessary when using
#         the gir produced by valac, because it does not include the
#         'shared-library' attribute in <namespace> tag.


g-ir-compiler \
--shared-library=libpalelib.so \
--output=type/Palelib-1.0.typelib \
type/Palelib-1.0.gir

echo "Test Python..."

# Note 1: Ubuntu's default path for typelib files seems to be:
#         /usr/lib/girepository-1.0/.
# Note 2: It is also possible to programmatically change the
#         GI_TYPELIB_PATH environment var in Python (os.environ API).
#         If you do so, make sure to set it before importing from
#         gi.repository.
LD_LIBRARY_PATH=lib \
GI_TYPELIB_PATH=type \
./test.py

redsquare.vala

namespace Palelib {

    public class RedSquare : Clutter.Actor {

    //private vars
    private Clutter.Canvas _canvas;
    private int[] _col = { 255, 0, 0 };

    //Constructor - Needs to be called explicitly from Python by .new()
    public RedSquare() {
      stdout.printf( "RedSquare constructor.\n" );

      _canvas = new Clutter.Canvas();
      _canvas.set_size(300,300);

      this.set_size(300,300);
      this.set_content( _canvas );

      //Connect to the draw signal.
      _canvas.draw.connect(drawme);

      //Make it reactive and connect to the button-press-event
      this.set_reactive(true);
      this.button_press_event.connect( cleek );
    }

    //Button press signal handler
    private bool cleek ( Clutter.ButtonEvent evt ) {
      stdout.printf("Vala cleek() has run!\n");
      this._col = {0,255,0}; //Just change the colour
      this.redraw("from Vala");
      //return true; //Stops the signal here. Python won't get it.
      return false; //Lets the signal carry on going (to Python).
    }

    //Draws the Cairo art to the canvas
    private bool drawme( Cairo.Context ctx, int w, int h) {
      stdout.printf("drawme test.\n");
      ctx.set_source_rgb(this._col[0],this._col[1],this._col[2]);
      ctx.rectangle(0,0,300,300);
      ctx.fill();
      return true;
    }

    //Redraw - forces invalidate which trips the draw event
    //Am gonna call this directly from Python too!
    public void redraw(string? thing) {
      thing = thing ?? "from null"; //tests for null or else
      stdout.printf( "redraw test %s.\n", thing );

      this._canvas.invalidate();
    }
    } //end RedSquare class
} //end namespace

test.py

​​>
#!/usr/bin/env python3

"""
Tests the instance of our Vala actor.

I expect to see a red square on the white stage.
(It can be clicked.)

"""

import sys
from gi.repository import Palelib, Clutter

Clutter.init(sys.argv)
stage = Clutter.Stage()
stage.set_size(800, 400)
stage.set_title("Blah blah")
stage.connect('destroy', lambda x: Clutter.main_quit() )


# Make our Object:
rs = Palelib.RedSquare.new() #Note the .new() call. Yuck.
print(rs)
#print(dir(rs)) # See that it is an Actor object.

rs.set_position(100,100)

stage.add_child(rs)

#Force rs to appear. Calls a Vala method and passes a string.
rs.redraw("from Python")

"""
# Crud for testing:
r1 = Clutter.Rectangle()
r1.set_size(50,50)
r1.set_position(0,0)
damnweird = Clutter.Color.new(0,0,0,255)
r1.set_color( damnweird  )

stage.add_child(r1)
"""



"""
Let's get an event going from Python!
Because the RedSquare actor is *already* listening
to a button-press-event (in Vala) this is the second 
such event it will obey. 

I *think* it happens after the vala cleek() method runs.
If you |return true| in cleek(), then this does NOT run,
so that implies that Python is happening second in the chain.
"""
def gogo( a, evt ):
  print ("Hello from gogo. %s %s" % (a,evt))
rs.connect("button_press_event", gogo)



stage.show_all()
Clutter.main()

【讨论】:

  • 希望这是合法的。我有一个问题。整个 Clutter 库加载到 RAM 中多少次?我在 Python 中启动它,但我也在我的 .so 文件中启动它吗?即,Clutter 库及其所有关系是否加载一次或两次?
猜你喜欢
  • 1970-01-01
  • 2018-08-07
  • 1970-01-01
  • 2013-11-16
  • 2016-10-18
  • 2011-06-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多