以下gtk+编程例子是来自网络《GTK+ 2.0 中文教程》中进度条 Progress Bars的内容——进度条改写网上的例子
源代码出处是http://www.huzheng.org/ebook/gtk2-tut/x892.html
在网上查了几个进度条例子程序都是只有这个例子,修改过的程序也是基于gtk2.0,将原程序用A4纸打印出来反复研究,要修改很多地方才能适用gtk3.0,也遇到很大困难,试改无数遍才成功,分享一下困难与成功的喜悦
将源代码复制到文本编辑器中保存为progressbar1.c
打开虚拟终端进入progressbar1.c所在的文件夹,使用这行命令进行编译
-g -W是为之后使用gdb程序调试使用的,> mistake.text 2>&1表示将错误信息重定向保存到mistake.text文本文件中,; gedit mistake.text表示使用gedit文本编辑器打开mistake.text文本文件,总体意思是编译progressbar1.c过程将错误信息保存到文本文件,编译完成后马上打开文本文件,方便查看错误信息,这只是针对错误太多占满整个屏幕的情况,保存在文件中可以向后查看
假设有10个错误地方,并不意味着你一定要一次修改完10个错误才进行编译,先修改最上面的第一个错误,再编译,再报错9个,依此类推
在openSUSE-Leap-15.3-DVD-x86_64的gnome3.34.7桌面环境下编译的,其中pkg-config --cflags --libs gtk±3.0两边有反引号括起来的
ruhong@localhost:~/gtk> gcc -g -Wall progressbar1.c -o progressbar1 pkg-config --cflags --libs gtk+-3.0
> mistake.text 2>&1 ; gedit mistake.text
ruhong@localhost:~/gtk> ./progressbar1
#include <gtk/gtk.h>
typedef struct _ProgressData {
GtkWidget *window;
GtkWidget *pbar;
int timer;
gboolean activity_mode;
} ProgressData;
/* 更新进度条,这样就能够看到进度条的移动 */
gint progress_timeout( gpointer data )
{
ProgressData *pdata = (ProgressData *)data;
gdouble new_val;
if (pdata->activity_mode)
{
gtk_progress_bar_pulse (GTK_PROGRESS_BAR (pdata->pbar));
} else {
/* 使用在调整对象中设置的取值范围计算进度条的值 */
new_val = gtk_progress_bar_get_fraction (GTK_PROGRESS_BAR (pdata->pbar)) + 0.01;
if (new_val > 1.0)
new_val = 0.0;
/* 设置进度条的新值 */
gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (pdata->pbar), new_val);
}
/* 这是一个 timeout 函数,返回 TRUE,这样它就能够继续被调用 */
return TRUE;
}
/* 回调函数,切换在进度条你的滑槽上的文本显示 */
void toggle_show_text( GtkWidget *widget, ProgressData *pdata )
{
const gchar *text;
text = gtk_progress_bar_get_text (GTK_PROGRESS_BAR (pdata->pbar));
if (text && *text)
gtk_progress_bar_set_text (GTK_PROGRESS_BAR (pdata->pbar), "");
else
gtk_progress_bar_set_text (GTK_PROGRESS_BAR (pdata->pbar), "Some Text");
}
/* 回调函数,切换进度条的活动模式 */
void toggle_activity_mode( GtkWidget *widget, ProgressData *pdata )
{
pdata->activity_mode = !pdata->activity_mode;
if (pdata->activity_mode)
gtk_progress_bar_pulse (GTK_PROGRESS_BAR (pdata->pbar));
else
gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (pdata->pbar), 0.0);
}
/* 回调函数,切换进度条的移动方向 */
void toggle_orientation( GtkWidget *widget, ProgressData *pdata )
{
switch (gtk_progress_bar_get_inverted (GTK_PROGRESS_BAR (pdata->pbar))) {
case FALSE:
gtk_progress_bar_set_inverted (GTK_PROGRESS_BAR (pdata->pbar),
TRUE);
break;
case TRUE:
gtk_progress_bar_set_inverted (GTK_PROGRESS_BAR (pdata->pbar),
FALSE);
break;
default:; // 什么也不做
}
}
/* 清除分配的内存,删除定时器(timer) */
void destroy_progress( GtkWidget *widget, ProgressData *pdata)
{
g_source_remove (pdata->timer);
pdata->timer = 0;
pdata->window = NULL;
g_free (pdata);
gtk_main_quit ();
}
int main( int argc, char *argv[])
{
ProgressData *pdata;
GtkWidget *separator;
GtkWidget *grid;
GtkWidget *button;
GtkWidget *check;
GtkWidget *vbox;
gtk_init (&argc, &argv);
/* 为传递到回调函数中的数据分配内存 */
pdata = g_malloc (sizeof (ProgressData));
pdata->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size (GTK_WINDOW (pdata->window), 500, 200);
gtk_window_set_resizable (GTK_WINDOW (pdata->window), TRUE);
g_signal_connect (G_OBJECT (pdata->window), "destroy",
G_CALLBACK (destroy_progress), pdata);
gtk_window_set_title (GTK_WINDOW (pdata->window), "GtkProgressBar");
gtk_container_set_border_width (GTK_CONTAINER (pdata->window), 10);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
gtk_container_set_border_width (GTK_CONTAINER (vbox), 10);
gtk_container_add (GTK_CONTAINER (pdata->window), vbox);
gtk_widget_show (vbox);
/* 创建一个居中对齐的对象 */
pdata->pbar = gtk_progress_bar_new ();
gtk_progress_bar_set_show_text (GTK_PROGRESS_BAR (pdata->pbar), TRUE);
gtk_box_pack_start (GTK_BOX (vbox), pdata->pbar, TRUE, FALSE, 5);
gtk_widget_show (pdata->pbar);
/* 加一个定时器(timer),以更新进度条的值 */
pdata->timer = g_timeout_add (200, progress_timeout, pdata);
separator = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
gtk_box_pack_start (GTK_BOX (vbox), separator, FALSE, FALSE, 0);
gtk_widget_show (separator);
/* 行数、列数、同质性(homogeneous) */
grid = gtk_grid_new ();
gtk_box_pack_start (GTK_BOX (vbox), grid, FALSE, TRUE, 0);
gtk_widget_show (grid);
/* 添加一个复选按钮,以选择是否显示在滑槽里的文本 */
check = gtk_check_button_new_with_label ("Show text");
gtk_grid_attach (GTK_GRID (grid), check, 0, 0, 1, 1);
g_signal_connect (G_OBJECT (check), "clicked", G_CALLBACK (toggle_show_text), pdata);
gtk_widget_show (check);
/* 添加一个复选按钮,切换活动状态 */
check = gtk_check_button_new_with_label ("Activity mode");
gtk_grid_attach (GTK_GRID (grid), check, 0, 1, 1, 1);
g_signal_connect (G_OBJECT (check), "clicked", G_CALLBACK (toggle_activity_mode), pdata);
gtk_widget_show (check);
/* 添加一个复选按钮,切换移动方向 */
check = gtk_check_button_new_with_label ("Right to Left");
gtk_grid_attach (GTK_GRID (grid), check, 0, 2, 1, 1);
g_signal_connect (G_OBJECT (check), "clicked", G_CALLBACK (toggle_orientation), pdata);
gtk_widget_show (check);
/* 添加一个按钮,用来退出应用程序 */
button = gtk_button_new_with_label ("close");
g_signal_connect_swapped (G_OBJECT (button), "clicked",
G_CALLBACK (gtk_widget_destroy), pdata->window);
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
/* 将按钮设置为能缺省的构件 */
gtk_widget_set_can_default (button, TRUE);
/* 将缺省焦点设置到这个按钮上,使之成为缺省按钮,只要按回车键
* 就相当于点击了这个按钮 */
//译者注: 能缺省的构件在获取焦点后成为缺省构件,用户按方向键等可以切换焦点。
gtk_widget_grab_default (button);
gtk_widget_show (button);
gtk_widget_show (pdata->window);
gtk_main ();
return 0;
}
效果图如下
一、程序的总体意思是进度条最小值为0,最大值为1,当到达1时就马上变为0,从0变1的过程分成200毫秒,每毫秒更新进度条,定时函数gtk_timeout_add改为g_timeout_add,gtk_timeout_remove改为g_source_remove
二、修改进度条的方向为从右到左边
gtk3.0的API手册中GtkProgressBar orientation有讲述在vbox中只能左右调转,在hbox中只能上下调转,本程序的进度条是装入vbox中只有左右调转两种情况
https://developer-old.gnome.org/gtk3/stable/ch26s02.html#id-1.6.3.4.12
GTK+ 2.x GTK+ 3
GtkProgressBarOrientation GtkOrientation inverted
GTK_PROGRESS_LEFT_TO_RIGHT GTK_ORIENTATION_HORIZONTAL FALSE
GTK_PROGRESS_RIGHT_TO_LEFT GTK_ORIENTATION_HORIZONTAL TRUE
gtk_progress_bar_set_orientation函数已经不使用了,改用gtk_progress_bar_set_inverted,默认正常情况下进度条是从左边到右边gtk_progress_bar_set_inverted (GTK_PROGRESS_BAR (pdata->pbar), FALSE); 参数的预设值为FALSE,调转进度条方向,从右边到左边,就是gtk_progress_bar_set_inverted (GTK_PROGRESS_BAR (pdata->pbar), TRUE); 参数值改为TRUE就行了
三、进度条正上方显示百分比或者其它文字
gtk_progress_bar_set_show_text (GTK_PROGRESS_BAR (pdata->pbar), TRUE);
gtk_progress_bar_set_text (GTK_PROGRESS_BAR (pdata->pbar), “Some Text”)要同时存在这两句才能在进度条正上方显示Some Text,只有第一句没有第二句就会自动在进度条正上方显示百分比,没有第一句只有第二句就什么也不显示,所以gtk_progress_bar_set_show_text要紧接着gtk_progress_bar_new
以下这三句,本人也不太明白,也没有用gdb调试progressbar1观察变量text的变化,还不太会使用gdb
const gchar *text;
text = gtk_progress_bar_get_text (GTK_PROGRESS_BAR (pdata->pbar));
if (text && *text)
四、切换进度条的活动模式
gtk_progress_bar_pulse表示暂停进度条,中间有一个片段来回移动,gtk_progress_bar_set_fraction表示正常显示进度条,程序最开头就gboolean activity_mode定义activity_mode的值要么FALSE要么TRUE,且默认值为FALSE
pdata->activity_mode = !pdata->activity_mode;
这句意思是将activity_mode的值互相调换
if (pdata->activity_mode)
本人猜测,并没有用gdb调试progressbar1观察变量activity_mode的变化,还不太会使用gdb
五、align = gtk_alignment_new (0.5, 0.5, 0, 0);语句的目的是让进度条居中,但是在gtk3.0中与vbox在一起却报错,只能去掉,直接将进度条装入vbox中,gtk_box_pack_start (GTK_BOX (vbox), pdata->pbar, TRUE, FALSE, 5);第三个参数改为TRUE可以实现居中功能