天天看點

GTK構件之微調按鈕

GTK構件之微調按鈕

1.微調按鈕簡介

       微調按鈕(Spin Button)構件通常用于讓使用者從一個取值範圍你選擇一個值。它由一個文本輸入框和旁邊的向上和向下兩個按鈕組成。點選某一個按鈕會讓文本輸入框裡的數值大小在一定範圍你改變。文本輸入框裡也可以直接輸入一個特定值。

       微調按鈕構件允許其中的數值沒有小數位或具有指定的小數位,并且數值可以按一種可配置的方式增加或減小。在按鈕較長時間呈按下狀态時,構件的數值會根據工具按下時間的長短加速變化。

       微調按鈕用一個調整對象來維護該按鈕能夠取值的範圍。微調按鈕構件是以而具有了很強大的功能。

2.調整對象簡介

     GTK 有多種構件能夠由使用者通過滑鼠或鍵盤進行調整,比如範圍構件。還有一些構件,比如說 GtkText 和GtkViewport,内部都有一些可調整的屬性。

       很明顯,當使用者調整範圍構件的值時,應用程式需要對值的變化進行響應。一種辦法就是當構件的調整值發生變化時,讓每個構件引發自己的信号,将新值傳遞到信号處理函數中,或者讓它在構件的内部資料結構中查找構件的值。 但是,也許需要将這個調整值同時連接配接到幾個構件上,使得調整一個值時,其它的構件都随之響應。最明顯的示例就是将一個滾動條連接配接到一個視角構件(viewport)或者滾動的文本區(text area)上。如果每個構件都要有自己的設定或擷取調整值的方法,程式員或許需要自己編寫很複雜的信号處理函數,以便将這些不同構件之間的變化同步或相關聯。

       GTK用一個調整對象(Adjustment object)解決了這個問題。調整對象不是構件,但是為構件提供了一種以抽象、 靈活的方法來傳遞調整值資訊。調整對象最明顯的用處就是為範圍構件(比如滾動條和比例構件)儲存配置參數和值。 然而,因為調整對象是從 Object派生的,在其正常的資料結構之外,它還具有一些特殊的功能。 最重要的是,它們能 夠引發信号,就像構件一樣,這些信号不僅能夠讓程式對使用者在可調整構件上的輸入進行響應,還能在可調整構件之間透明地傳播調整值。

       在許多其它的構件中都能夠看到調整對象的用處。比如進度條、 視角 、 滾動視窗等。

  •  微調按鈕中建立調整對象函數:
GtkAdjustment *gtk_adjustment_new (gdouble value,
gdouble lower,gdouble upper,
gdouble step_increment,gdouble page_increment,
gdouble page_size);
形參:value -- 微調按鈕初始值
      lower、upper  --構件允許的最大值、最小值
      step_increment  --滑鼠左鍵按下構件一次增加/減小的值
      page_increment  --滑鼠右鍵下構件一次增加/減少的值
      page_size  --沒有用到
傳回值:傳回微調按鈕構件對象      
  •  微調按鈕建立函數:
GtkWidget *gtk_spin_button_new (GtkAdjustment *adjustment,gdouble  climb_rate,guint digits)
形參:adjustment --調整對象
      climb_rate --指明構件數值變化的加速度(長時間按住按鈕, 數值會加速變化)。介于0.0~1.0之間
      digits --微調按就值小數位數      
  •  微調按鈕參數配置函數:
void gtk_spin_button_configure( GtkSpinButton *spin_button,GtkAdjustment *adjustment,
gdouble climb_rate,guint digits );
形參:spin_button --微調按鈕控件
adjustment --調整對象
      climb_rate --指明構件數值變化的加速度(長時間按住按鈕, 數值會加速變化)。介于0.0~1.0之間
      digits --微調按就值小數位數      
  •  設定或擷取構件内部使用的調整對象:
/*擷取微調按鈕調整對象資訊*/
GtkAdjustment *gtk_spin_button_get_adjustment (GtkSpinButton *spin_button);
/*設定微調按鈕調整對象資訊*/
gtk_spin_button_set_adjustment (GtkSpinButton *spin_button,GtkAdjustment *adjustment);      
  •  設定微調按鈕小數位數:
void gtk_spin_button_set_digits (GtkSpinButton *spin_button,guint digits)
形參:spin_button --微調按鈕控件
      digits --微調按鈕數值小數位數      
  •  設定微調按鈕數值:
void gtk_spin_button_set_value (GtkSpinButton *spin_button,gdouble value);
形參:spin_button --微調按鈕控件
      value-- 要設定的數值      
  •  擷取按鈕目前數值:
/*以整數方式擷取目前按鈕數值*/
gdouble gtk_spin_button_get_value ( GtkSpinButton *spin_button );
/*以小數方式擷取目前按鈕數值*/
gint gtk_spin_button_get_value_as_int( GtkSpinButton *spin_button );      
  •  以目前值為基準修改微調按鈕數值:
void gtk_spin_button_spin( GtkSpinButton *spin_button,GtkSpinType direction,gdouble increment );
形參:spin_button --微調按鈕控件
direction 取以下參數:
        GTK_SPIN_STEP_FORWARD
        GTK_SPIN_STEP_BACKWARD
        GTK_SPIN_PAGE_FORWARD
        GTK_SPIN_PAGE_BACKWARD
        GTK_SPIN_HOME
        GTK_SPIN_END
        GTK_SPIN_USER_DEFINED      

  GTK_SPIN_STEP_FORWARD和GTK_SPIN_STEP_BACKWARD将構件的值按increment參數指定的數值增大或減小,除非increment參數是 0。這種情況下,構件的值将按與其相關聯的調整對象的step_increment值改變。

 GTK_SPIN_PAGE_FORWARD和GTK_SPIN_PAGE_BACKWARD隻是簡單地按increment參數改變微調按鈕構件的值。

 GTK_SPIN_HOME 将構件的值設定為相關聯調整對象的範圍的最小值。

 GTK_SPIN_END 将構件的值設定為相關聯調整對象的範圍的最大值。

 GTK_SPIN_USER_DEFINED簡單地按指定的數值改變構件的數值。

  •  限制微調按鈕構件的文本框隻能輸入數值:
void gtk_spin_button_set_numeric (GtkSpinButton *spin_button,gboolean numeric)
形參:spin_button --微調按鈕控件
      numeric  --TRUE 隻能輸入數字;FALSE 可以輸入任意内容      
  •  設定讓微調按鈕構件在upper和lower之間循環:
void gtk_spin_button_set_wrap (GtkSpinButton  *spin_button, gboolean wrap)
形參:spin_button --微調按鈕控件
      wrap --TRUE 當按鈕值到達最小值再往下調整将變為最大值;最大值再往上調整将為最小值
            FALSE 當按鈕值到達最小值再往下調整将保持不變;最大值再往上調整保持不變      

  可以設定讓微調按鈕構件将其值圓整到最接近 step_increment 的值(在該微調按鈕構件使用的調整對象中設定的)。用下面的函數實作:

void gtk_spin_button_set_snap_to_ticks( GtkSpinButton *spin_button,gboolean snap_to_ticks );      
  •  微調按鈕構件的更新方式可以用下面的函數改變:
void gtk_spin_button_set_update_policy( GtkSpinButton*spin_button,GtkSpinButtonUpdatePolicy policy );
形參:spin_button --微調按鈕控件
      policy  --可以取如下值:
      GTK_UPDATE_ALWAYS 
          GTK_UPDATE_IF_VALID。      
  •  更新微調按鈕:
void gtk_spin_button_update( GtkSpinButton *spin_button );      

3.微調按鈕示例

  • 本示例實作共能如下:
  1. 通過微調按鈕數值日期(年、月、日);
  2. 通過複選按鈕選擇微調按鈕僅能輸入數字;
  3. 設定數值的小數位數
  4. 退出按鈕通過對話框提示是否退出,儲存按鈕提示儲存成功;
#include <gtk/gtk.h>
#include <stdio.h>
/*微調按鈕回調函數*/
void spin_button_callback(GtkWidget *widget,gpointer data)
{
  GtkWidget *spinbutton=(GtkWidget *)data;
  int val;
  /*擷取目前微調按鈕的值*/
  val=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget));
  g_print("val=%d\n",val);
  /*修改小數位數*/
  gtk_spin_button_set_digits(GTK_SPIN_BUTTON(spinbutton),val);
}
/*複選按鈕處理函數*/
void check_button_callback(GtkWidget *widget,gpointer data)
{
  GtkWidget *spinbutton=(GtkWidget *)data;
  if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
  {
    /*設定微調按鈕隻能輸入數字*/
    gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(spinbutton),TRUE);
  }
  else
  {
    /*設定微調按鈕可以輸入任意内容*/
    gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(spinbutton),FALSE);
  }
}
/*儲存按鈕處理函數*/
void save_button_callback(GtkWidget *widget,gpointer data)
{
  g_print("儲存\n");
  GtkWidget *window=(GtkWidget *)data;
  GtkWidget *dialog;
  GtkWidget *label;
  dialog=gtk_dialog_new_with_buttons("儲存", GTK_WINDOW(window),GTK_DIALOG_MODAL,NULL);
  gtk_window_set_default_size(GTK_WINDOW(dialog),100, 100);
  label=gtk_label_new("儲存成功\n");
  gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),label,TRUE, TRUE,0);
  gtk_widget_show(label);
  gtk_widget_show(dialog);
}
GtkWidget *dialog;
/*對話框處理回調函數*/
void button_clicked_callback(GtkWidget *widget,gpointer data)
{
  char *pada=(gchar *)data;
  if(!strcmp(pada,"on"))
  {
    gtk_widget_destroy(dialog);//關閉對話框
  }
  if(!strcmp(pada,"ok"))
  {
    gtk_main_quit();
  }
}
/*退出按鈕處理函數*/
void quit_button_callback(GtkWidget *widget,gpointer data)
{
  g_print("退出\n");
  GtkWidget *window=(GtkWidget *)data;
  GtkWidget *label;
  GtkWidget *table;
  GtkWidget *button;
  dialog=gtk_dialog_new_with_buttons("是否退出", GTK_WINDOW(window),GTK_DIALOG_MODAL,NULL);
  gtk_window_set_default_size(GTK_WINDOW(dialog),100, 100);
  label=gtk_label_new("是否退出");
  gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),label,TRUE, TRUE,0);
  gtk_widget_show(label);

  /*建立組裝表*/
  table=gtk_table_new(1,0,FALSE);
  gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area),table,FALSE, FALSE, 0);
  gtk_widget_show(table);
  /*建立按鈕*/
  button=gtk_button_new_from_stock(GTK_STOCK_NO);
  gtk_table_attach_defaults(GTK_TABLE(table),button,0,1,0,1);
  gtk_widget_show(button);
  g_signal_connect(GTK_OBJECT(button),"clicked",G_CALLBACK(button_clicked_callback),"on");
  /*建立按鈕*/
  button=gtk_button_new_from_stock(GTK_STOCK_OK);
  gtk_table_attach_defaults(GTK_TABLE(table),button,1,2,0,1);
  g_signal_connect(GTK_OBJECT(button),"clicked",G_CALLBACK(button_clicked_callback),"ok");
  gtk_widget_show(button);
  gtk_widget_show(dialog);
}
int main(int argc,char *argv[])
{
  GtkWidget *window;
  GtkWidget *vbox,*box;
  GtkWidget *frame;
  GtkAdjustment *adjust;
  GtkWidget *table;
  GtkWidget *label;
  GtkWidget *spin_button,*spin_val_button;
  GtkWidget *check_button;
  GtkWidget *button;
  gtk_init(&argc,&argv);
  window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_window_set_title(GTK_WINDOW(window), "微調按鈕");
  gtk_window_set_default_size(GTK_WINDOW(window),320, 240);
  gtk_container_set_border_width(GTK_CONTAINER(window) ,5);
  g_signal_connect(G_OBJECT(window),"destroy",G_CALLBACK(gtk_main_quit),NULL);

  /*建立縱向盒*/
  vbox=gtk_vbox_new(FALSE,0);
  gtk_container_set_border_width(GTK_CONTAINER(vbox) ,2);
  gtk_container_add(GTK_CONTAINER(window),vbox);
  gtk_widget_show(vbox);
  /*建立架構構件*/
  frame=gtk_frame_new("日期設定");
  gtk_frame_set_label_align(GTK_FRAME(frame),1.0,0.5);
  /*設定架構構件風格*/
  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_OUT);
  gtk_box_pack_start(GTK_BOX(vbox),frame, FALSE,TRUE,0);
  gtk_widget_show(frame);

  /*建立組裝表*/
  table=gtk_table_new(2,3,FALSE);
  gtk_container_add(GTK_CONTAINER(frame),table);
  /*設定列之間的間隔*/
  gtk_table_set_col_spacings(GTK_TABLE(table),20);
  gtk_widget_show(table);

  /*建立調整對象*/
  adjust=(GtkAdjustment *)gtk_adjustment_new(2022,1970,3000,1,1,0);
  /*建立微調按鈕*/
  spin_button=gtk_spin_button_new(adjust,0.5, 0);
  /*限制微調按鈕隻能輸入數值*/
  gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(spin_button),TRUE);
  /*設定按鈕達到最大值後再變為最小值*/
  gtk_spin_button_set_wrap (GTK_SPIN_BUTTON(spin_button), TRUE);
  gtk_table_attach_defaults (GTK_TABLE(table),spin_button,0,1,1,2);
  gtk_widget_show(spin_button);
  /*設定标簽*/
  label=gtk_label_new("年");
  gtk_table_attach_defaults(GTK_TABLE(table),label,0,1,0,1);
  
  gtk_widget_show(label);

  /*建立微調按鈕*/
  adjust=(GtkAdjustment *)gtk_adjustment_new(1,1,12,1,1,0);
  spin_button=gtk_spin_button_new(adjust,1, 0);
  gtk_spin_button_set_wrap (GTK_SPIN_BUTTON(spin_button), TRUE);
  gtk_table_attach_defaults (GTK_TABLE(table),spin_button,1,2,1,2);
  gtk_widget_show(spin_button);
  /*設定标簽*/
  label=gtk_label_new("月");
  gtk_table_attach_defaults(GTK_TABLE(table),label,1,2,0,1);
  gtk_widget_show(label);

  /*建立微調按鈕*/
  adjust=(GtkAdjustment *)gtk_adjustment_new(1,1,31,1,1,0);
  spin_button=gtk_spin_button_new(adjust,0.5, 0);
  gtk_spin_button_set_wrap (GTK_SPIN_BUTTON(spin_button), TRUE);
  gtk_table_attach_defaults (GTK_TABLE(table),spin_button,2,3,1,2);
  gtk_widget_show(spin_button);
  /*設定标簽*/
  label=gtk_label_new("日");
  gtk_table_attach_defaults(GTK_TABLE(table),label,2,3,0,1);
  gtk_widget_show(label);

  /*建立架構構件*/
  frame=gtk_frame_new("數值調整");
  gtk_frame_set_label_align(GTK_FRAME(frame),0.5,0.5);
  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_OUT);
  gtk_box_pack_start(GTK_BOX(vbox),frame, FALSE,TRUE,0);
  gtk_widget_show(frame);
  /*建立縱向向盒*/
  box=gtk_vbox_new(FALSE,0);
  gtk_container_add(GTK_CONTAINER(frame),box);
  gtk_widget_show(box);
  /*建立組裝表*/
  table=gtk_table_new(2,2,FALSE);
  gtk_box_pack_start(GTK_BOX(box),table,TRUE,TRUE,0);
  /*設定列之間的間隔*/
  gtk_table_set_col_spacings(GTK_TABLE(table),10);
  gtk_widget_show(table);  
  /*建立調整對象*/
  adjust=(GtkAdjustment *)gtk_adjustment_new(0,-5000,5000,0.5,0.5,0);
  spin_val_button=gtk_spin_button_new(adjust,0.5, 2);
  gtk_table_attach_defaults (GTK_TABLE(table),spin_val_button,0,1,1,2);
  gtk_widget_show(spin_val_button);
  /*設定标簽*/
  label=gtk_label_new("數值");
  gtk_table_attach_defaults(GTK_TABLE(table),label,0,1,0,1);
  gtk_widget_show(label);

  /*建立調整對象*/
  adjust=(GtkAdjustment *)gtk_adjustment_new(2,0,6,1,1,0);
  spin_button=gtk_spin_button_new(adjust,0.5, 0);
  g_signal_connect(G_OBJECT(spin_button),"value_changed",G_CALLBACK(spin_button_callback), spin_val_button);
  gtk_table_attach_defaults (GTK_TABLE(table),spin_button,1,2,1,2);
  gtk_widget_show(spin_button);
  /*設定标簽*/
  label=gtk_label_new("小數位數");
  gtk_table_attach_defaults(GTK_TABLE(table),label,1,2,0,1);
  gtk_widget_show(label);

  /*建立複選按鈕*/
  check_button=gtk_check_button_new_with_label("僅輸入數字");
  gtk_box_pack_start(GTK_BOX(box),check_button,FALSE,FALSE,0);
  g_signal_connect(G_OBJECT(check_button),"toggled",G_CALLBACK(check_button_callback), spin_button);
  gtk_widget_show(check_button);

  /*建立橫向盒*/
  box=gtk_hbox_new(FALSE,0);
  gtk_box_pack_start(GTK_BOX(vbox),box,TRUE,TRUE,0);
  gtk_widget_show(box);
  
  /*建立儲存按鈕*/
  button=gtk_button_new_with_label("退出");
  gtk_box_pack_start(GTK_BOX(box),button,FALSE,FALSE,0);
  g_signal_connect(G_OBJECT(button),"clicked",G_CALLBACK(quit_button_callback),window);
  gtk_widget_show(button);
  
  /*建立儲存按鈕*/
  button=gtk_button_new_with_label("儲存");
  gtk_box_pack_end(GTK_BOX(box),button,FALSE,FALSE,0);
  g_signal_connect(G_OBJECT(button),"clicked",G_CALLBACK(save_button_callback),window);
  gtk_widget_show(button);
  gtk_widget_show(window);
  gtk_main();
}