Fine-tuning button for GTK components

Fine-tuning button for GTK components

1. Introduction to spinner buttons

  The Spin Button widget is typically used to allow the user to select a value from a range of values. It consists of a text input box with up and down buttons next to it. Clicking a certain button will make the value in the text input box change within a certain range. A specific value can also be entered directly into the text input box.
  The Spin Button widget allows the value to have no or specified decimal places, and the value can be increased or decreased in a configurable manner. When the button is pressed for a long time, the value of the component will change at an accelerated rate according to the length of time the tool is pressed.
  A spinner uses an adjustment object to maintain the range of values ​​the button can take. This makes the spinner widget very powerful.

2. Adjust the object profile

  GTK has various widgets that can be adjusted by the user via mouse or keyboard, such as the range widget. There are also some components, such as GtkText and GtkViewport, which have some adjustable properties inside.
  Obviously, when the user adjusts the value of the range widget, the application needs to respond to the value change. One approach is to have each widget raise its own signal when the widget's adjusted value changes, passing the new value into a signal handler, or have it look up the widget's value in the widget's internal data structure. However, it may be necessary to connect this adjustment value to several components at the same time, so that when one value is adjusted, the other components respond accordingly. The most obvious examples are connecting a scrollbar to a viewport or scrolling text area. If each component has its own method for setting or getting the adjustment value, the programmer may need to write a very complex signal processing function to synchronize or correlate the changes between these different components.
  GTK solves this problem with an adjustment object (Adjustment object). Tuning objects are not components, but provide an abstract and flexible way for components to pass tuning value information. The most obvious use of adjustment objects is to store configuration parameters and values ​​for range widgets such as scrollbars and scale widgets. However, because the adjustment object is derived from Object, it has some special functions in addition to its normal data structure. Most importantly, they can raise signals, like widgets, that not only allow programs to respond to user input on adjustable widgets, but also transparently propagate adjustment values ​​between adjustable widgets.
  The use of adjustment objects can be found in many other widgets. Such as progress bar, viewing angle, scrolling window, etc.

  • Create an adjustment object function in the fine-tuning button:
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  --没有用到
返回值:返回微调按钮构件对象
  • Spinner button creation function:
GtkWidget *gtk_spin_button_new (GtkAdjustment *adjustment,gdouble  climb_rate,guint digits)
形参:adjustment --调整对象
      climb_rate --指明构件数值变化的加速度(长时间按住按钮, 数值会加速变化)。介于0.0~1.0之间
      digits --微调按就值小数位数
  • Fine-tuning button parameter configuration function:
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 --微调按就值小数位数
  • Set or get the adjustment object used internally by the widget:
/*获取微调按钮调整对象信息*/
GtkAdjustment *gtk_spin_button_get_adjustment (GtkSpinButton *spin_button);
/*设置微调按钮调整对象信息*/
gtk_spin_button_set_adjustment (GtkSpinButton *spin_button,GtkAdjustment *adjustment);
  • Set the number of decimal places for the spinner button:
void gtk_spin_button_set_digits (GtkSpinButton *spin_button,guint digits)
形参:spin_button --微调按钮控件
      digits --微调按钮数值小数位数
  • Set spinner button value:
void gtk_spin_button_set_value (GtkSpinButton *spin_button,gdouble value);
形参:spin_button --微调按钮控件
      value-- 要设置的数值
  • Get the current value of the button:
/*以整数方式获取当前按钮数值*/
gdouble gtk_spin_button_get_value ( GtkSpinButton *spin_button );
/*以小数方式获取当前按钮数值*/
gint gtk_spin_button_get_value_as_int( GtkSpinButton *spin_button );
  • Modify the value of the spinner button based on the current value:
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 and GTK_SPIN_STEP_BACKWARD increase or decrease the value of the component by the value specified by the increment parameter, unless the increment parameter is 0. In this case, the widget's value will be changed by the step_increment value of its associated adjustment object.
  GTK_SPIN_PAGE_FORWARD and GTK_SPIN_PAGE_BACKWARD simply change the value of the spinner widget by the increment parameter.
  GTK_SPIN_HOME sets the widget's value to the minimum of the range of the associated adjustment object.
  GTK_SPIN_END sets the widget's value to the maximum value of the associated adjustment object's range.
  GTK_SPIN_USER_DEFINED simply changes the value of the widget by the specified value.

  • Restrict the text box of the spinner widget to only input values:
void gtk_spin_button_set_numeric (GtkSpinButton *spin_button,gboolean numeric)
形参:spin_button --微调按钮控件
      numeric  --TRUE 只能输入数字;FALSE 可以输入任意内容
  • Set the spinner widget to cycle between upper and lower:
void gtk_spin_button_set_wrap (GtkSpinButton  *spin_button, gboolean wrap)
形参:spin_button --微调按钮控件
      wrap --TRUE 当按钮值到达最小值再往下调整将变为最大值;最大值再往上调整将为最小值
            FALSE 当按钮值到达最小值再往下调整将保持不变;最大值再往上调整保持不变

  Can be set to have the spinner widget round its value to the nearest step_increment (set in the adjustment object used by the spinner widget). Implement it with the following function:

void gtk_spin_button_set_snap_to_ticks( GtkSpinButton *spin_button,gboolean snap_to_ticks );
  • The way the spinner widget is updated can be changed with the following functions:
void gtk_spin_button_set_update_policy( GtkSpinButton*spin_button,GtkSpinButtonUpdatePolicy policy );
形参:spin_button --微调按钮控件
      policy  --可以取如下值:
		  GTK_UPDATE_ALWAYS 
          GTK_UPDATE_IF_VALID。

  In the GTK_UPDATE_IF_VALID mode, the spinner widget will update only when the input text is a valid value within the specified range of its adjustment object, otherwise the text will be reset to the current value.
  In GTK_UPDATE_ALWAYS mode, we will ignore errors when converting text to numbers.

  • Update spinner button:
void gtk_spin_button_update( GtkSpinButton *spin_button );

3. Example of spinner button

insert image description here
  This example implements the following functions:

  1. Numeric date (year, month, day) through the spinner button;
  2. Selecting the spinner via the check button can only enter numbers;
  3. Set the number of decimal places for a value
  4. The exit button prompts whether to exit through a dialog box, and the save button prompts that the save is successful;
#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();
}

Guess you like

Origin blog.csdn.net/weixin_44453694/article/details/127520000