Pages

2008年12月17日 星期三

如何使用 GtkProgressBar

  進度條(ProgressBar)是一個和使用者互動必備的元件,因為你必須讓使用者了解目前處理進度,若等不下去就可以趕緊取消。至於使用他的方式我覺得可以採取「Timer」或「Thread」。下面就以計時器的方式來介紹進度條的使用。但礙於程式太佔版面,所以只會顯示部份程式碼。
  
  一個進度條的產生是透過 gtk_progress_bar_new,進度條的範圍是[0,1],且以浮點數儲存。如果要讀取或修改進度條的數值利用 gtk_progress_bar_set(get)_fraction。了解這些之後,咱們就來看看程式碼。
/*
 以下程式執行會產生一個主視窗+按鍵
 當按下按鍵就建立另一個視窗+進度條
 並且透過計時器每次增加0.01,直到1.0為止
*/
#include<gtk/gtk.h>

gdouble new_val;
guint timer_id = 0;

static gboolean flush_progressbar(gpointer progressbar)
{
new_val= gtk_progress_bar_get_fraction(GTK_PROGRESS_BAR(progressbar))+0.01;
if(new_val >= 1.0) new_val = 1.0;

gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progressbar), new_val);

if(new_val >= 1.0) {
/* 舊版是用 gtk_timeout_remove() */
g_source_remove(timer_id);  
return FALSE;
}

return TRUE; // 如此計時器才會一直 work
}

static void create_window(GtkWidget *widget, gpointer window)
{
// 產生並初始化視窗
...

GtkWidget *progressbar;
progressbar = gtk_progress_bar_new();
gtk_layout_put(GTK_LAYOUT(layout), progressbar, 100, 200);

...
 
// 100毫秒執行一次
/* 舊版是用 gtk_timeout_add() */
timeId = g_timeout_add(100 , flush_progressbar, progressbar);
}

int main(int argc, char *argv[])
{
// window - 主視窗
// window_create_after - 按下按鍵後產生的視窗
GtkWidget *window;
GtkWidget *window_create_after;
GtkWidget *button;

gtk_set_locale();
gtk_init(&argc, &argv);

// 產生並初始化 window
// 產生並出使化 button、加到 window 中
// 註冊 clicked 事件用來產生 window_create_after
// 以及產生一個 timer
 
gtk_main();
return(0);
}


這裡要注意的有兩點:
  1. 不要計時器中加入 delay 的機制(如:sleep),因為會導致前一次沒處理完,下一次又開始處理(re-entrant routine),導致 stack overflow。 
  2. 不要讓主程式(main process)去處理 progressbar 的值,因為只會看到最終完成的畫面,中間的遞增過程使用者看不到。會有這種結果其實也不難想像,由於主程式正在執行某個function call,即使你不斷地更新進度條的內容,這些 event handler 只能等到目前的程式執行完,控制權回到 caller (也許好幾層),才會去執行這些更新畫面的 handler。
 

最後再介紹兩支和進度條相關的函式:
gtk_progress_bar_set_pulse_step(GTK_PROGRESS_BAR(progressbar),0.1);
gtk_progress_bar_pulse(GTK_PROGRESS_BAR(progressbar));

  這兩支函式可以讓進度條內的東東左跑右跑,就是放入 Live CD,在 ubuntu 圖樣的那個畫面,進度條開始跑進度之前的行為。就如同以上的程式碼,每次以0.1的間隔在移動,移動完右邊,就移左邊;移動完左邊,就移動右邊。

沒有留言:

 
Blogger Templates