LINUX下GTK 实现简单计算器

更新时间:2023-05-07 04:08:01 阅读量: 实用文档 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

摘要

随着计算机的越来越普及,学习计算机的人越来越多。作为一个学习计算机的人员,最基本的那就是必须会编程。但是在微软垄断下的现在的计算机编程大多是基于windows下的编程。设置很多人没听说过或者不会Linux下编程。本设计的目的就是为初学Linux下编程的人员提供基础的例子。让大家了解Linux下的编程。

本程序运用Linux下的工具GTK+2.0作为工具,以C语言为核心编写。简单易懂,GTK+2.0主要功能有:

●窗口与简单控件的实现

●菜单与工具栏的实现

●常用控件的实现

●对话框的实现

……

关键词:Linux GTK+2.0

Abstract

As computers become increasingly popular, more and more people learn the computer. As a learning computer personnel, the most basic that we must be programmed. However, under the Microsoft monopoly in computer programming is now mostly under the windows-based programming. Set a lot of people never heard of or will not, under Linux programming. The purpose of this design is for beginners programming under Linux provides the basis of examples. Let everyone know the programming under Linux.

●Window and a simple realization of the control

●Realization of the menu and tool bar

●The realization of common control

●Realization of the dialog box

……

KEYWORDS:Linux GTK+2.0

目录

第一章引言 (2)

1.1GTK+简介 (2)

第二章程序实现 (3)

2.1窗口构建 (3)

2.1.1基本窗口实现 (3)

2.1.2按钮实现 (4)

2.2控件 (5)

2.2.1按钮盒设置 (5)

2.2.2框架设置 (5)

2.2.3分割面板 (6)

2.3对话框 (6)

2.3.1多项选一的窗口 (6)

2.3.2创建消息框 (6)

2.4综合实现 (7)

结束语 (9)

代码 (10)

第一章引言

1.1GTK+简介

GTK+最初是GIMP的专用开发库,后来发展为Unix-like系统下开发图形界面的应用程序的主流开发工具之一。GTK+是自由软件,并且是GNU计划的一部分。GTK+的许可协议是LGPL。

GTK(GIMP Toolkit)是一套跨多种平台的图形工具包,按LGPL许可协议发布的。虽然最初是为GIMP写的,但目前已发展为一个功能强大、设计灵活的一个通用图形库。特别是被GNOME选中使得GTK+广为流传,成为Linux下开发图形界面的应用程序的主流开发工具之一,当然GTK+并不要求必须在Linux上,事实上,目前GTK+已经有了成功的windows版本。

与其他很多部件工具箱不同,GTK+ 并不基于Xt。这一决策优劣互见:优点是GTK+ 可以应用于其他系统,其灵活性也很强;而缺点就是它无法利用以传统方法为X11定制的X资源数据库。GTK+ 最早应用于X Window System,如今已移植至其他平台,诸如Microsoft Windows, DirectFB,以及Quartz在Mac OS X。

使用GTK的环境:

GNOME是以GTK+为基础,就是说为GNOME编写的程序使用GTK+ 做为其工具箱。

Xfce也基于GTK+,但是它的应用程序并不对很多其他程序有依赖。(这就是"GNOME程序"和"GTK+程序"的不同)。

LXDE也基于GTK+。

GPE Palmtop环境和Nokia的互联网平板电脑的框架Maemo基于GTK+。

这只是一部分,另外GTK+ 也可以运行在KDE的环境下。而且GTK+ 也可以在Microsoft Windows运行,另外还有DirectFB和ncurses。

以下程序都是使用GTK+开发、属于开源软件,可以运行于Linux/Unix,Windows,Mac等多种操作系统平台上。

Geany,代码编辑器;

GIMP,类似于Photoshop的图像处理程序;

Inkscape,类似于Illustrator、CorelDraw的矢量图形绘制工具;

Pidgin,支持多种协议(IRC、Gtalk、Yahoo Talk、MSN、QQ等等)的聊天工具。

2

第二章程序实现

2.1窗口构建

2.1.1基本窗口实现

窗口时GUI编程中直接面向对用户的操作对象。

1,设置include文件与声明主函数

首先是#include语句,这是每个GTK+2.0程序都要包含的文件。然后是函数声明int main(int argc,char *argv[]),这是标准的C语言主函数的声明。

2,声明变量

GtkWidget *window;声明了窗口控件的指针。期中GtkWidget是GTK2.0控件类型,window是变量名;它与变量类型无关。

3,初始化GTK+2.0的命令行参数

函数gtk_init(&argc,&argv);这是在GTK2.0程序中必需的,不管设计中是否用到命令行参数,都需要用这一函数来初始化。

4,创建窗口

代码行window=gtk_window_new(GTK_WINDOW_TOPLEVEL);用来创建窗口。函数gtk_window_new创建一个窗口并返回这个窗口的空间指针,在这里这个指针的值赋给了变量window;参数GTK_WINDOW_TOPLEVEL指明窗口的类型为最上层的主窗口,还可以取另一个值GTK_WINDOW_POPUP指明窗口的类型为弹出式的无边框的窗口。

5,现实窗口

代码行gtk_widge_show(window);用来现实上一步创建的窗口。函数gtk_widget_show是用来现实控件的,它没有返回类型,参数是要现实的空间的指针,在这里是窗口window。

6,主事件循环

函数gtk_main();是最关键的,它是GTK+2.0的主事件循环,每一个GTK+2.0程序都要一个,否则程序就无法运行。所谓事件循环是指GUI程序运行时等待来自外部用户发出的事件,如键入活鼠标移动等,GTK+2.0将这些事件包装成信号,用户再根据信号的功能编写相应的回调函数来处理这些事件。

代码最后返回逻辑值FALSE,它相当于整数0。写这行代码更能体现程序的完整性和可读性。

3

以上完成了简单的变量的声明、窗口的创建、显示。

2.1.2按钮实现

1,图像控件

图像控件在GTK+2.0编程中经常用到,图像控件最简单的创建方法之一就是直接从图像文件中创建,使用函数gtk_image_new_from_file,它只有一个参数就是要调用的图像文件名,返回结果是图像控件的指针。

GTK+2.0+自身带有一个叫GDKPIXBUF的程序库,GTK+2.0+使用它来支持多种图像文件格式,如PNG,JPEG,BMP,GIF等。

2,标签控件

多数情况下,标签文本在GTK+2.0编程中起到提示的作用。用gtk_label_new 函数可以直接创建一个标签文本,它的参数就是标签要提示的文本字符串。事实上创建带有标签的按钮时,按钮中就包含了一个标签控件。

3,创建按钮

这里定义了两个函数来分别创建不同样式的按钮,期中create_button1创建的按钮中包含了一个纵向盒状容器来容纳一个图像的一个标签;create_button2则用到了了纵向盒状容器。把图像和标签建完后,用gtk_box_pack_start函数排放到盒状容器内。由于返回的值是控件的指针。所以两个函数的返回类型均为GtkWidget*。

第三个按钮的创建用到了函数gtk_button_new_with_stock,意思是从系统自带的资源项目中创建按钮,它只有一个参数,表示一系统自带资源(包括文字、图像和快捷键)的一个字符串命名。GTK+2.0中用一系列一GTK_STLCO开头的宏表示,如GTK_STOCK_CANCELL表示取消,GTK_STOCK_ADD表示增加。

4,多函数实现

为编写方便,将上面两个函数放到了主函数的前面。如果主函数后面定义活在外部文件中定义,则一定要在主函数前面加上函数声明。格式:GtkWidget* create_button1 (void);

GtkWdiget* create_button2 (void);

5,回调函数的参数

回调函数on_button_clicked,它的主要功能是向终端输出一行文字信息。而且四个按钮的单击信号都连接了这个函数。为了让输出内容不同,每个按钮连接信号时传递给回调函数的参数都是不同的,如第一个按钮传递的参数是字符串b1,第二个按钮的参数则是b2,第三个按钮的参数是b3,第四个按钮的参数是b4.注意的是一定要将字符串强制转换成gpointer类型,如(gpointer)b4。因为回

4

调函数接收的参数也是gpointer类型的,它为了把字符串显示出来,还需要将这个指针类型转换为字符串型,如(gchar*)data。两外如果终端支持中文的话,参数可以直接设为中文。

2.2控件

2.2.1按钮盒设置

1,按钮盒的属性

按钮盒的属性有以下几个值:GTK_BUTTONBOX_DEFAULT_STLE_,默认排列;GTK_BUTTONBOX_SPREAD,紧密排列;GTK_BUTTONX_EDGE,居中排列;

GTK_BUTTONBOX_START,首对其排列;GTK_BUTTONBOX_END,尾对其排列。

2,控件的间隔

由于按钮盒是继承自盒状容器的,所以可以直接使用与盒状容器的相关函数来操作它,如用函数gtk_box_set_spacing来设定按钮盒中按钮之间的空格间隙。

2.2.2框架设置

1,框架的外观

可以用函数gtk_frame_set_shadow_type来设定框架控件的外观轮廓,其第二个参数为GtkShadowType类型,可以取以下几个值:GTK_SHADOW_NONE,无外框线;GTK_SHADOW_IN,内向型的外框线;GTK_SHADOW_OUT,外向型的外框线(像个按钮);GTK_SHADOW_ETCHED_IN和GTK_SHADOW_ETCHED_OUT一个向内凹一个向外凸。

2,纵横比框架控件

纵横比框架控件性能和框架控件在总体上是一致的,只不过它在长宽比例上是固定的,所以此程序在运行时即使拖长了窗口,它也不好占满整个容器的空间。可以使用下面函数来设定规范框架的长宽比:

Gtk_aspect_frame_set(GTK_ASPECT_FRAME(frame),0,0.8,0.8,TRUE);

其第二和第三个参数分别表示横向和纵向的位置,取值0到1之间的浮点数,其中0表示左边,1表示右边,第四个参数表示纵横比的系数;最后一个参数表示其子控件是否受其约束。

框架控件在GTK+2.0编程中经常用到,主要起到美化外观和规范其他控件的作用。

5

2.2.3分割面板

向分割面板中加控件

创建分割面板控件用函数gtk_vpanel(纵向)活gtk_hpanel_new(横向)来直接创建,向分隔面板中添加控件也很简单,用函数gtk_panel_add1和

gtk_panel_add2就可以实现,期中add1表示向分隔面板的第一个容器控件添加,即横向面板的左侧或纵向面板的上部,add2则依次。

2.3对话框

2.3.1多项选一的窗口

1,创建单选按钮

创建单选按钮有许多个函数,每个函数的第一个参数都是单向链表(GSList)类型的,表示单选按钮所属的组。在创建一组的第一个单选按钮时,可以将此参数设为NULL,而余下的单选按钮在创建时首先要用gtk_radio_button_get_group 函数来设定单选按钮所属的组。

除此之外,还可以用函数gtk_radio_button_new_from_widget来一次创建一组单选按钮,它的参数是前一单选按钮的控件指针。

2,用单选按钮的“clicked”信号加回调函数来显示用户的选择。

单选按钮是继承自多选按钮的,单个的单选按钮和多选按钮在功能上是一样的。

2.3.2创建消息框

1,创建消息框控件

消息框控件时GTK+2.0中特有的。用gtk_dialog_new函数来创建,他有如下参数:

●暂用的父窗口控件,GtkWindow类型,可以设为NULL,表示无父窗口。

●消息框标记,可以取值为GTK_DIALOG_MODAL,模态对话框;GTK_DIALOG_DES TORY_WITH_PARENT,与父控件一起被销毁;GTK_DIALOG_NO_SEPARAOR,在消息框的按钮上面没有分割横线。

●消息类型,可以取四个宏定义值之一,分别是:GTK_MESSAGE_INFO,信息;GTK_MESSAGE_ERROR,错误;GTK_MESSAGE_WARNING,警告;

6

GTK_MESSAGE_QUESTION,问题。

●消息框中的按钮类型,有以下宏定义:GTK_BUTTONS_NONE,无按钮;GTK_BUTTONS_OK,确认;GTK_BUTTONS_CLOSE,关闭;GTK_BUTTONS_CANCEL,取消;GTK_YES_NO,是/否按钮;GTK_BUTTONS_OK_CANCLE,确认/取消按钮。

●格式化的字符串信息,与g_print活printf格式想听的格式化字符串,用于消息框中现实输出。

2,运行消息框

运行消息框用函数gtk_dialog_run,此函数的参数是消息框的控件指针,返回一个整数值,代表消息框运行时用户点击的按钮标记,编程时根据此标记判断用户的选择。运行结束后直接用gtk_widget_destory函数将其销毁。

2.4综合实现

1,构件界面

采用一个纵向盒状容器和多个横向盒状容器设计。另外在单行输入控件的阅读方向属性上用函数gk_widget_set_direction设定为GTK_TEXIT_DIR_RTL,即从右向左,使此控件的数字显示器更像是一个计算器的显示屏。

2,数字按钮的回调函数

数字按钮0~9的功能是向计算器输入数字,通过计位和定位,最后显示出来,所以它们的回调函数都是同一个,只不过是传递的参数根据不同的按钮传递不同的数字。

3,小数点按钮的回调函数

小数点按钮的回调函数是较特殊的一个。首先小数点在一个数中只能出现一次,再按得话则不起作用,小数地按钮子点击后要对所输入的数字做处理,使之成为浮点数,并且让后续数字也转换为相应的浮点数字。

4,运算按钮回调函数

次计算器只有加减乘除四种运算功能,这四个运算按钮用了同一个回调函数,根据传递的参数设定当前的计算方法。

5,等号按钮的回调函数是根据当前的计算方法进行相应的运算,并将计算结果输出到简单输出控件中。

6,清除按钮的回调函数

清除按钮的功能是清楚当前显示,同时清楚所有标记,将标记设为默认等。

程序多次用到stdlib.H和glib中共的字符串转换成浮点数和浮点数转换成字符串等转换函数。

此外,TK+2.0编程界面代码占了很大一部分,而且很复杂,但这只是一些排

7

8 列控件函数和信号连接宏的简单组合。

附程序窗口截图:

2.4

结束语

本文主要简单说明了如何在Linux系统中用GTK+2.0来实现一个简单的六位计算功能的计算器。此程序虽然简单,但是涵盖了GTK+中的很多最基础的诸如窗口创建,如何在窗口中添加控件,对话框的实现等等知识。就像学习C语言一样,用小的例子来阐释其基本算法,基本思想。然后再引导大家由浅入深的学习Linux平台上的图形界面的编程。本文更详细的说明了几种回调函数的的应用,如数字按钮的回调函数,运算按钮的回调函数等。程序设计完成后,还需要进行编译运行,当然Linux环境下很多用gcc编译,此次也是基于gcc,但是可以用Makefile——自动化编译。可以更综合全面的学习如何编译Makefile。自已希望通过这个小程序更好的来学习Linux的编程,学习和研究开源软件,将来在这方面有所成就。

9

代码

源程序代码:

/*******************计算器calc.c***********************************/ #include

#include

static GtkWidget *entry;//定义单行输入控件来现实输入输出的数字

gint count=0;//计位

gdouble nn=0;//计数一

gdouble mm=0;//计数二

gint s=0;//算法

gboolean first=TRUE;//首次输入

gboolean have_dot=FALSE;//是否有小数点

gboolean have_result=FALSE;//是否有结果输出

gchar number[100];//保持用户输入的数字

void clear_all (void)

{

//清除所有相关标记

gint i;

gtk_entry_set_text(GTK_ENTRY(entry),"");

nn=0;

mm=0;

s=0;

count=0;

first=TRUE;

have_dot=FALSE;

have_result=FALSE;

for(i=0;i<100;i++)

number[i]='\0';

}

void on_num_clicked (GtkButton *button,gpointer data)

10

{

//当数字键按下时执行

const gchar *num;

gint i;

if(have_result)

clear_all();//有结果则全部清除

if(count==6) return;//够6位数则不能再输入数字

count++;

num=gtk_button_get_label(GTK_BUTTON(button));//取数

i=g_strlcat(number,num,100);//保持

if(first)

nn=strtod(number,NULL);//数一

else

mm=strtod(number,NULL);//数二

gtk_entry_set_text(GTK_ENTRY(entry),number);//显示

}

void on_dot_clicked (GtkButton *button,gpointer data)

{

//当小数点按下时

gint i;

if(have_result)

clear_all();//全部清除

if(have_dot==FALSE) //如果无小数点则可以

{

have_dot=TRUE;

i=g_strlcat(number,".",100);

gtk_entry_set_text(GTK_ENTRY(entry),number);

}

//如果有小数点则不输出

}

void on_clear_clicked (GtkButton *button,gpointer data)

{

11

clear_all();//全部清除

}

void on_suan_clicked (GtkButton *button,gpointer data)

{

//当计算按钮+ - * /按下时

gint i;

switch(GPOINTER_TO_INT(data))

{

case 1://"+"

s=1;

gtk_entry_set_text(GTK_ENTRY(entry),"");

first=FALSE;

count=0;

break;

case 2://"-"

s=2;

gtk_entry_set_text(GTK_ENTRY(entry),"");

first=FALSE;

count=0;

break;

case 3://"*"

s=3;

gtk_entry_set_text(GTK_ENTRY(entry),"");

first=FALSE;

count=0;

break;

case 4://"/"

s=4;

gtk_entry_set_text(GTK_ENTRY(entry),"");

first=FALSE;

count=0;

break;

}

12

have_dot=FALSE;

for(i=0;i<100;i++) //清除数字

number[i]='\0';

}

void on_eq_clicked (GtkButton *button,gpointer data)

{

//当等号键按钮按下时

double numb;

gchar num[100];

gchar *result;

switch(s)

{

case 1://"+"

numb=nn+mm;

break;

case 2://"-"

numb=nn-mm;

break;

case 3://"*"

numb=nn*mm;

break;

case 4://"/"

numb=nn/mm;

break;

}

result=g_ascii_dtostr(num,100,numb);

gtk_entry_set_text(GTK_ENTRY(entry),result);

have_result=TRUE;

}

int main(int argc,char *argv[])

{

13

GtkWidget *window;

GtkWidget *vbox;

GtkWidget *hbox,*hbox1,*hbox2,*hbox3,*hbox4;

GtkWidget *button;

GtkWidget *label;

gtk_init(&argc,&argv);

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),"璁$畻鍣?);

gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); gtk_container_set_border_width(GTK_CONTAINER(window),10);

vbox=gtk_vbox_new(FALSE,0);

gtk_container_add(GTK_CONTAINER(window),vbox);

hbox=gtk_hbox_new(FALSE,0);

gtk_box_pack_start(GTK_BOX(vbox),hbox,FALSE,FALSE,5);

label=gtk_label_new("计算器");

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(on_clear_clicked),NULL);

entry=gtk_entry_new();

gtk_widget_set_direction(entry,GTK_TEXT_DIR_RTL);

gtk_box_pack_start(GTK_BOX(vbox),entry,FALSE,FALSE,5);

hbox1=gtk_hbox_new(FALSE,0);

gtk_box_pack_start(GTK_BOX(vbox),hbox1,FALSE,FALSE,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",

14

G_CALLBACK(on_num_clicked),NULL);

button=gtk_button_new_with_label("2");

gtk_box_pack_start(GTK_BOX(hbox1),button,TRUE,TRUE,5);

g_signal_connect(G_OBJECT(button),"clicked",

G_CALLBACK(on_num_clicked),NULL);

button=gtk_button_new_with_label("1");

gtk_box_pack_start(GTK_BOX(hbox1),button,TRUE,TRUE,5);

g_signal_connect(G_OBJECT(button),"clicked",

G_CALLBACK(on_num_clicked),NULL);

button=gtk_button_new_with_label("+");

g_signal_connect(G_OBJECT(button),"clicked",

G_CALLBACK(on_suan_clicked),(gpointer)1);

gtk_box_pack_start(GTK_BOX(hbox1),button,TRUE,TRUE,5);

hbox2=gtk_hbox_new(FALSE,0);

gtk_box_pack_start(GTK_BOX(vbox),hbox2,FALSE,FALSE,5);

button=gtk_button_new_with_label("6");

g_signal_connect(G_OBJECT(button),"clicked",

G_CALLBACK(on_num_clicked),NULL);

gtk_box_pack_start(GTK_BOX(hbox2),button,TRUE,TRUE,5);

button=gtk_button_new_with_label("5");

g_signal_connect(G_OBJECT(button),"clicked",

G_CALLBACK(on_num_clicked),NULL);

gtk_box_pack_start(GTK_BOX(hbox2),button,TRUE,TRUE,5);

button=gtk_button_new_with_label("4");

g_signal_connect(G_OBJECT(button),"clicked",

G_CALLBACK(on_num_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(on_suan_clicked),(gpointer)2);

gtk_box_pack_start(GTK_BOX(hbox2),button,TRUE,TRUE,5);

hbox3=gtk_hbox_new(FALSE,0);

15

gtk_box_pack_start(GTK_BOX(vbox),hbox3,FALSE,FALSE,5);

button=gtk_button_new_with_label("9");

g_signal_connect(G_OBJECT(button),"clicked",

G_CALLBACK(on_num_clicked),NULL);

gtk_box_pack_start(GTK_BOX(hbox3),button,TRUE,TRUE,5);

button=gtk_button_new_with_label("8");

g_signal_connect(G_OBJECT(button),"clicked",

G_CALLBACK(on_num_clicked),NULL);

gtk_box_pack_start(GTK_BOX(hbox3),button,TRUE,TRUE,5);

button=gtk_button_new_with_label("7");

g_signal_connect(G_OBJECT(button),"clicked",

G_CALLBACK(on_num_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(on_suan_clicked),(gpointer)3);

gtk_box_pack_start(GTK_BOX(hbox3),button,TRUE,TRUE,5);

hbox4=gtk_hbox_new(FALSE,0);

gtk_box_pack_start(GTK_BOX(vbox),hbox4,FALSE,FALSE,5);

button=gtk_button_new_with_label("0");

g_signal_connect(G_OBJECT(button),"clicked",

G_CALLBACK(on_num_clicked),NULL);

gtk_box_pack_start(GTK_BOX(hbox4),button,TRUE,TRUE,5);

button=gtk_button_new_with_label(".");

g_signal_connect(G_OBJECT(button),"clicked",

G_CALLBACK(on_num_clicked),NULL);

gtk_box_pack_start(GTK_BOX(hbox4),button,TRUE,TRUE,5);

button=gtk_button_new_with_label("=");

g_signal_connect(G_OBJECT(button),"clicked",

G_CALLBACK(on_num_clicked),NULL);

gtk_box_pack_start(GTK_BOX(hbox4),button,TRUE,TRUE,5);

button=gtk_button_new_with_label("/");

g_signal_connect(G_OBJECT(button),"clicked",

16

G_CALLBACK(on_suan_clicked),(gpointer)4);

gtk_box_pack_start(GTK_BOX(hbox4),button,TRUE,TRUE,5);

gtk_widget_show_all(window);

gtk_main();

return FALSE;

}

Makefile:

CC=gcc

all:

$(CC) -o calc calc `pkg-config --cflags --libs gtk+-2.0`

17

本文来源:https://www.bwwdw.com/article/duhe.html

Top