HelloWorld written in GTK+

 

The following code is a HelloWorld routine written in GTK+. After compiling and running, a window with a button will be displayed. Clicking the button will pop up a prompt message dialog box.

//hello.c
#include <gtk/gtk.h>
//主窗口中按钮的回调函数
void	on_button_clicked(GtkWidget* button, gpointer userdata)
{
	GtkWidget *dialog;
//创建带确认按钮的对话框,父控件为空
	dialog = gtk_message_dialog_new(NULL, 
			GTK_DIALOG_MODAL |GTK_DIALOG_DESTROY_WITH_PARENT,
			GTK_MESSAGE_INFO,
			GTK_BUTTONS_OK,
			(gchar*)userdata);
	gtk_dialog_run(GTK_DIALOG(dialog));//显示并运行对话框
	gtk_widget_destroy(dialog);//销毁对话框
}
//主函数
int	main(int argc, char* argv[])
{
	GtkWidget *window, *button;
	//初始化GTK+程序
	gtk_init(&argc, &argv);
	//创建窗口,并为窗口的关闭信号加回调函数以便退出
	window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
	g_signal_connect(G_OBJECT(window),"delete_event",
			G_CALLBACK(gtk_main_quit),NULL);
	gtk_window_set_title(GTK_WINDOW(window),"Hello World!");
	gtk_container_set_border_width(GTK_CONTAINER(window),10);
	//创建按钮控件,为单击信号加回调函数,将其放入窗口中
	button=gtk_button_new_with_label("Hello World!");
	g_signal_connect(G_OBJECT(button),"clicked",
			G_CALLBACK(on_button_clicked),(gpointer)"你好!\n自由的世界。");
	gtk_container_add(GTK_CONTAINER(window),button);
	//下面函数显示窗口控件同时显示其中的所有其它控件
	gtk_widget_show_all(window);
	gtk_main();
	return FALSE;
}
 


 

You can directly use the command "gcc `pkg-config -cflags -libs gtk+2.0` hello.c -o hello" to compile the above code, but it is better to make a Makefile with the content as follows:

CC = gccall:$(CC) `pkg-config --cflags --libs gtk+-2.0` hello.c -o hello

In this case, you can use the make command to compile, which makes it much simpler and less error-prone. What I want to emphasize again is the question of quotation marks. Many beginners often make this mistake. [`] is the single quotation mark under [~], not [']; this involves command quotes in LINUX SHELL programming, under LINUX The standard BASH supports command quotes, while other SHELLs are not necessarily.

The following two figures show the running window of the program and the dialog box that pops up by clicking the Hello World button:

Initialization, main loop and exit

Unlike the development of GUI programs in C under MS WINDOWS, GTK+ does not use the WinMain function, but directly cuts in by the standard format main function in the C language, which is unified in the UNIX operating system family. The function gtk_init is the beginning of the Peugeot GTK+ program. Its two parameters are the addresses of the two parameters of the main function. After this function, various related parts of the program can be processed, such as the creation and display of the control, adding a callback function to the signal of the control, setting or modifying the properties of the control, etc. Finally, the gtk_main function is executed, the program enters the main event loop, begins to receive the signal and calls its corresponding callback function for the signal. The function gtk_main_quit is used to end the main event loop, that is, exit the GTK+ program.

Creation, display and layout of controls

The controls in GTK+ are divided into container controls and non-container controls. Non-container controls are mainly basic GUI elements, such as text labels, images, text entry controls, etc. There are many container controls, and the common point is that they can be arranged in a certain way. For other controls, GTK+ forms a unique GUI interface layout style. The general form of the GTK+ control creation function is: gtk_control name_new (parameter...) or gtk_control name_new_with_parameter name (parameter...), and its return value is a pointer of GtkWidget type, which can be called after the creation is complete gtk_widget_show function to show or hide this control, or use related functions to modify the properties of the control.

Signal connection and callback function

GTK+ uses signals and callback functions to handle external events. Controls inherit the same signal from their parent control, and different controls have their own different signals. For example, button controls have "clicked" signals, but text label controls don’t. This signal. GTK+2.0 uses the macro g_signal_connect to complete the connection between the signal and the callback function. This is a key difference between it and the GTK+1.X version. This macro has four parameters. The first parameter is the object to which the signal is connected. The button or window in the example needs to be converted with the G_OBJECT macro, that is, the object type GtkWidget is converted to the GObject type, and the format is generally G_OBJECT(button); the second parameter is the signal name in string format; the third parameter is Callback function name, use the G_CALLBACK macro to convert; the fourth parameter is a pointer to the parameter to be passed to the callback function. In the above example, the callback function "on_button_clicked" added for the "clicked" signal of the button:

g_signal_connect(G_OBJECT(button),"clicked",
	G_CALLBACK(on_button_clicked),(gpointer)"你好!\n自由的世界。");

Careful readers will immediately see a shortcoming of this macro, that is, only one parameter can be passed to the callback function. Of course, smart readers will immediately think of using structure types to pass multiple parameters. The above content seems a bit more complicated for beginners, as long as you pass this threshold, you will actually enter the world of GTK+.


International programming

gettext package

The above program runs when the main window is displayed in English. We can change it to Chinese. This single language version is not suitable for the internationalization of the application. GTK+ uses the gettext software package to achieve internationalization, which makes this problem very difficult. simple. The gettext software package is an important tool for solving internationalization problems in the GNU project. The current version is 0.11.x, which supports C/C++ and JAVA languages. It is widely used in the open source world. GNOME/GTK+ is used for internationalization problems. Solved, under normal circumstances, the GNU/LINUX system installs this software package by default.

Code

The first is to add the relevant C language header files to the source code as follows:

#include <libintl.h>		//gettext支持
#include <locale.h>		//locale支持
 

Then there is the definition of macros, the following definition form is the standard format used in GNOME/GTK+:

#define PACKAGE "hello"	//软件包名
#define LOCALEDIR "./locale" //locale所在目录
#define _(string)	gettext(string)
#define N_(string)	string

Add the following related functions to the main function of the program:

bindtextdomain(PACKAGE,LOCALEDIR);
	//以上函数用来设定国际化翻译包所在位置
	textdomain(PACKAGE);
	//以上函数用来设定国际化翻译包名称,省略了.mo

Related string modification

Rewrite the string that needs to be internationalized in the code-that is, multilingual output into _() macro, the code is as follows:

gtk_window_set_title(GTK_WINDOW(window),_("Hello World!"));
  ... ...
  button=gtk_button_new_with_label(_("Hello World!"));
  g_signal_connect(G_OBJECT(button),"clicked",
      G_CALLBACK(on_button_clicked),(gpointer)(_("Hello, the Free World!")));
... ...

Generate relevant documents and translation

After completing the above modification, execute the following command: xgettext -k_ -o hello.po hello.c, its function is to add the string in the underscore opening bracket (as shown in the macro definition) in hello.c to hello. po file. The header of the po file can be added with the package name, version, translator’s email address, etc. The content of the behavior comment starting with # in the po file, the following is the content of the hello.po file with the header omitted, and the content after msgid is In English, the content after msgstr is translated Chinese, and it is saved in UTF8 format after translation.

#: hello.c:26 hello.c:29
msgid "Hello World!"
msgstr "你好世界!"
#: hello.c:31
msgid "Hello, the Free World!"
msgstr "你好,自由的世界!"

The next step is to execute the command: msgfmt -o hello.mo hello.po to format the hello.po file as a hello.mo file, so that the program can correctly read the data in the mo file according to the current locale setting when it is running. Thereby displaying information about the language. Regarding the location of the .mo file, this program is located in the LC_MESSAGES directory under the Chinese directory zh_CN under the ./locale directory, that is, under the ./locale/zh_CN/LC_MESSAGES directory. The default directory in REDHAT is /usr/share/locale . Copy the mo file generated in this step to the corresponding directory, set the locale to simplified Chinese, and then run this program, the test result will become Chinese (as shown in the figure below), if the locale is set to English, the display will still be the above English information.


Automatically generate Makefile and package

Automatic generation of Makefile files is the wish of many LINUX programming enthusiasts. In fact, as long as you make good use of AUTOCONF and AUTOMAKE, you will easily generate Makefile files and package them (generate sources in *.tar.gz format). Code package) function. The configuration files related to these two tools are configure.in and Makefile.am. As long as we understand the format of these two files and the related macros, it's all right.

Operation process

The premise is to make the corresponding directory and source program files, such as hello.c in the hello directory in this example.

1. First execute the autoscan command to generate the configure.scan file;

2. Execute mv configure.scan configure.in and rename it;

3. Edit configure.in, add a line after AC_INIT(hello.c), AM_INIT_AUTOMAKE(hello,1.0) means that the package name is hello, and the version is 1.0, so after make is compiled, execute make dist will generate a file called hello -1.0.tar.gz source code package, this is a format that conforms to the GNU open source standard. Add Makefile in the brackets of AC_OUTPUT() in the last line to indicate the output Makefile file (there are many macro definitions in the configure.in file, please refer to the autobook book for detailed usage), and the end of editing the configure.in file at this point;

4. Execute the aclocal command to generate the aclocal.m4 macro file;

5. Execute the autoconf command to generate the configure shell executable script;

6. Edit the Makefile.am file, the content is as follows:

AUTOMAKE_OPTIONS = foreign
INCLUDES = `pkg-config --cflags gtk+-2.0`
LIBS = `pkg-config --libs gtk+-2.0`
bin_PROGRAMS = hello
hello_SOURCES = hello.c

Description: The first line represents the parameters of the AUTOMAKE command, which are external and do not follow the GNU standard (that is, no instructions, installation, change records, etc.); the second line represents the directory containing the file; the third line represents the dynamic link library The directory and the library to be linked; the fourth line represents the output executable file name; the last line represents the source program file of the executable file, which can have multiple file names.

7. Execute the command automake --add-missing -copy, which means to create the Makefile.in file and add the missing files, and copy them at the same time (by default it is a symbolic link, which will cause problems between different file systems), so far The operation is complete.

Compile, test, install and package

Execute ./configure to generate Makefile; execute make to compile; execute ./hello to run this program; execute make install to install, by default, the executable file hello is copied to the /usr/local/bin directory; execute make dist will be Generate the hello-1.0.tar.gz source code package in the current directory, so you can publish your source code package to the outside world.


Use threads

In the application of thread in GTK+, in addition to the two functions g_thread_init and g_thread_supported in GLIB, gdk_thread_init is also used to initialize the thread application in X WINDOW. In addition, when the GTK+ control is to be operated in the thread, the function must be executed before the operation. Enter with gdk_thread_enter, and execute the function gdk_thread_leave to leave after the operation is completed. This is also the case when the GTK+ main loop is executed. GTK+ uses this to achieve thread safety; the following code uses threads to create an image that moves clockwise on the screen (24x24 pixels) :

//thread.c
#include <gtk/gtk.h>
typedef struct _Ourarg Ourarg;
struct _Ourarg {
	GtkWidget *fixed;
	GtkWidget *image;
	gint right;
	gint left;
};
void	image_go(Ourarg *arg)
{
	gint x, y, toward;
	x = y = arg->left;
	toward = 1;
	for(;;)
	{
		g_usleep(1500);
		gdk_threads_enter();
		gtk_fixed_move(GTK_FIXED(arg->fixed),arg->image, x, y);
		switch(toward)
		{
		case 1:
			x = x + 10;
			if( x > arg->right ) toward = 2;
			break;
		case 2:
			y = y + 10;
			if( y > arg->right ) toward = 3;
			break;
		case 3:
			x = x - 10;
			if( x < arg->left ) toward = 4;
			break;
		case 4:
			y = y -10;
			if( y < arg->left ) toward = 1;
		}
		gdk_threads_leave();
	}
}
int	main(int argc, char* argv[])
{
	GtkWidget *window;
	GtkWidget *vbox, *viewport, *button;
	GtkWidget *image, *fixed;
	Ourarg *arg;
	if(!g_thread_supported()) g_thread_init(NULL);
	gdk_threads_init();
	gtk_init(&argc,&argv);
	window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
	gtk_window_set_title(GTK_WINDOW(window),"线程测试");
	g_signal_connect(G_OBJECT(window),"delete_event",
			G_CALLBACK(gtk_main_quit),NULL);
	gtk_container_set_border_width(GTK_CONTAINER(window),2);
	vbox = gtk_vbox_new(FALSE,0);
	gtk_container_add(GTK_CONTAINER(window),vbox);
	fixed = gtk_fixed_new();
	gtk_widget_set_usize(fixed,340,340);
	viewport = gtk_viewport_new(NULL,NULL);
	gtk_box_pack_start(GTK_BOX(vbox),viewport,FALSE,FALSE,5);
	gtk_container_add(GTK_CONTAINER(viewport),fixed);
	image = gtk_image_new_from_file("ss.png");
	gtk_fixed_put(GTK_FIXED(fixed),image,40,40);
	button = gtk_button_new_with_label("退出");
	gtk_box_pack_start(GTK_BOX(vbox),button,FALSE,FALSE,5);
	g_signal_connect(G_OBJECT(button),"clicked",
			G_CALLBACK(gtk_main_quit),NULL);
	gtk_widget_show_all(window);
	arg = g_new(Ourarg,1);
	arg->fixed = fixed;
	arg->image = image;
	arg->left = 40;
	arg->right = 260;
	g_thread_create(image_go, arg, FALSE, NULL);
	gdk_threads_enter();
	gtk_main();
	gdk_threads_leave();
	return FALSE;
}

Based on thread safety considerations, you must execute the following code before the gtk_init function:

if(!g_thread_supported()) g_thread_init(NULL);
	gdk_threads_init();

The thread executes an endless loop, constantly moving the image control in the GtkFixed control, and changing the direction according to the position of the image.


Guess you like

Origin blog.csdn.net/woailp___2005/article/details/6852721