开罗:: SolidPattern不是GooCanvas2 :: CairoPattern类型的

问题描述

我正在尝试将旧的Gtk2 perl脚本转换为Gtk3。这是Gtk2版本的样子:

#!/usr/bin/perl

use 5.30.0;
use strict;
use warnings;
use diagnostics;

use Gtk2 '-init';
use Goo::Canvas;

my $canvas = Goo::Canvas->new;
my $pattern = Cairo::SolidPattern->create_rgba(0,0);
$pattern = Goo::Cairo::Pattern->new($pattern);

my $rect = Goo::Canvas::Rect->new(
    $canvas->get_root_item,100,'fill-pattern' => $pattern,'line-dash'    => Goo::Canvas::LineDash->new([5,5]),'line-width'   => 1,'stroke-color' => 'black',);

这是我的Gtk3尝试:

#!/usr/bin/perl

use 5.30.0;
use strict;
use warnings;
use diagnostics;

use Gtk3 '-init';
use goocanvas2;

my $canvas = goocanvas2::Canvas->new;
my $pattern = Cairo::SolidPattern->create_rgba(0,0);

my $rect = goocanvas2::CanvasRect->new(
    parent => $canvas->get_root_item,x => 0,y => 0,width => 100,height => 100,'line-dash'    => goocanvas2::CanvasLineDash->newv([5,);

但这会导致错误

Uncaught exception from user code:
    Cairo::SolidPattern=SCALAR(0x558de4acb260) is not of type goocanvas2::CairoPattern at /usr/lib64/perl5/vendor_perl/5.30.1/x86_64-linux/Glib.pm line 222.
    Glib::Object::_LazyLoader::AUTOLOAD("goocanvas2::CanvasRect","parent",goocanvas2::CanvasGroup=HASH(0x558de4abe1a0),"x","y","width",...) called at test.pl line 14

我还尝试插入$pattern = goocanvas2::CairoPattern->new($pattern);,但这没有帮助:

Uncaught exception from user code:
    Could not fetch information for package goocanvas2::CairoPattern; perhaps it has not been loaded via Glib::Object::Introspection? at test.pl line 13.

但是查看goocanvas2.pm的来源,它确实通过Glib :: Object :: Introspection加载了goocanvas2

任何建议如何解决此问题?

解决方法

我尝试在Ubuntu 20.04上安装libgoocanvas-2.0-dev,并且它为/usr/share/gir-1.0/GooCanvas-2.0.gir安装GooCanvas的内省XML文件。在此文件中,我看到了GooCanvas2::CanvasRect->new()的绑定定义:

<class name="CanvasRect"
       c:symbol-prefix="canvas_rect"
       c:type="GooCanvasRect"
       parent="CanvasItemSimple"
       glib:type-name="GooCanvasRect"
       glib:get-type="goo_canvas_rect_get_type"
       glib:type-struct="CanvasRectClass">
  <implements name="CanvasItem"/>
  <function name="new"
            c:identifier="goo_canvas_rect_new"
            introspectable="0">
    <return-value transfer-ownership="full">
      <type name="CanvasItem" c:type="GooCanvasItem*"/>
    </return-value>
    <parameters>
      <parameter name="parent" transfer-ownership="none" skip="1">
        <type name="CanvasItem" c:type="GooCanvasItem*"/>
      </parameter>
      <parameter name="x" transfer-ownership="none">
        <type name="gdouble" c:type="gdouble"/>
      </parameter>
      <parameter name="y" transfer-ownership="none">
        <type name="gdouble" c:type="gdouble"/>
      </parameter>
      <parameter name="width" transfer-ownership="none">
        <type name="gdouble" c:type="gdouble"/>
      </parameter>
      <parameter name="height" transfer-ownership="none">
        <type name="gdouble" c:type="gdouble"/>
      </parameter>
      <parameter name="..." transfer-ownership="none">
        <varargs/>
      </parameter>
    </parameters>
  </function>

我注意到fill-pattern参数的定义可能包含在最后一个name="..."参数包中。因此尚不清楚参数应为哪种类型。但是文件的后面可能有一个线索,在第244行,我们有:

<glib:boxed glib:name="CairoPattern"
            c:symbol-prefix="cairo_pattern"
            glib:type-name="GooCairoPattern"
            glib:get-type="goo_cairo_pattern_get_type">
</glib:boxed>

我不确定glib:boxed的确切含义,但是根据Glib::Object::Introspection的文档:

类,接口以及盒装和基本类型都有自己的类型 在某种程度上,名称空间是因为GType的概念是完全 在Perl绑定中替换为Perl软件包名称。

因此boxed类型在Perl中获得了自己的名称空间。有关盒装类型here的更多信息。

错误消息:

Cairo::SolidPattern=SCALAR(0x55a027382d18) is not of type GooCanvas2::CairoPattern ...

表示它期望使用GooCanvas2::CairoPattern类型,但是当我尝试使用这种类型时,例如

my $pattern = GooCanvas2::CairoPattern->new();

我收到错误消息:

Could not fetch information for package GooCanvas2::CairoPattern; perhaps it has not been loaded via Glib::Object::Introspection?

更新

以下C程序运行正常,表明该模式应为cairo_pattern_t类型:

#include <gtk/gtk.h>
#include <goocanvas.h>

static gboolean
on_delete_event (GtkWidget *window,GdkEvent  *event,gpointer   unused_data)
{
    exit (0);
}

int main(int argc,char *argv[]) {
    gtk_init (&argc,&argv);
    GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    gtk_window_set_default_size (GTK_WINDOW (window),640,600);
    g_signal_connect (window,"delete_event",G_CALLBACK (on_delete_event),NULL);
    GtkWidget *scrolled_win = gtk_scrolled_window_new (NULL,NULL);
    gtk_container_add (GTK_CONTAINER (window),scrolled_win);
    GtkWidget *canvas = goo_canvas_new();
    goo_canvas_set_bounds (GOO_CANVAS (canvas),1000,1000);
    GooCanvasItem *root = goo_canvas_get_root_item (GOO_CANVAS (canvas));
    cairo_pattern_t *pattern = cairo_pattern_create_rgba( 0.0,0.0,1.0,0.5 );
    GooCanvasItem *rect = goo_canvas_rect_new(
        root,100,"line-width","stroke-color","black","fill-pattern",pattern,NULL
    );
    gtk_widget_set_size_request (canvas,600,450);
    gtk_container_add (GTK_CONTAINER (scrolled_win),canvas);
    gtk_widget_show_all(window);
    gtk_main ();
    return 0;
}

更新2

更多调试信息:GooCanvas2::CanvasRect->new()中的呼叫GObject.xs被重定向到line 1327

SV *
g_object_new (class,...)
   // ...

line 1359处找到属性参数fill-pattern的期望类型。看起来这是类型G_TYPE_BOXED。然后在line 1378

gperl_value_from_sv (&params[i].value,ST (FIRST_ARG+i*2+1));

它尝试从提供的Perl参数(类型为Cairo::SolidPattern)中检索装箱的值,该值导致line 136

    case G_TYPE_BOXED:
        /* SVs need special treatment! */
        if (G_VALUE_HOLDS (value,GPERL_TYPE_SV)) {
            g_value_set_boxed (value,gperl_sv_is_defined (sv)
                               ? sv : NULL);
        } else {
            g_value_set_static_boxed (
                value,gperl_get_boxed_check (
                    sv,G_VALUE_TYPE(value)));
        }

第一次检查失败,因此进入第二个替代项g_value_set_static_boxed(),该替代项首先调用gperl_get_boxed_check(),请参见GBoxed.xs中的line 558。在第568行

boxed_info = g_hash_table_lookup (info_by_gtype,(gpointer) gtype);

boxed_info作为BoxedInfo *的返回内容

{
  gtype = 93825018188384,package = 0x555556e4e7a0 "GooCanvas2::CairoPattern",wrapper_class = 0x0
}

并且在第575行unwrap设置为_default_wrapper_class.unwrap并在第583行:

return (*unwrap) (gtype,boxed_info->package,sv);

它将在line 420处调用default_boxed_unwrap()

在第429行嘶哑:

if (!sv_derived_from (sv,package))
    croak ("%s is not of type %s",gperl_format_variable_for_output (sv),package);

因为Cairo::SolidPattern并非来自GooCanvas2::CairoPattern

更新3

GooCanvas's source,它为模式定义了多个设置器/获取器:fill-colorfill-color-rgbafill-color-gdk-rgbafill-pixbuffill-pattern ,所有这些都在内部设置/获取相同的属性goo_canvas_style_fill_pattern_id。并且其他设置者不存在对cairo_pattern_t使用错误的自省包装器的问题。因此,这可行:

my $rect = GooCanvas2::CanvasRect->new(
  ...
  'fill-color-gdk-rgba' => Gtk3::Gdk::RGBA::parse('red'),);

此外,在构建$rect之后,我们可以通过GooCanvas2::CairoPattern从中获取$rect->get('fill-pattern')

这不允许使用从开罗创建的其他图案(线性等),但是至少纯色可以通过提供任意RGBA起作用,并且pixbuf setter应该足以满足其他需求。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...