使用 Vala 自定义 GTK 小部件
Custom GTK widget with Vala
我正在尝试使用 Vala 创建一个简单的自定义 GTK 小部件:
public class PageView : Gtk.Widget {
public PageView () {
//base ();
set_name ("pageview");
set_has_window (true);
}
/*
* Method and Signal Overrides
*/
public override Gtk.SizeRequestMode get_request_mode () {
return Gtk.SizeRequestMode.CONSTANT_SIZE;
// Don’t trade height-for-width or width-for-height
}
public override void get_preferred_width
(out int minimum,
out int natural) {
stdout.printf ("PageView#get_preferred_width\n");
minimum = natural = pg_pixel_width;
}
public override void get_preferred_height
(out int minimum,
out int natural) {
stdout.printf ("PageView#get_preferred_height\n");
minimum = natural = pg_pixel_height;
}
public override void get_preferred_width_for_height
( int height,
out int minimum,
out int natural) {
stdout.printf ("PageView#get_preferred_width_for_height\n");
minimum = natural = pg_pixel_width;
}
public override void get_preferred_height_for_width
( int width,
out int minimum,
out int natural) {
stdout.printf ("PageView#get_preferred_height_for_width\n");
minimum = natural = pg_pixel_height;
}
public override void size_allocate (Gtk.Allocation alloc) {
stdout.printf ("PageView#size_allocate\n");
set_allocation (alloc);
if (get_window() != null) {
get_window().move_resize (
alloc.x, alloc.y, alloc.width, alloc.height);
}
}
public override void realize () {
stdout.printf ("PageView#realize\n");
set_realized (true);
if (get_window() == null) {
Gtk.Allocation allocation;
get_allocation (out allocation);
_window_attr = Gdk.WindowAttr () {
x = allocation.x,
y = allocation.y,
width = allocation.width,
height = allocation.height,
event_mask = get_events() | Gdk.EventMask.EXPOSURE_MASK,
window_type = Gdk.WindowType.CHILD,
wclass = Gdk.WindowWindowClass.INPUT_OUTPUT
};
_window_attr_type = Gdk.WindowAttributesType.X |
Gdk.WindowAttributesType.Y;
_window = new Gdk.Window (
get_parent_window (), _window_attr, _window_attr_type);
set_window (_window);
}
}
public override void unrealize () {
stdout.printf ("PageView#unrealize\n");
}
public override bool draw (Cairo.Context cr) {
stdout.printf ("PageView#draw\n");
Gtk.Allocation allocation;
get_allocation (out allocation);
get_style_context () .render_background (cr,
allocation.x, allocation.y,
allocation.width, allocation.height);
cr.save ();
cr.scale (allocation.width, allocation.height);
cr.set_source_rgba (255, 255, 0, 1.0);
cr.set_line_width (10);
cr.line_to (1, 1);
cr.stroke ();
cr.restore ();
return true;
}
/*
* Public Attributes
*/
public int pg_pixel_width {
get { return 480; }
}
public int pg_pixel_height {
get { return 480; }
}
/*
* Private Members
*/
private Gdk.Window _window;
private Gdk.WindowAttr _window_attr;
private Gdk.WindowAttributesType _window_attr_type;
}
问题是,当我将它添加到我的主 Gtk.Window 时,我遇到了分段错误。这些是我得到的调试信息:
PageView#get_preferred_height
PageView#get_preferred_width
PageView#size_allocate
PageView#realize
PageView#get_preferred_height
PageView#get_preferred_width
PageView#size_allocate
PageView#size_allocate
Segmentation fault (core dumped)
看来如果我把realize ()
里面的set_window (_window)
的调用改成set_window(null)
,或者如果我把一个空父window传给新创建的Gdk.Window,应用程序在没有分段错误的情况下运行(但在任何一种情况下都不会像预期的那样显示小部件)。我主要跟随 this example 来实现虚拟方法并尝试在 Vala 中移植 C 代码。问题的原因可能是什么?
这里有几个建议:
使用 GDB/Nemvier/Builder 调试崩溃的应用程序以找出问题所在。我使用以下命令行调试 vala/gtk 个应用程序:
G_DEBUG=致命警告 gdb path/to/executable
使用内置的 GTK 功能而不是重新发明它。如果你想让一个小部件成为一个特定的大小,使用Gtk.Widget.set_size_request()
,你将不需要上面90%的代码。要实现自定义绘图,请创建一个 Gtk.DrawingArea,连接到绘图信号,实现它,然后就完成了。
最后我在构造函数中去掉了set_has_window(true)
,只实现了draw()
信号。这似乎已经成功了!下面是工作代码段:
public class PageView : Gtk.Widget {
public PageView () {
set_name ("pageview");
}
/*
* Method and Signal Overrides
*/
public override Gtk.SizeRequestMode get_request_mode () {
return Gtk.SizeRequestMode.CONSTANT_SIZE;
// Don’t trade height-for-width or width-for-height
}
public override void get_preferred_width
(out int minimum,
out int natural) {
stdout.printf ("PageView#get_preferred_width\n");
minimum = natural = pg_pixel_width;
}
public override void get_preferred_height
(out int minimum,
out int natural) {
stdout.printf ("PageView#get_preferred_height\n");
minimum = natural = pg_pixel_height;
}
public override void size_allocate (Gtk.Allocation alloc) {
stdout.printf ("PageView#size_allocate\n");
base.size_allocate (alloc);
}
public override void realize () {
stdout.printf ("PageView#realize\n");
base.realize ();
}
public override void unrealize () {
stdout.printf ("PageView#unrealize\n");
base.unrealize ();
}
public override bool draw (Cairo.Context cr) {
stdout.printf ("PageView#draw\n");
Gtk.Allocation allocation;
get_allocation (out allocation);
cr.set_line_width (1);
cr.set_source_rgba (255, 255, 0, 1);
cr.save ();
cr.scale (allocation.width, allocation.height);
cr.move_to (0, 0);
cr.line_to (1, 1);
cr.restore ();
cr.stroke ();
return false;
}
...
}
我正在尝试使用 Vala 创建一个简单的自定义 GTK 小部件:
public class PageView : Gtk.Widget {
public PageView () {
//base ();
set_name ("pageview");
set_has_window (true);
}
/*
* Method and Signal Overrides
*/
public override Gtk.SizeRequestMode get_request_mode () {
return Gtk.SizeRequestMode.CONSTANT_SIZE;
// Don’t trade height-for-width or width-for-height
}
public override void get_preferred_width
(out int minimum,
out int natural) {
stdout.printf ("PageView#get_preferred_width\n");
minimum = natural = pg_pixel_width;
}
public override void get_preferred_height
(out int minimum,
out int natural) {
stdout.printf ("PageView#get_preferred_height\n");
minimum = natural = pg_pixel_height;
}
public override void get_preferred_width_for_height
( int height,
out int minimum,
out int natural) {
stdout.printf ("PageView#get_preferred_width_for_height\n");
minimum = natural = pg_pixel_width;
}
public override void get_preferred_height_for_width
( int width,
out int minimum,
out int natural) {
stdout.printf ("PageView#get_preferred_height_for_width\n");
minimum = natural = pg_pixel_height;
}
public override void size_allocate (Gtk.Allocation alloc) {
stdout.printf ("PageView#size_allocate\n");
set_allocation (alloc);
if (get_window() != null) {
get_window().move_resize (
alloc.x, alloc.y, alloc.width, alloc.height);
}
}
public override void realize () {
stdout.printf ("PageView#realize\n");
set_realized (true);
if (get_window() == null) {
Gtk.Allocation allocation;
get_allocation (out allocation);
_window_attr = Gdk.WindowAttr () {
x = allocation.x,
y = allocation.y,
width = allocation.width,
height = allocation.height,
event_mask = get_events() | Gdk.EventMask.EXPOSURE_MASK,
window_type = Gdk.WindowType.CHILD,
wclass = Gdk.WindowWindowClass.INPUT_OUTPUT
};
_window_attr_type = Gdk.WindowAttributesType.X |
Gdk.WindowAttributesType.Y;
_window = new Gdk.Window (
get_parent_window (), _window_attr, _window_attr_type);
set_window (_window);
}
}
public override void unrealize () {
stdout.printf ("PageView#unrealize\n");
}
public override bool draw (Cairo.Context cr) {
stdout.printf ("PageView#draw\n");
Gtk.Allocation allocation;
get_allocation (out allocation);
get_style_context () .render_background (cr,
allocation.x, allocation.y,
allocation.width, allocation.height);
cr.save ();
cr.scale (allocation.width, allocation.height);
cr.set_source_rgba (255, 255, 0, 1.0);
cr.set_line_width (10);
cr.line_to (1, 1);
cr.stroke ();
cr.restore ();
return true;
}
/*
* Public Attributes
*/
public int pg_pixel_width {
get { return 480; }
}
public int pg_pixel_height {
get { return 480; }
}
/*
* Private Members
*/
private Gdk.Window _window;
private Gdk.WindowAttr _window_attr;
private Gdk.WindowAttributesType _window_attr_type;
}
问题是,当我将它添加到我的主 Gtk.Window 时,我遇到了分段错误。这些是我得到的调试信息:
PageView#get_preferred_height
PageView#get_preferred_width
PageView#size_allocate
PageView#realize
PageView#get_preferred_height
PageView#get_preferred_width
PageView#size_allocate
PageView#size_allocate
Segmentation fault (core dumped)
看来如果我把realize ()
里面的set_window (_window)
的调用改成set_window(null)
,或者如果我把一个空父window传给新创建的Gdk.Window,应用程序在没有分段错误的情况下运行(但在任何一种情况下都不会像预期的那样显示小部件)。我主要跟随 this example 来实现虚拟方法并尝试在 Vala 中移植 C 代码。问题的原因可能是什么?
这里有几个建议:
使用 GDB/Nemvier/Builder 调试崩溃的应用程序以找出问题所在。我使用以下命令行调试 vala/gtk 个应用程序:
G_DEBUG=致命警告 gdb path/to/executable
使用内置的 GTK 功能而不是重新发明它。如果你想让一个小部件成为一个特定的大小,使用
Gtk.Widget.set_size_request()
,你将不需要上面90%的代码。要实现自定义绘图,请创建一个 Gtk.DrawingArea,连接到绘图信号,实现它,然后就完成了。
最后我在构造函数中去掉了set_has_window(true)
,只实现了draw()
信号。这似乎已经成功了!下面是工作代码段:
public class PageView : Gtk.Widget {
public PageView () {
set_name ("pageview");
}
/*
* Method and Signal Overrides
*/
public override Gtk.SizeRequestMode get_request_mode () {
return Gtk.SizeRequestMode.CONSTANT_SIZE;
// Don’t trade height-for-width or width-for-height
}
public override void get_preferred_width
(out int minimum,
out int natural) {
stdout.printf ("PageView#get_preferred_width\n");
minimum = natural = pg_pixel_width;
}
public override void get_preferred_height
(out int minimum,
out int natural) {
stdout.printf ("PageView#get_preferred_height\n");
minimum = natural = pg_pixel_height;
}
public override void size_allocate (Gtk.Allocation alloc) {
stdout.printf ("PageView#size_allocate\n");
base.size_allocate (alloc);
}
public override void realize () {
stdout.printf ("PageView#realize\n");
base.realize ();
}
public override void unrealize () {
stdout.printf ("PageView#unrealize\n");
base.unrealize ();
}
public override bool draw (Cairo.Context cr) {
stdout.printf ("PageView#draw\n");
Gtk.Allocation allocation;
get_allocation (out allocation);
cr.set_line_width (1);
cr.set_source_rgba (255, 255, 0, 1);
cr.save ();
cr.scale (allocation.width, allocation.height);
cr.move_to (0, 0);
cr.line_to (1, 1);
cr.restore ();
cr.stroke ();
return false;
}
...
}