我在C中为GTK + 3制作了一个简单的自定义小部件,名为AwLed,并将其添加到自定义Glade目录中。它在Glade内部或使用aw_led_new()函数创建时可以正常工作。 但是,当我创建一个加载Glade文件并显示其小部件的简单程序(在主窗口小部件上调用show_all())时,自定义小部件不会显示自己。 我添加了一些printf-fflushs来调试,发现函数Realize,Allocate甚至都没有被调用。看起来整个共享库似乎没有被加载。
现在,除了用GtkBuilder加载小部件之外,Glade还做了什么?为什么忽略这些小部件?我想写一些样板来实现GtkBuildable接口吗?
非常感谢任何帮助。
awled.c
#include <gtk/gtk.h>
#include "awled.h"
enum {
PROP_0,
PROP_ACTIVE,
};
static void aw_led_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec);
static void aw_led_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec);
static void aw_led_realize (GtkWidget *widget);
static void aw_led_unrealize (GtkWidget *widget);
static void aw_led_map (GtkWidget *widget);
static void aw_led_unmap (GtkWidget *widget);
static void aw_led_size_allocate (GtkWidget *widget,
GtkAllocation *allocation);
static void aw_led_get_preferred_width (GtkWidget *widget,
gint *minimal_width,
gint *natural_width);
static void aw_led_get_preferred_height (GtkWidget *widget,
gint *minimal_height,
gint *natural_height);
static gboolean aw_led_draw (GtkWidget *widget,
cairo_t *cr);
G_DEFINE_TYPE (AwLed, aw_led, GTK_TYPE_WIDGET)
#define parent_class aw_led_parent_class
static void
aw_led_class_init (AwLedClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->set_property = aw_led_set_property;
object_class->get_property = aw_led_get_property;
widget_class->realize = aw_led_realize;
widget_class->unrealize = aw_led_unrealize;
widget_class->map = aw_led_map;
widget_class->unmap = aw_led_unmap;
widget_class->size_allocate = aw_led_size_allocate;
widget_class->get_preferred_width = aw_led_get_preferred_width;
widget_class->get_preferred_height = aw_led_get_preferred_height;
widget_class->draw = aw_led_draw;
GParamSpec* param_spec;
param_spec = g_param_spec_boolean ("active", "Active", "LED State",
FALSE, G_PARAM_READWRITE);
g_object_class_install_property (object_class, PROP_ACTIVE, param_spec);
}
static void
aw_led_init (AwLed *led)
{
gtk_widget_set_has_window (GTK_WIDGET (led), FALSE);
led->state = FALSE;
led->color_on.red = 0.0;
led->color_on.green = 0.6;
led->color_on.blue = 0.0;
led->color_on.alpha = 1.0;
led->color_off.red = 0.6;
led->color_off.green = 0.0;
led->color_off.blue = 0.0;
led->color_off.alpha = 1.0;
/*priv->backing_store = NULL; //what?? needed?
priv->backing_store_valid = FALSE;
priv->pos_redraw_idle_id = 0;*/
}
static void
aw_led_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
AwLed *led = AW_LED (object);
switch (prop_id)
{
case PROP_ACTIVE:
led->state = g_value_get_boolean (value);
gtk_widget_queue_resize (GTK_WIDGET (led));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
aw_led_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
AwLed *led = AW_LED (object);
switch (prop_id)
{
case PROP_ACTIVE:
g_value_set_boolean (value, led->state);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
GtkWidget *
aw_led_new ()
{
return g_object_new (AW_TYPE_LED,
"active", FALSE,
NULL);
}
static void
aw_led_realize (GtkWidget *widget)
{
AwLed *led = AW_LED (widget);
GtkAllocation allocation;
GdkWindowAttr attributes;
gint attributes_mask;
GTK_WIDGET_CLASS (aw_led_parent_class)->realize (widget);
gtk_widget_get_allocation (widget, &allocation);
attributes.window_type = GDK_WINDOW_CHILD;
attributes.x = allocation.x;
attributes.y = allocation.y;
attributes.width = allocation.width;
attributes.height = allocation.height;
attributes.wclass = GDK_INPUT_ONLY;
attributes.event_mask = (gtk_widget_get_events (widget) |
GDK_EXPOSURE_MASK);
attributes_mask = GDK_WA_X | GDK_WA_Y;
led->input_window = gdk_window_new (gtk_widget_get_window (widget),
&attributes, attributes_mask);
gdk_window_set_user_data (led->input_window, led);
}
static void
aw_led_unrealize (GtkWidget *widget)
{
AwLed *led = AW_LED (widget);
if (led->input_window) {
gdk_window_destroy (led->input_window);
led->input_window = NULL;
}
GTK_WIDGET_CLASS (aw_led_parent_class)->unrealize (widget);
}
static void
aw_led_map (GtkWidget *widget)
{
AwLed *led = AW_LED (widget);
GTK_WIDGET_CLASS (parent_class)->map (widget);
if (led->input_window)
gdk_window_show (led->input_window);
}
static void
aw_led_unmap (GtkWidget *widget)
{
AwLed *led = AW_LED (widget);
if (led->input_window)
gdk_window_hide (led->input_window);
GTK_WIDGET_CLASS (parent_class)->unmap (widget);
}
static void
aw_led_size_allocate (GtkWidget *widget,
GtkAllocation *allocation)
{
AwLed *led = AW_LED (widget);
gtk_widget_set_allocation (widget, allocation);
if (gtk_widget_get_realized (widget)) {
gdk_window_move_resize (led->input_window,
allocation->x, allocation->y,
allocation->width, allocation->height);
}
}
static void
aw_led_get_preferred_width (GtkWidget *widget,
gint *minimal_width,
gint *natural_width)
{
*minimal_width = 20;
*natural_width = 35;
}
static void
aw_led_get_preferred_height (GtkWidget *widget,
gint *minimal_height,
gint *natural_height)
{
*minimal_height = 20;
*natural_height = 35;
}
static gboolean
aw_led_draw (GtkWidget *widget,
cairo_t *cr)
{
gint width, height;
AwLed* led = AW_LED(widget);
width = gtk_widget_get_allocated_width (widget);
height = gtk_widget_get_allocated_height (widget);
GdkRGBA color = (led->state) ? led->color_on : led->color_off;
cairo_arc (cr, width / 2.0, height / 2.0,
MIN (width, height) / 2.0, 0, 2 * G_PI);
gdk_cairo_set_source_rgba (cr, &color);
cairo_fill (cr);
return TRUE;
}
awled.h
#ifndef __AW_LED_H__
#define __AW_LED_H__
#include <gtk/gtk.h>
G_BEGIN_DECLS
#define AW_TYPE_LED (aw_led_get_type ())
#define AW_LED(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), AW_TYPE_LED, AwLed))
#define AW_LED_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), AW_TYPE_LED, AwLedClass))
#define AW_IS_LED(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), AW_TYPE_LED))
#define AW_IS_LED_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), AW_TYPE_LED))
#define AW_LED_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), AW_TYPE_LED, AwLedClass))
typedef struct _AwLed AwLed;
typedef struct _AwLedClass AwLedClass;
typedef enum {
OVAL,
RECTANGULAR
} AwLedShape;
struct _AwLed {
GtkWidget parent_instance;
//public members
//@TODO Move these to .C file (AwLedPrivate structure)
GdkRGBA color_on;
GdkRGBA color_off;
AwLedShape shape;
gboolean state;
GdkWindow *input_window;
};
struct _AwLedClass {
GtkWidgetClass parent_class;
};
GType aw_led_get_type (void) G_GNUC_CONST;
GtkWidget* aw_led_new ();
gboolean aw_led_get_state (AwLed* led);
void aw_led_set_state (AwLed* led, gboolean state);
G_END_DECLS
#endif /* __AW_LED_H__ */
test_builder.c
#include <gtk/gtk.h>
#include <awled.h>
int main(int argc, char* argv[]) {
GtkBuilder* builder;
GtkWidget *window, *led, *led2, *box;
gtk_init(&argc, &argv);
builder = gtk_builder_new();
gtk_builder_add_from_file(builder, "interface.ui", NULL);
window = (GtkWidget*) gtk_builder_get_object(builder, "window1");
led = (GtkWidget*) gtk_builder_get_object(builder, "led1");
box = (GtkWidget*) gtk_builder_get_object(builder, "box1");
//weird... if I create only one this way, all of them show themselves!
//led2 = aw_led_new();
//gtk_box_pack_end(GTK_BOX(box), led2, 0, 0, 0);
gtk_widget_show_all(window);
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
gtk_main();
}