注册 登录
电子工程世界-论坛 返回首页 EEWORLD首页 频道 EE大学堂 下载中心 Datasheet 专题
damiaa的个人空间 https://home.eeworld.com.cn/space-uid-59433.html [收藏] [复制] [分享] [RSS]
日志

【 STM32MP135F-DK测评】+(4)用GTK制作计算器

已有 60 次阅读2025-3-4 10:44 |个人分类:STM32

             【 STM32MP135F-DK测评】+(4)用GTK制作计算器
 
 
上次搭建好开发环境后,这次试一下GTK图形库开发一个小应用:计算器。
 

一、基本概念

GTK(GIMP Toolkit)是一套开源的跨平台图形用户界面(GUI)工具包1。最初,GTK是为GNU图像处理程序(GIMP)设计的,但随着时间的推移,它已经成为了一个功能强大的GUI开发框架。
GTK提供了一组可重用的GUI元素,如按钮、文本框、下拉列表、进度条等,这些元素可以用于开发各种类型的应用程序1。它是基于对象的,并采用C语言编写,但GTK也有许多其他编程语言的封装,如Python、Perl、Ruby等,这使得开发者可以使用自己熟悉的语言进行GUI开发。

主要功能和特性

GTK库不仅包含了GUI元素,还包含了一些附加功能,如用于绘制二维图形的Cairo库、用于解析XML的LibXML2库、以及用于处理国际化和本地化的Gettext库等。这些功能使得开发者能够更轻松地开发高质量的应用程序。
GTK还提供了丰富的布局管理功能,允许开发者灵活地控制GUI元素的排列和布局。此外,GTK还支持事件处理机制,使得开发者可以处理用户的输入事件,如鼠标点击、键盘按键等。

支持的操作系统和开发语言

GTK支持运行在Linux、UNIX、Windows和macOS等平台上,这使得开发者可以在不同的操作系统上进行GUI开发1。同时,GTK也支持多种编程语言,如C、C++、Python、Perl等,这进一步扩大了GTK的应用范围12。

应用场景或案例

GTK在开源社区中得到了广泛的应用。许多著名的开源软件,如GIMP、GNOME桌面环境、Inkscape等都使用了GTK作为GUI开发框架3。此外,一些商业软件也采用了GTK进行开发,证明了GTK的可靠性和实用性。

安装和使用方法

在Linux系统上,GTK通常可以通过包管理器进行安装,如apt-get、yum等。例如,在Debian或Ubuntu系统上,可以使用以下命令安装GTK开发库:
bash
复制
sudo apt-get install libgtk-3-dev
 
基本程序框架如下
 
下面的程序中还需要加入控件布局的一些函数和方法
 
GTK布局的基本概念
GTK布局是指在GTK中组织和排列控件(如按钮、文本框、列表等)的方法。GTK提供了多种布局容器,用于在窗口中组织和定位这些控件。
GTK中常用的布局容器
  1. GtkHBox:水平布局容器,允许控件在水平方向上排列。
  2. GtkVBox:垂直布局容器,允许控件在垂直方向上排列。
  3. GtkTable:表格布局容器,允许控件以表格形式排列。
  4. GtkAlignment:对齐布局容器,允许控件按照指定的位置和比例进行排列。
  5. GtkFixed:固定布局容器,允许控件在固定位置进行排列,通常用于特殊布局需求。
如何在GTK中使用布局容器进行界面设计
  1. 创建布局容器:使用相应的函数创建布局容器,如gtk_hbox_new()、gtk_vbox_new()等。
  2. 添加控件:使用gtk_container_add()函数将控件添加到布局容器中。
  3. 设置布局属性:可以使用gtk_box_pack_start()或gtk_box_pack_end()设置布局属性,如控件的排列方式、间距等。
  4. 显示控件:使用gtk_widget_show_all()函数显示布局容器及其包含的所有控件。
简单的GTK布局示例代码 以下是一个简单的GTK水平布局示例:

 

二、实践阶段


有了上面的概念后下面的实践就好办了。
第一步,创建主程序,程序中加入按键1、2、3、4、5、6、7、8、9、0、+、-、*、/、=、clear、help加入数据显示行。并用vbox,hbox进行布局。连接按键和处理程序。代码如下:

int main ( int argc , char* argv[])
{
   GtkWidget *window;
   GtkWidget *vbox;
   GtkWidget *hbox,*hbox1,*hbox2,*hbox3;
   GtkWidget *button;
   GtkWidget *label;
   gtk_init(&argc,&argv);
   s.count =0;
   s.first_data =TRUE;
   s.fi_dot =FALSE;
   s.se_dot =FALSE;
   s.cac_result_flag =FALSE; 
   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),"Calculator V1.0");
   gtk_window_set_default_size(GTK_WINDOW(window),150,150);
   gtk_container_set_border_width(GTK_CONTAINER(window),10); 
   vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL,0);
   gtk_container_add(GTK_CONTAINER(window),vbox);
 
   hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL,0);
   gtk_box_pack_start(GTK_BOX(vbox),hbox,FALSE,FALSE,5);
 
   //第一行 计算器标号和清除按钮
   label = gtk_label_new("Calculator");
   gtk_box_pack_start(GTK_BOX(hbox),label,TRUE,TRUE,5);
   button = gtk_button_new_with_label("C");
   gtk_box_pack_start(GTK_BOX(hbox),button,TRUE,TRUE,5);
   //信号连接 连接按钮和响应函数
   g_signal_connect(G_OBJECT(button),"clicked",
         G_CALLBACK(clear_clicked),NULL);
   button = gtk_button_new_with_label("?");
   gtk_box_pack_start(GTK_BOX(hbox),button,TRUE,TRUE,5);
   //信号连接 连接按钮和响应函数
   g_signal_connect(G_OBJECT(button),"clicked",
         G_CALLBACK(help_clicked),NULL);
   //第二行 输入显示   第二第三第四第五行等距离 使用vbox 和hbox
   input_enter = gtk_entry_new();
   gtk_widget_set_direction(input_enter,GTK_TEXT_DIR_RTL);
   //每个按钮都是以同样的方式组装到横向盒里的,这里只有一个对象
   gtk_box_pack_start(GTK_BOX(vbox),input_enter,FALSE,FALSE,5);
   //第三行 0,1,2,3,4,+号
   hbox1 = gtk_box_new(FALSE,0);
   //hbox1 组装vbox盒里的,这样形成一行
   gtk_box_pack_start(GTK_BOX(vbox),hbox1,FALSE,FALSE,5);
 
   button = gtk_button_new_with_label("0");
   g_signal_connect(G_OBJECT(button),"clicked",
         G_CALLBACK(number_clicked),NULL);
   gtk_box_pack_start(GTK_BOX(hbox1),button,TRUE,TRUE,5);
   button = gtk_button_new_with_label("1");
   g_signal_connect(G_OBJECT(button),"clicked",//按钮连接到相关响应函数
         G_CALLBACK(number_clicked),NULL);
   //button “1” 装进hbox1盒子,同样后面的“2”, “3”,“4”,“5”,“+”都装到hbox1 这样一行中有6个按钮     
   //其他行同样道理
   gtk_box_pack_start(GTK_BOX(hbox1),button,TRUE,TRUE,5);
   button = gtk_button_new_with_label("2");
   g_signal_connect(G_OBJECT(button),"clicked",
         G_CALLBACK(number_clicked),NULL);
   gtk_box_pack_start(GTK_BOX(hbox1),button,TRUE,TRUE,5);
 
   button = gtk_button_new_with_label("3");
   gtk_box_pack_start(GTK_BOX(hbox1),button,TRUE,TRUE,5);
   g_signal_connect(G_OBJECT(button),"clicked",
         G_CALLBACK(number_clicked),NULL);
 
   button = gtk_button_new_with_label("4");
   gtk_box_pack_start(GTK_BOX(hbox1),button,TRUE,TRUE,5);
   g_signal_connect(G_OBJECT(button),"clicked",
         G_CALLBACK(number_clicked),NULL);
 
   button = gtk_button_new_with_label("+");
   g_signal_connect(G_OBJECT(button),"clicked",
         G_CALLBACK(operator_clicked),(gpointer)1);
   gtk_box_pack_start(GTK_BOX(hbox1),button,TRUE,TRUE,5);
   //第四行5,6,7,8,9,-号
   hbox2 = gtk_box_new(FALSE,0);
   gtk_box_pack_start(GTK_BOX(vbox),hbox2,FALSE,FALSE,5);
   button = gtk_button_new_with_label("5");
   gtk_box_pack_start(GTK_BOX(hbox2),button,TRUE,TRUE,5);
   g_signal_connect(G_OBJECT(button),"clicked",
         G_CALLBACK(number_clicked),NULL);
   
   button = gtk_button_new_with_label("6");
   g_signal_connect(G_OBJECT(button),"clicked",
         G_CALLBACK(number_clicked),NULL);
   gtk_box_pack_start(GTK_BOX(hbox2),button,TRUE,TRUE,5);
 
   button = gtk_button_new_with_label("7");
   g_signal_connect(G_OBJECT(button),"clicked",
         G_CALLBACK(number_clicked),NULL);
   gtk_box_pack_start(GTK_BOX(hbox2),button,TRUE,TRUE,5);
 
   button = gtk_button_new_with_label("8");
   g_signal_connect(G_OBJECT(button),"clicked",
         G_CALLBACK(number_clicked),NULL);
   gtk_box_pack_start(GTK_BOX(hbox2),button,TRUE,TRUE,5);
 
   button = gtk_button_new_with_label("-");
   g_signal_connect(G_OBJECT(button),"clicked",
         G_CALLBACK(operator_clicked),(gpointer)2);
   gtk_box_pack_start(GTK_BOX(hbox2),button,TRUE,TRUE,5);
   //第五行 *,9,.,=,/
   hbox3 = gtk_box_new(FALSE,0);
   button = gtk_button_new_with_label("9");
   g_signal_connect(G_OBJECT(button),"clicked",
         G_CALLBACK(number_clicked),NULL);
   gtk_box_pack_start(GTK_BOX(hbox3),button,TRUE,TRUE,5);
   
   gtk_box_pack_start(GTK_BOX(vbox),hbox3,FALSE,FALSE,5);
   button = gtk_button_new_with_label("*");
   g_signal_connect(G_OBJECT(button),"clicked",
         G_CALLBACK(operator_clicked),(gpointer)3);
   gtk_box_pack_start(GTK_BOX(hbox3),button,TRUE,TRUE,5);

 
   button = gtk_button_new_with_label(".");
   g_signal_connect(G_OBJECT(button),"clicked",
         G_CALLBACK(dot_clicked),NULL);
   gtk_box_pack_start(GTK_BOX(hbox3),button,TRUE,TRUE,5);
 
   button = gtk_button_new_with_label("=");
   g_signal_connect(G_OBJECT(button),"clicked",
         G_CALLBACK(equ_clicked),NULL);
   gtk_box_pack_start(GTK_BOX(hbox3),button,TRUE,TRUE,5);
 
   button = gtk_button_new_with_label("/");
   g_signal_connect(G_OBJECT(button),"clicked",
         G_CALLBACK(operator_clicked),(gpointer)4);
   gtk_box_pack_start(GTK_BOX(hbox3),button,TRUE,TRUE,5);
 
   //gtk_widget_show_all 显示
   gtk_widget_show_all(window);
   //主循环
   gtk_main();
 
   return FALSE;
}

第二步,进行数据处理:
采用一个结构体保存过程数据:
count限制一下输入位数,s保存是加减乘除等计算方法的一种,first_data指示是输入计算数据的两个数的第一个还是第二个,因为输入的数据会保存到不同的数组numberFi 或numberSe中。fi_dot、se_dot为了保证一个数据中只有一个小数点。

每次计算开始的时候会清除所有数据到开始阶段如下:

Help按钮的消息框:

clear按钮:

加减乘除等操作符响应函数:

数字按钮响应函数:

根据先前是否按下s.first_data把数据保存到s.numberFi或 s.numberSe中。

当然如果是有s.cac_result_flag为真,也就是如果计算结果完成了或程序刚启动,就清除数据到计算前状态。

小数点按钮响应函数:

避免多个小数点在一个数字中。

根据先前是否按下s.first_data把数据保存到s.numberFi或 s.numberSe中。

当然如果是有s.cac_result_flag为真,也就是如果计算结果完成了或程序刚启动,就清除数据到计算前状态。

=符合响应函数:

根据符号和s.numberFi、s.numberSe计算结果并显示。

s.cac_result_flag标记为真,下次按钮按下就会清除数据准备计算。

#include <gtk/gtk.h>
#include <stdlib.h>
static GtkWidget *input_enter; //定义单行输入控件来显示输入输出的数字
struct ss
{
      gint count; //计位
      gint s;  //算法
      gboolean first_data;  //首次输入
      gboolean fi_dot;  //是否有小数点
      gboolean se_dot;  //是否有小数点
      gboolean cac_result_flag;  //是否有结果输出
      gchar numberFi[100]; //保存用户输入的数字
      gchar numberSe[100]; //保存用户输入的数字
} s;

void clear (void)
{ 
  //重新计算清除标记
   gtk_entry_set_text(GTK_ENTRY(input_enter),"");
   s.s = 0;
   s.count = 0 ;
   s.first_data = TRUE;
   s.fi_dot = FALSE;
   s.se_dot = FALSE;
   s.cac_result_flag = FALSE;
   for(gint i = 0 ; i < 100 ; i++)
   {   
      s.numberFi[i] = 0;
      s.numberSe[i] = 0;
   }
}
void help_clicked (GtkWidget *widget, gpointer window)
{
      GtkWidget *dialog;
        dialog = gtk_message_dialog_new(window,
                  GTK_DIALOG_DESTROY_WITH_PARENT,
                  GTK_MESSAGE_INFO,
                  GTK_BUTTONS_OK,
                  "The calculator app provides simple operations of addition, subtraction, multiplication, and division.");
        gtk_window_set_title(GTK_WINDOW(dialog), "HELP");
        gtk_dialog_run(GTK_DIALOG(dialog));
        gtk_widget_destroy(dialog);
}
void number_clicked (GtkButton* button,gpointer data)
{ //当数定键按下时执行
   const gchar *num;
   if(s.cac_result_flag)//按下数字键和小数点键时显示结果清零,并且数据清理重新开始计数
         clear();
   if(s.count == 8) return; //限制输入位数
   s.count++;
   num = gtk_button_get_label(GTK_BUTTON(button));//取数

   if(s.first_data)
   {
      g_strlcat(s.numberFi,num,100);//保存
      gtk_entry_set_text(GTK_ENTRY(input_enter),s.numberFi);//显示
   }
   else
   {      
      g_strlcat(s.numberSe,num,100);//保存
      gtk_entry_set_text(GTK_ENTRY(input_enter),s.numberSe);//显示
   }
}
void dot_clicked (GtkButton* button,gpointer data)
{ //当小数点按下时
   if(s.cac_result_flag)//按下数字键和小数点键时显示结果清零,并且数据清理重新开始计数
         clear();
   if(s.first_data)
   {
      if(s.fi_dot == FALSE) //每个数字串只一次按下小数点      
      {
         s.fi_dot = TRUE;
         g_strlcat(s.numberFi,".",100);
         gtk_entry_set_text(GTK_ENTRY(input_enter),s.numberFi);
      }
   }            
   else
   {
      if(s.se_dot == FALSE) //每个数字串只一次按下小数点      
      {     
            s.se_dot =TRUE;
            g_strlcat(s.numberSe,".",100);
            gtk_entry_set_text(GTK_ENTRY(input_enter),s.numberSe);   
      }
   }  
   //如果有小数点则不输出
}
void clear_clicked (GtkButton* button,gpointer data)
{
   clear();//全部清除
}
void operator_clicked (GtkButton* button,gpointer data)
{ 
   // +,-,*,/ 按下时
   switch(GPOINTER_TO_INT(data))
   {
      case 1: //"+"
         s.s = 1;
         gtk_entry_set_text(GTK_ENTRY(input_enter),"");
         s.first_data = FALSE ; s.count = 0; break;
      case 2: //"-"
         s.s = 2;
         gtk_entry_set_text(GTK_ENTRY(input_enter),"");
         s.first_data = FALSE ; s.count = 0; break;
      case 3: //"*"
         s.s = 3;
         gtk_entry_set_text(GTK_ENTRY(input_enter),"");
         s.first_data = FALSE ; s.count = 0; break;
      case 4: //"/"
         s.s = 4;
         gtk_entry_set_text(GTK_ENTRY(input_enter),"");
         s.first_data = FALSE ; s.count = 0; break;
   }
}
void equ_clicked (GtkButton* button,gpointer data)
{ //当等号键按钮按下时
   double numb=0;
   gchar num[100];
   gchar *result;

   gdouble n = strtod(s.numberFi,NULL);//数一转换
   gdouble m = strtod(s.numberSe,NULL);//数二转换
   switch(s.s)
   {
      case 1: //"+
         numb = n+m;
         break;
      case 2: //"-"
         numb = n-m;
         break;
      case 3: //"*"
         numb = n*m;
         break;
      case 4: //"/"
         numb = n/m;
         break;
   }
   result = g_ascii_dtostr(num,100,numb);
   gtk_entry_set_text(GTK_ENTRY(input_enter),result);
   s.cac_result_flag = TRUE;
}

三、显示结果:

 

所有程序就介绍完了:显示结果如下:
 
                                                                                    谢谢

本文来自论坛,点击查看完整帖子内容。

评论 (0 个评论)

facelist doodle 涂鸦板

您需要登录后才可以评论 登录 | 注册

热门文章