When constructing a more complicated user interface, with dozens or hundreds of widgets, doing all the setup work in C code is cumbersome, and making changes becomes next to impossible.,GTK is a widget toolkit. Each user interface created by GTK consists of widgets. This is implemented in C using GObject, an object-oriented framework for C. Widgets are organized in a hierachy. The window widget is the main container. The user interface is then built by adding buttons, drop-down menus, input fields, and other widgets to the window. If you are creating complex user interfaces it is recommended to use GtkBuilder and its GTK-specific markup description language, instead of assembling the interface manually. You can also use a visual user interface editor, like Glade.,Note that GtkBuilder can also be used to construct objects that are not widgets, such as tree models, adjustments, etc. That is the reason the method we use here is called gtk_builder_get_object() and returns a GObject instead of a GtkWidget.,Implementing the search needs quite a few code changes that we are not going to completely go over here. The central piece of the search implementation is a signal handler that listens for text changes in the search entry:
#include <gtk/gtk.h>
static void
activate (GtkApplication* app,
gpointer user_data)
{
GtkWidget *window;
window = gtk_application_window_new (app);
gtk_window_set_title (GTK_WINDOW (window), "Window");
gtk_window_set_default_size (GTK_WINDOW (window), 200, 200);
gtk_widget_show_all (window);
}
int
main (int argc,
char **argv)
{
GtkApplication *app;
int status;
app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE);
g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
status = g_application_run (G_APPLICATION (app), argc, argv);
g_object_unref (app);
return status;
}
gcc `pkg-config --cflags gtk+-3.0` - o example - 0 example - 0. c `pkg-config --libs gtk+-3.0`
#include <gtk/gtk.h>
static void
print_hello (GtkWidget *widget,
gpointer data)
{
g_print ("Hello World\n");
}
static void
activate (GtkApplication *app,
gpointer user_data)
{
GtkWidget *window;
GtkWidget *button;
GtkWidget *button_box;
window = gtk_application_window_new (app);
gtk_window_set_title (GTK_WINDOW (window), "Window");
gtk_window_set_default_size (GTK_WINDOW (window), 200, 200);
button_box = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
gtk_container_add (GTK_CONTAINER (window), button_box);
button = gtk_button_new_with_label ("Hello World");
g_signal_connect (button, "clicked", G_CALLBACK (print_hello), NULL);
g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_widget_destroy), window);
gtk_container_add (GTK_CONTAINER (button_box), button);
gtk_widget_show_all (window);
}
int
main (int argc,
char **argv)
{
GtkApplication *app;
int status;
app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE);
g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
status = g_application_run (G_APPLICATION (app), argc, argv);
g_object_unref (app);
return status;
}
gcc `pkg-config --cflags gtk+-3.0` - o example - 1 example - 1. c `pkg-config --libs gtk+-3.0`
#include <gtk/gtk.h>
static void
print_hello (GtkWidget *widget,
gpointer data)
{
g_print ("Hello World\n");
}
static void
activate (GtkApplication *app,
gpointer user_data)
{
GtkWidget *window;
GtkWidget *grid;
GtkWidget *button;
/* create a new window, and set its title */
window = gtk_application_window_new (app);
gtk_window_set_title (GTK_WINDOW (window), "Window");
gtk_container_set_border_width (GTK_CONTAINER (window), 10);
/* Here we construct the container that is going pack our buttons */
grid = gtk_grid_new ();
/* Pack the container in the window */
gtk_container_add (GTK_CONTAINER (window), grid);
button = gtk_button_new_with_label ("Button 1");
g_signal_connect (button, "clicked", G_CALLBACK (print_hello), NULL);
/* Place the first button in the grid cell (0, 0), and make it fill
* just 1 cell horizontally and vertically (ie no spanning)
*/
gtk_grid_attach (GTK_GRID (grid), button, 0, 0, 1, 1);
button = gtk_button_new_with_label ("Button 2");
g_signal_connect (button, "clicked", G_CALLBACK (print_hello), NULL);
/* Place the second button in the grid cell (1, 0), and make it fill
* just 1 cell horizontally and vertically (ie no spanning)
*/
gtk_grid_attach (GTK_GRID (grid), button, 1, 0, 1, 1);
button = gtk_button_new_with_label ("Quit");
g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_widget_destroy), window);
/* Place the Quit button in the grid cell (0, 1), and make it
* span 2 columns.
*/
gtk_grid_attach (GTK_GRID (grid), button, 0, 1, 2, 1);
/* Now that we are done packing our widgets, we show them all
* in one go, by calling gtk_widget_show_all() on the window.
* This call recursively calls gtk_widget_show() on all widgets
* that are contained in the window, directly or indirectly.
*/
gtk_widget_show_all (window);
}
int
main (int argc,
char **argv)
{
GtkApplication *app;
int status;
app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE);
g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
status = g_application_run (G_APPLICATION (app), argc, argv);
g_object_unref (app);
return status;
}
gcc `pkg-config --cflags gtk+-3.0` - o example - 2 example - 2. c `pkg-config --libs gtk+-3.0`
First, we create a horizontally orientated box container where 6 pixels are placed between children. This box becomes the child of the top-level window.,Although a Gtk.ListBox must have only Gtk.ListBoxRow children, you can add any kind of widget to it via Gtk.Container.add() and a Gtk.ListBoxRow widget will automatically be inserted between the list and the widget.,Although a Gtk.FlowBox must have only Gtk.FlowBoxChild children, you can add any kind of widget to it via Gtk.Container.add(), and a Gtk.FlowBoxChild widget will automatically be inserted between the box and the widget.,The Gtk.Notebook widget is a Gtk.Container whose children are pages that can be switched between using tab labels along one edge.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
import gi
gi.require_version("Gtk", "3.0")
from gi.repository
import Gtk
class MyWindow(Gtk.Window):
def __init__(self):
super().__init__(title = "Hello World")
self.box = Gtk.Box(spacing = 6)
self.add(self.box)
self.button1 = Gtk.Button(label = "Hello")
self.button1.connect("clicked", self.on_button1_clicked)
self.box.pack_start(self.button1, True, True, 0)
self.button2 = Gtk.Button(label = "Goodbye")
self.button2.connect("clicked", self.on_button2_clicked)
self.box.pack_start(self.button2, True, True, 0)
def on_button1_clicked(self, widget):
print("Hello")
def on_button2_clicked(self, widget):
print("Goodbye")
win = MyWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
self.box = Gtk.Box(spacing = 6) self.add(self.box)
self.button1 = Gtk.Button(label = "Hello")
self.button1.connect("clicked", self.on_button1_clicked)
self.box.pack_start(self.button1, True, True, 0)
self.button2 = Gtk.Button(label = "Goodbye")
self.button2.connect("clicked", self.on_button2_clicked)
self.box.pack_start(self.button2, True, True, 0)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
import gi
gi.require_version("Gtk", "3.0")
from gi.repository
import Gtk
class GridWindow(Gtk.Window):
def __init__(self):
super().__init__(title = "Grid Example")
button1 = Gtk.Button(label = "Button 1")
button2 = Gtk.Button(label = "Button 2")
button3 = Gtk.Button(label = "Button 3")
button4 = Gtk.Button(label = "Button 4")
button5 = Gtk.Button(label = "Button 5")
button6 = Gtk.Button(label = "Button 6")
grid = Gtk.Grid()
grid.add(button1)
grid.attach(button2, 1, 0, 2, 1)
grid.attach_next_to(button3, button1, Gtk.PositionType.BOTTOM, 1, 2)
grid.attach_next_to(button4, button3, Gtk.PositionType.RIGHT, 2, 1)
grid.attach(button5, 1, 2, 1, 1)
grid.attach_next_to(button6, button5, Gtk.PositionType.RIGHT, 1, 1)
self.add(grid)
win = GridWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
last modified January 6, 2022
#!/usr/bin/python
# ZetCode PyGTK tutorial
#
# This code example draws a circle
# using the cairo library
#
# author: jan bodnar
# website: zetcode.com
# last edited: February 2009
import gtk
import math
class PyApp(gtk.Window):
def __init__(self):
super(PyApp, self).__init__()
self.set_title("Simple drawing")
self.resize(230, 150)
self.set_position(gtk.WIN_POS_CENTER)
self.connect("destroy", gtk.main_quit)
darea = gtk.DrawingArea()
darea.connect("expose-event", self.expose)
self.add(darea)
self.show_all()
def expose(self, widget, event):
cr = widget.window.cairo_create()
cr.set_line_width(9)
cr.set_source_rgb(0.7, 0.2, 0.0)
w = self.allocation.width
h = self.allocation.height
cr.translate(w / 2, h / 2)
cr.arc(0, 0, 50, 0, 2 * math.pi)
cr.stroke_preserve()
cr.set_source_rgb(0.3, 0.4, 0.6)
cr.fill()
PyApp()
gtk.main()
In our example, we will draw a circle and will it with a solid colour.
darea = gtk.DrawingArea()
We will be doing our drawing operations on the DrawingArea
widget.
darea.connect("expose-event", self.expose)
We create the cairo context object from the
gdk.Window
of the drawing area. The context is an
object that is used to draw on all Drawable objects.
cr.set_line_width(9)
We set the width of the line to 9 pixels.
cr.set_source_rgb(0.7, 0.2, 0.0)
One type of widget that you might be interested in creating is a widget that is merely an aggregate of other GTK widgets. This type of widget does nothing that couldn't be done without creating new widgets, but provides a convenient way of packaging user interface elements for reuse. The FileSelection and ColorSelection widgets in the standard distribution are examples of this type of widget. ,Since there is quite a bit more going on in this widget, than the last one, we have more fields in the data structure, but otherwise things are pretty similar. ,The example widget that we'll create in this section is the Tictactoe widget, a 3x3 array of toggle buttons which triggers a signal when all three buttons in a row, column, or on one of the diagonals are depressed. ,The Dial widget as we've described it so far runs about 670 lines of code. Although that might sound like a fair bit, we've really accomplished quite a bit with that much code, especially since much of that length is headers and boilerplate. However, there are quite a few more enhancements that could be made to this widget:
struct _GtkButtonClass {
GtkContainerClass parent_class;
void( * pressed)(GtkButton * button);
void( * released)(GtkButton * button);
void( * clicked)(GtkButton * button);
void( * enter)(GtkButton * button);
void( * leave)(GtkButton * button);
};
struct _GtkButton {
GtkContainer container;
GtkWidget * child;
guint in_button: 1;
guint button_down: 1;
};
#ifndef __TICTACTOE_H__
#define __TICTACTOE_H__
.
.
.
#endif /* __TICTACTOE_H__ */
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
.
.
.
#ifdef __cplusplus
}
#endif /* __cplusplus */
#ifndef __TICTACTOE_H__
#define __TICTACTOE_H__
#include <gdk/gdk.h>
#include <gtk/gtkvbox.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#define TICTACTOE(obj) GTK_CHECK_CAST (obj, tictactoe_get_type (), Tictactoe)
#define TICTACTOE_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, tictactoe_get_type (), TictactoeClass)
#define IS_TICTACTOE(obj) GTK_CHECK_TYPE (obj, tictactoe_get_type ())
typedef struct _Tictactoe Tictactoe;
typedef struct _TictactoeClass TictactoeClass;
struct _Tictactoe
{
GtkVBox vbox;
GtkWidget *buttons[3][3];
};
struct _TictactoeClass
{
GtkVBoxClass parent_class;
void (* tictactoe) (Tictactoe *ttt);
};
guint tictactoe_get_type (void);
GtkWidget* tictactoe_new (void);
void tictactoe_clear (Tictactoe *ttt);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __TICTACTOE_H__ */
guint
tictactoe_get_type() {
static guint ttt_type = 0;
if (!ttt_type) {
GtkTypeInfo ttt_info = {
"Tictactoe",
sizeof(Tictactoe),
sizeof(TictactoeClass),
(GtkClassInitFunc) tictactoe_class_init,
(GtkObjectInitFunc) tictactoe_init,
(GtkArgFunc) NULL,
};
ttt_type = gtk_type_unique(gtk_vbox_get_type(), & ttt_info);
}
return ttt_type;
}
Then you have to change each call that involves GTK, for example creating a button will look now like this:,These old activities are to be ported to GTK 3. This guide explains how.,These are the changes noted by developers while porting activities,pygobject is what we use to make GTK 3 activities. So, it's really useful to take a look at the code examples that are there. Even more, you can run some demo application that show how to use something specific about the library.
import gtk
import gi
gi.require_version('Gtk', '3.0')
from gi.repository
import Gtk
from gi.repository
import Gdk, Pango, GObject
button = Gtk.Button()
from gi.repository
import Gtk
def _destroy_cb(widget, data = None):
Gtk.main_quit()
w = Gtk.Window()
w.connect("destroy", _destroy_cb)
label = Gtk.Label('Hello World!')
w.add(label)
w.show_all()
Gtk.main()
from sugar3.activity
import activity
from sugar3.graphics.toolbarbox
import ToolbarBox
from sugar3.activity.widgets
import ActivityToolbarButton
from sugar3.activity.widgets
import StopButton
from sugar3.graphics.toolbarbox
import ToolbarButton
from sugar3.graphics
import style