[ZT] Creating your OWN GTK + WIDGET & Adding It to Glade Palette

zhaozj2021-02-16  95

http://wingtk.sourceforge.net/ishan/widget.html

Creating Your OWN GTK Widget & Adding It to Glade Palette

Tutorial by: ishan chattopadhyaya

Introduction

In this tutorial we would be creating a new GTK widget (based upon GDK) and be adding it to the Glade Palette so that you can use the widget you created in your own GTK programs that you create with Glade. For this tutorial we would create A Simple Widget That Works AS A Clock and Call IT GTKClock (See Figure 1).

Figure 1: The gtkclock widget

Figure 2: The final result

The Create We Would Be Writing To Create The Widget Would Be GTK 2.0. We would be adding the widget to glade version> = 1.1.2. For this tutorial, i Have Used Glade-2.0.0, The Latest That IS. Nevertheless , I am very sure that only with a minor changes to the code, the same thing can be achieved with GTK 1.2 and Glade 0.6.4 as well Glade can be downloaded from:. GLADE-FTP-site Figure 2 shows our widget in. The Glade's Palette Window.

Creating the new widget: What is gtk widget factory

The new widget, GtkClock, would consist of two files, viz. Gtkclock.c & gtkclock.h. Whatever code required to make the widget, goes into these files. Writing these files entirely from scratch might be difficult in the beginning, esp. if one does not have enough experience of creating widgets. So, in order to simplify things, a very neat tool, GTK Widget Factory (GWF), can be used to create the framework inside these two files, upon which the entire widget can BUILT. GWF CAN Be Found Here (Win32 Version of GWF IS Here).

Even if you decide not to use GWF, then also you can follow this tutorial and achieve your goal All you need to do in that case would be to use the files that GWF outputs from here:. Gtkclock-initial.c & gtkclock-initial .h.figure 3: GTK Widget Factory

BUILDING The Widget Files: gtkclock.c & gtkclock.h

Create a directory, e.g. / home / / GtkClockOpen up GWF. Fill in the details regarding your widget, save your project and build the files (write source). Save the project in the above directory.

For the Parent and Parent Include, I Found Out That WhatVer You Supply, It Doesn't Reflect Anything Upon The Generated Files. So Just Go Ahead and Fill in Whatver you want.

Editing the gtkclock.c & gtkclock.h Files

First Of All, Open the gtkclock.h File (That GWF generate) and Find the Following Part of The Code (BEFORE MAKING CHANGES):

Filename: gtkclock.h

Before making changes ... 1: guint gtk_clock_get_type (void); 2: GtkClock * gtk_clock_new (void); 3: void gtk_clock_construct (GtkClock * clock); ... After making changes ... 1: guint gtk_clock_get_type (void); 2: gtkwidget * gtk_clock_new (void); 3: Void gtk_clock_construct (gtkclock * clock); ...

Now change the 'GtkClock * gtk_clock_new (void)' to 'GtkWidget * gtk_clock_new (void)' in line 2. This has to be done so as to conform to GTK standards. This function is defined in gtkclock.c and thus changes have to BE Made to the definition as well. so, open the file and make the following changes to the gtk_clock_new () function.

Filename: gtkclock.c

Before Making ChangeSgtkClock * gtk_clock_new (void) {gtkclock * clock; clock = gtk_clock (gtk_type_new (gtk_clock_get_type ()));

GTK_CLOCK_CONSTRUCT (CLOCK);

Return clock;

After Making Changes1: gtkwidget * 2: gtk_clock_new (void) 3: {4: gtkwidget * clock; 5: clock = gtk_type_new (gtk_clock_get_type ()); 6: // gtk_clock_construct (clock);

7: Return Clock;

8: }

This function, gtk_clock_new () is called when a new object of GtkClock widget class is created. It returns the type of GtkClock. Here, we've commented out line 6 because we do not want to construct the clock through this function. We would Call this function at a through noother function That is executed when widget is initialised.

Now, We would be adding the data members to the gtkclock class. For a clock class, it is obvious what The data members be Hour, min and sec. So, in the header file (gtkclock.h), add these items to the Struct_gtkclock:

Filename: gtkclock.h

BEFORE MAKING CHANGESTYPEDEF STRUCT _GTKCLOCK GTKCLOCK ;TYPEF STRUCT _GTKCLOCKCLASS GTKCLOCKCLASS; STRUCT _GTKCLOCK

{

GTKWIDGET PARENT;

}; After makeking change _gtkclock gtkclock; 2: typedf struct _gtkclockclass gtkclockclass; 3: struct _gtkclock

4: {

5: gtkwidget parent;

6: Int Hour; // Value of Hours Is Stored Here

7: Int min; // value of minutes is stored here

8: Int sec; // value of seconds is stored here

9: };

. Let's now focus on to drawing part of the widget Before drawing the widget onto the screen, first of all, a default size has to be allocated to widget's drawing area Our function for this would be:. Gtk_clock_size_request () Of course, the. user / app developer can resize the widget after instantiating it. The subsequent gtk_clock_realize () function is for creating the drawing area while taking the allocated size of the widget into consideration.

Here's the code for the gtk_clock_size_request () and gtk_clock_realize () filename: gtkclock.c

New functions added (in any suitable place you like) / * add these prototypes somewhere in the beginning of the file * /

1: Static void gtk_clock_size_request (gtkwidget * widget, gtkrequisition * req);

2: static void gtk_clock_realize (gtkwidget * widget);

.....

..... 3: static void gtk_clock_size_request (gtkwidget * widget, gtkrequisition * req) 4: {5: Req-> width = 200; // default value6: Req-> height = 200; // default value7:} 8 : static void gtk_clock_realize (gtkwidget * widget)

9: {

10: gtkclock * Drawing_area;

11: gdkwindowattr attributes;

12: Gint Attributes_mask; 13: g_return_if_fail (widget! = Null);

14: g_return_if_fail (gtk_is_clock (widget)); 15: Drawing_Area = GTK_Clock (Widget);

16: gtk_widget_set_flags (widget, gtk_realized); 17: attributes.window_type = gdk_window_child;

18: attributes.x = widget-> allocation.x;

19: attributes.y = widget-> allocation.y;

20: attributes.width = widget-> allocation.width;

30: attributes.height = widget-> allocation.height;

31: attributes.wclass = GDK_INPUT_OUTPUT;

32: attributes.visual = gtk_widget_get_visual (widget);

33: attributes.colormap = gtk_widget_get_colormap (widget);

34: attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK; 35: attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; 36: widget-> window = gdk_window_new (gtk_widget_get_parent_window (widget),

& attributes, attributes_mask;

37: gdk_window_set_user_data (widget-> window, drawing_area); 38: widget-> style = gtk_style_attach (widget-> style, widget-> window); 39: gtk_style_set_background (widget-> style, widget-> window, GTK_STATE_NORMAL);

40:}

The size_request () Function is self-evlanatory. What the realize () Function Does is described as Follows:

Quoted from:. GTK 2.0 Tutorial "First, we have a function that does the work of creating the X window Notice that a mask is passed to the function gdk_window_new () which specifies which fields of the GdkWindowAttr structure actually have data in them (the remaining fields will be given default values). Also worth noting is the way the event mask of the widget is created. We call gtk_widget_get_events () to retrieve the event mask that the user has specified for this widget (with gtk_widget_set_events ()), and add the events that we are interested in ourselves. After creating the window, we set its style and background, and put a pointer to the widget in the user data field of the GdkWindow. This last step allows GTK to dispatch events for this window to The Correct Widget. "

Having written the functions for size requisition and realisation of the widget, we'll have to specify that, when instantiating the widgets, these functions should be used instead of the GtkWidget's default routines. For this, make the following changes to the gtk_clock_class_init () Function:

Filename: gtkclock.c

Before Making ChangesStatic voidgtk_clock_class_init (gtkclockclass * klass) {gtkobjectClass * Object_class;

Object_class = (gtkobjectclass *) klass;

Object_class-> destroy = gtk_clock_destroy;

PARENT_CLASS = GTK_TYPE_CLASS (gtk_widget_get_type ());

} After making changes1: static void2: gtk_clock_class_init (GtkClockClass * klass) 3: {4: GtkObjectClass * object_class; 5: GtkWidgetClass * widget_class; 6: object_class = (GtkObjectClass *) klass; 7: widget_class = (GtkWidgetClass *) klass; 8 : Object_class-> destroy = gtk_clock_destroy;

9: parent_class = gtk_type_class (gtk_widget_get_type ());

10: / * Overides the default methods * /

11: widget_class-> realize = gtk_clock_realize;

12: widget_class-> size_request = gtk_clock_size_request;

13:}

Now, we'll add one of the most important functions, gtk_clock_init (). This function is responsible for the initiation of the widget. In this function, we would be calling a function gtk_timeout_add () that would call the construct () function to build the clock. Since we want to have a real-time clock, we want the clock to be updated continuously. For this we'll use the gtk_timeout_add () function. It's 1st argument is the interval of time (in milliseconds) between each Call to the function (2nd argument) That Has To Be Executed, IE the gtk_clock_construct () Function In this case.

Filename: gtkclock.c

Update the following function1: static void2: gtk_clock_init (GtkClock * clock) 3: {4: / * Make the clock, refresh after every 1ms * / 5: gtk_timeout_add (1, gtk_clock_construct, (gpointer) (clock));

6:}

The gtk_timeout_add () function requires its 2nd argument to be a function with the following prototype: gint function (gpointer data); (Return value 0 to stop the function being executed, non-zero to continue the timeout)

It's thus clear that we should change the function declaration & definition for the gtk_clock_construct () function So, here's the complete function after having made the changes to its definition.Filename:. Gtkclock.c

Update The Following Function1: Gint2: GTK_Clock_Construct (GPOINTER DATA) 3: {4: gtkclock * clock = data;

5: / * if any problem Drawing, Stop The Timeout * /

6: If (! Gtk_widget_drawable (clock) Return 0; 7: / * Get the Time, And Store The Vals of Hour, Min, And Secs AS GTKClock Class Data * /

8: Get_current_time (& Clock-> Hour, & clock-> min, & clock-> sec);

9: / * Draw the clock * /

10: GTK_CLOCK_DRAW (gtk_widget (clock), null; 11: Return 1;

12:}

Now, here's the single most important function to draw the clock: gtk_clock_draw () It actually draws the clock on the drawing area that we initialised in the realize () function The main things that this draw () function does is..:

Initialise The Colors That Are To Be Used for The Hands of The Clock.get The Class Data, IE The Values ​​of Hour, Min, And Sec.Draw The Marks for the Minutes (in Multiples of 5) .get the coordinates of the minutes SECONDS & HOURS AND DRAW LINES from Center To Those Coordinates. These Lines Would Symbolise The Hands.

SO, CREATE The Function As Follows. Also, Remember To Add A Prototype of the Function in The Beginning of The Source File (gtkclock.c).

Filename: gtkclock.c

Add this prototype somewhere in the beginning of the file1: static void2: gtk_clock_draw (GtkWidget * widget, GdkRectangle * area); New functions added (in any suitable place you like) static voidgtk_clock_draw (GtkWidget * widget, GdkRectangle * area) {GtkClock * CLOCK; int loop1; // loop variable

Int max_radius; // maximum radius of the clockint min = 0, hour = 0, sec = 0; // Hours, Minutes & Seconds

Int Yc, Xc; // X-Coordinate & Y-Coordinate

INT Alloc_width, Alloc_Height; // Allocated Height & Width

GDKCOLOR Colors [4]; // Colors for the Hands

GDKGC * clock_gc = gdk_gc_new (widget-> window); // graphics context for Drawing in the hands if (gtk_widget_drawable (widget))

{

Clock = gtk_clock (widget); alloc_width = widget-> allocation.width - 1;

Alloc_height = widget-> allocation.height - 1; gdk_window_clear_area (widget-> window, 0, 0, alloc_width, alloc_height); / * Store the colors * /

GDK_COLOR_PARSE ("RED", & Colors [0]); // for minute's hand

GDK_COLOR_PARSE ("Darkgreen", & Colors [1]); // for Hour's Hand

GDK_COLOR_PARSE ("Royalblue", & Colors [2]); // for second's hand

GDK_COLOR_PARSE ("Black", & Colors [3]); / * get the value from the gtkclock class * /

MIN = clock-> min; hour = clock-> Hour; sec = clock-> sec;

/ * SET MAX_RADIUS with the lesser value betWeen Height or Width * /

MAX_RADIUS = (alloc_width

/ * Draw the 12 Points Which Signify THE MARKS in the clock * /

For (LOOP1 = 0; loop1 <60; loop1 = 5)

{

GTK_CLOCK_OBTAIN_COORDINATES (& XC, & YC, MAX_RADIUS, MAX_RADIUS, LOOP1, MAX_RADIUS-10, 60);

GDK_GC_SET_LINE_ATTRIBUTES (Clock_GC, 10, GDK_LINE_SOLID, 0, 0);

GDK_DRAW_LINE (Widget-> WINDOW, WIDGET-> Style-> Black_Gc, XC, YC, XC 1, YC 1);

GDK_DRAW_LINE (Widget-> Window, Widget-> Style-> Black_Gc, XC 1, YC, XC, YC 1);

}

/ * Set line width to 2 * /

GDK_GC_SET_LINE_ATTRIBUTES (Clock_GC, 2, GDK_LINE_SOLID, 0, 0); / * Obtain Coordinates for Minutes and Draw A line from center to That point * /

GTK_CLOCK_OBTAIN_COORDINATES (& XC, & YC, MAX_RADIUS, MAX_RADIUS, MIN, MAX_RADIUS, 60);

GDK_COLORMAP_ALLOC_COLOR (GDK_COLORMAP_GET_SYSTEM (), & Colors [0], False, true);

GDK_GC_SET_FOREGROUND (clock_gc, colors 0); / * red * /

GDK_DRAW_LINE (Widget-> WINDOW, Clock_GC, XC, YC, MAX_RADIUS, MAX_RADIUS);

/ * Obtain coordinates for Hour and draw a line from center to tryt * /

GTK_CLOCK_OBTAIN_COORDINATES (& XC, & YC, MAX_RADIUS, MAX_RADIUS, (Hour! = 12)? Hour * 60 min: min, max_radius * 0.65, 12 * 60);

GDK_COLORMAP_ALLOC_COLOR (GDK_COLORMAP_GET_SYSTEM (), & Colors [1], False, true);

GDK_GC_SET_FOREGROUND (Clock_GC, Colors 1); / * Green * /

GDK_DRAW_LINE (Widget-> WINDOW, Clock_GC, XC, YC, MAX_RADIUS, MAX_RADIUS);

/ * Obtain Coordinates for seconds and draw a line from center to thing point * /

GTK_CLOCK_OBTAIN_COORDINATES (& XC, & YC, MAX_RADIUS, MAX_RADIUS, SEC, MAX_RADIUS *. 85, 60);

GDK_COLORMAP_ALLOC_COLOR (GDK_COLORMAP_GET_SYSTEM (), & Colors [2], False, true);

GDK_GC_SET_FOREGROUND (clock_gc, colors 2); / * blue * /

GDK_DRAW_LINE (Widget-> WINDOW, Clock_GC, XC, YC, MAX_RADIUS, MAX_RADIUS);

}

}

In line, you'll notice a gtk_clock_obtain_coordinates () function called. This is another utility function to obtain the coordinated for the line to be drawn based upon the value (say, 15, if current time's minutes is 15), maximum value (60 minutes), coordinates of centre and maximum possible radius of the arms. The calculated coordinates ar stored in address pointed to by xcood & ycood that are passed into the function when called. For a derivation of the formula (e) used here to calculate the Coordinates, Click Here. Here's The Function To Be Added: FileName: GTKCLOCK.C

Include this file: #include add this prototype somewhere in the beginning1 file1: void

2: gtk_clock_obtain_coordinates (int * xcood, int * ycood, int h, int K,

INT Value, int MAX_RADIUS, INT MAX_VAL); New Utility Function Added (at the end) 1: void

2: gtk_clock_obtain_coordinates (int * xcood, int * ycood, int h, int K,

INT Value, int MAX_RADIUS, INT MAX_VAL) 3: {4: Int Yc = * Ycood, XC = * Xcood, F; 5: Float T = 0, S = 0; 6: T = (FLOAT) (Value * 360.0 / (FLOAT) MAX_VAL) * 3.14159 / 180;

7: s = sin (t / 2);

8: YC = (int) (K 2 * Max_Radius * (POW (S, 2)) -max_radius);

9: f = -max_radius * max_radius h * h (yc-k) * (YC-K);

10: IF (value

11: XC = H (FLOAT) (POW (h * h-f, .5));

12: Else

13: XC = H - (float) (POW (h * h-f, .5));

14: * ycood = yc; * xcood = XC;

15:}

Figure 3: Clock's Variable Parameters

Now, after all this, finally, let's write the utility function to obtain the system time. The time () function is used to obtain the no. Of seconds since 1 January, 1970. Simple math would lead us to the present hour, minute and second. We'll call the function get_current_time (). It may be noted that time () works fine on Linux as well as on Windows. So, your widget should be portable. Here's the function. Also make sure that you declare the function at the beginning of the gtkclock.c file. It would be of no use to declare it in the header file, since the scope of the function is limited to the creation of the widget only, and is not meant for other developers to use While Using Your Widget.FileName: gtkclock.c

Add this prototype somewhere in the beginning of the file1: int

2: GET_CURRENT_TIME (INT * HR, INT * MN, INT * SC); new utility function added (at the end) / * this code (get_current_time ()) is full of bugs. * This is originally Taken from Take Yearly Project * of a friend of mine. Maybe you could suggest me * better code, or if I find Time, I'll Write a * better function. * / 1: Gint

2: GET_CURRENT_TIME (INT * HR, INT * MN, INT * SC) 3: {4: Long Hour = * hr, min = * mn, sec = * sc; 5: Hour = Time (null);

6: min = Hour; sec = hour; sec = hours% 60;

7: min = min-min% 60; min = min / 60; min = min% 60;

8: Hour = Hour / (60 * 60); Hour = Hour% 12; Hour = (Hour 6)% 12;

9: IF (min <30) min = min 30;

10: Else min = min-30;

11: if (! Hour) hour = 12; if (min> 30) Hour -; if (Hour <1) hour = 12; 12: * sc = sec; * mn = min; * hr = hour;

13: Return 1;

14:}

THIS Completes The Creation of The Widget. Here a Test Program: FILENAME: TESTCLOCK.C

1: #include

2: #include "gtkclock.h" 3: int main (int Argc, char * argv [])

4: {

5: gtkwidget * window;

6: gtkwidget * clock;

7: gtk_init (& argc, & argv);

8:

9: window = gtk_window_new (gtk_window_toplevel);

10: gtk_window_set_title (gtk_window (window), "GTKCLOCK Widget Example ...");

11: gtk_signal_connect (gtk_object (window), "delete_event", gtk_signal_func (gtk_main_quit), NULL);

12: gtk_container_border_width (gtk_container (window), 10); 13: Clock = gtk_clock_new ();

14: GTK_WIDGET_DRAW (Clock, NULL);

15: GTK_WIDGET_SHOW (CLOCK);

16: gtk_container_add (gtk_container (window), clock; 17: gtk_widget_show (window); 18: gtk_main ();

19:}

Download The Zip File for There 3 Files Here.

Adding the widget to glade Palette

Todo: Write Me! Note: for Widget Plugin to Glade, See http://wingtk.sourceforge.net/wglade.html

转载请注明原文地址:https://www.9cbs.com/read-10495.html

New Post(0)