第133页的gtk+编程例子——编写计算器应用

news2024/9/24 9:27:21

第133页的gtk+编程例子——编写计算器应用

以下gtk+编程例子是来自书籍《实用技术:开发Linux应用——用GTK+和GDK开发Linux图形用户界面应用》第133页的内容——编写计算器应用
例子程序是在gtk2.0编译的,已经修改许多地方才能在gtk3.0编译通过,尝试在gtk4.0编译,但是报错太多无法修改而成
书中的例子程序源代码可以到以下地址下载,也有有其它章节的例子程序
《Examples from “Developing Linux Applications with GTK+ and GDK” by Eric Harlow》
https://gitlab.com/steshaw/gtk-examples

《gtk计算器》是在gtk2.0编译的有效果图
https://rtoax.blog.csdn.net/article/details/88089639

在openSUSE-Leap-15.5-DVD-x86_64的gnome41.8桌面环境下编译的,其中pkg-config --cflags gtk±3.0两边有反引号括起来的,pkg-config --libs gtk±3.0也是一样两边有反引号括起来的,因为报错undefined reference to symbol 'sqrt@@GLIBC_2.2.5,所以一定要加上-lm选项,> mistake.text 2>&1 ; gedit mistake.text表示将编译过程的错误信息保存到文本文件mistake.text,编译完成后马上打开查看

ruhong@localhost:~/gtk/calculator> gcc -g -Wall -lm pkg-config --cflags gtk+-3.0 -o page133 page133.c pkg-config --libs gtk+-3.0 > mistake.text 2>&1 ; gedit mistake.text
ruhong@localhost:~/gtk/calculator> ./page133

/*
 * Calculator.c
 *
 * Example showing different widgets in use.
 *
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <ctype.h>
#include <gtk/gtk.h>

static float num1 = 0;
static char lastChar = (char) 0;
static char prevCmd = (char) 0;
#define BUF_SIZE 88

/*
 * --- data structure to keep track of the calculator buttons.
*/
typedef struct {

    char      *szLabel;    /* --- Label display on button --- */
    int       row;         /* --- Row to place the button --- */
    int       col;         /* --- Column to place the button --- */
    GtkWidget *widget;     /* --- Handle to the button --- */

} typCalculatorButton;


/* 
 * --- This is the button list.  Each button is documented here so 
 *     we can access it.
*/
typCalculatorButton buttonList [] = {
    {"C",   1, 0, NULL},      /* --- Clear --- */
    {"CE",  1, 1, NULL},      /* --- Clear --- */
    {"/",   1, 3, NULL},      /* --- Division --- */

    {"7",   2, 0, NULL},      /* --- Digit --- */
    {"8",   2, 1, NULL},      /* --- Digit --- */
    {"9",   2, 2, NULL},      /* --- Digit --- */
    {"*",   2, 3, NULL},      /* --- Multiplication --- */
    {"%",   2, 4, NULL},      /* --- Percent --- */

    {"4",   3, 0, NULL},      /* --- Digit --- */
    {"5",   3, 1, NULL},      /* --- Digit --- */
    {"6",   3, 2, NULL},      /* --- Digit --- */
    {"-",   3, 3, NULL},      /* --- Subtraction --- */
    {"1/x", 3, 4, NULL},      /* --- 1/x --- */

    {"1",   4, 0, NULL},      /* --- Digit --- */
    {"2",   4, 1, NULL},      /* --- Digit --- */
    {"3",   4, 2, NULL},      /* --- Digit --- */
    {"+",   4, 3, NULL},      /* --- Addition --- */
    {"sqrt",4, 4, NULL},      /* --- Square root --- */

    {"+/-", 5, 0, NULL},      /* --- Negate value --- */
    {"0",   5, 1, NULL},      /* --- zero --- */
    {".",   5, 2, NULL},      /* --- Decimal --- */
    {"=",   5, 3, NULL},      /* --- Equals/total --- */
    {"x^2", 5, 4, NULL},      /* --- Squared --- */
};

/*
 * --- Number of buttons in the data structure.  
*/
int nButtons = sizeof (buttonList) / 
               sizeof (typCalculatorButton);

/* --- This is the LCD panel - the results --- */
GtkWidget *label;


/*
 * CloseAppWindow
 *
 * The window is closing down, end the gtk loop
*/
gint CloseAppWindow (GtkWidget *widget, gpointer data)
{
    gtk_main_quit ();

    return (FALSE);
}


/*
 * TrimTrailingZeros
 *
 * Get rid of trailing zeros 
 * Takes the string and removes the trailing zeros.
*/
void TrimTrailingZeros (char *szDigits)
{
    int nIndex;
    int bDecimal = FALSE;
    int nPos = -1;

    /* --- Loop through the string. --- */
    for (nIndex = 0; nIndex < strlen (szDigits); nIndex++) {

        /* --- Is this a decimal? --- */
        if (szDigits[nIndex] == '.') {
             bDecimal = TRUE;
        }

        /* --- If we're on the right side of the decimal... --- */
        if (bDecimal) {

            /* --- A zero?  Hmm... from this point on? --- */
            if (szDigits[nIndex] == '0') {

               /* --- If we don't have a point yet... --- */
               if (nPos < 0) {
 
                   /* --- Save this as a point. --- */
                   nPos = nIndex;
               }
            } else {

               /* --- Clear it.  Bad point. --- */
               nPos = -1;
            }
        }
    }

    /* --- Truncate the field. --- */
    if (nPos > 0) {
        szDigits[nPos] = (char) 0;
    }
}


/*
 * TrimLeadingZeros
 *
 * Trim the leading zeros.
 * 
 * Converts numbers like "0000012" to "12"
*/
void TrimLeadingZeros (char *szDigits)
{
    int nPos;

    if (szDigits == NULL) return;

    /* --- While we have a combination a digit in front --- */
    for (nPos = 0; (szDigits[nPos] && szDigits[nPos] == '0'); nPos++) {

        /* --- If the digit is a zero and next char is a digit --- */
        if (isdigit (szDigits[nPos+1])) {

            /* --- Blank the field. --- */  
            szDigits[nPos] = ' ';
        } 
    }
}


/*
 * Command
 *
 * Returns true if the character is a two digit command.
*/
int Command (char ch)
{
    switch (ch) {
        case '+':
        case '-':
        case '/':
        case '*':
        case '=':
            return (TRUE);
    }
    return (FALSE);
}

/*
 * FloatingPointChar
 *
 * Returns true if the character is any of [0123456789.]
*/
int FloatingPointChar (char ch)
{

    return (isdigit (ch) || ch == '.');
}


/*
 * key_press
 *
 * Handle the button "key_press" event.
 *
 * Function looks for the keystroke in the calculator 
 * data structure and (if a match is found) presses the 
 * button that matches the keystroke for the user.  It
 * keeps our code small since we only have to handle the
 * button_clicked events.
*/
void key_press (GtkWidget *widget, 
                GdkEventKey *event, 
                gpointer data)
{
    int nIndex;

    /* --- Search through the buttons --- */
    for (nIndex = 0; nIndex < nButtons; nIndex++) {

        /* --- If the keystroke is the first character of a button AND --- */
        /* --- the button label length is one. --- */      
        if (event->keyval == buttonList[nIndex].szLabel[0] && 
            buttonList[nIndex].szLabel[1] == (char) 0) {

            /* --- Set focus to that button --- */
            gtk_widget_grab_focus (buttonList[nIndex].widget);

            /* --- Make like the button was clicked to do processing. --- */
            gtk_button_clicked (GTK_BUTTON (buttonList[nIndex].widget));
            return;
        }
    }
}


/*
 * HandleDigit
 *
 * Digit button was pressed, deal with it.  How it
 * is dealt with depends on the situation.
*/
void HandleDigit (char *str, char ch)
{
    char buffer[BUF_SIZE];
    int  len;

    /* --- And they just did a command --- */
    if (Command (lastChar)) {

        /* --- Clear the digit field --- */
        gtk_label_set_text (GTK_LABEL (label), "");

        /* --- If they did a computation --- */
        if (lastChar == '=') {

            /* --- Clear out the command --- */
            lastChar = (char) 0;
            prevCmd = (char) 0;
        }
    }

    /* --- Get the buffer in the led --- */
    strcpy (buffer, gtk_label_get_text (GTK_LABEL (label)));

    /* --- Add the new character on it. --- */
    len = strlen (buffer);
    buffer[len] = (gchar) ch;
    buffer[len+1] = (gchar) 0;
   
    /* --- Trim leading zeros. --- */
    TrimLeadingZeros (buffer);

    /* --- Add digit to field. --- */
    gtk_label_set_text (GTK_LABEL (label), (char *) buffer);
}


/*
 * MaybeUnary
 *
 * str
 * 
 * Check to see if the user hit a unary operator button - 
 * like %, sqrt, 1/x, etc that should be dealt with NOW
 * not later.
*/
void MaybeUnaryOperation (char *str)
{
    char buffer[BUF_SIZE];
    float num2;

    /* --- Get number in the field. --- */
    num2 = atof (gtk_label_get_text (GTK_LABEL (label)));

    /* --- Percentage? --- */
    if (strcmp (str, "%") == 0) {
        num2 = num2 / 100;

    /* --- Trying for 1/x? --- */
    } else if (strcmp (str, "1/x") == 0) {

        /* --- Can't divide by zero. --- */
        if (num2 == 0) {
            /*Error (); */
            return;
        }
        num2 = 1 / num2;

    /* --- Calculate sqrt --- */
    } else if (strcmp (str, "sqrt") == 0) {
        num2 = sqrt ((double) num2);

    /* --- Calculate square --- */
    } else if (strcmp (str, "x^2") == 0) {
        num2 = num2 * num2;
    }

    /* --- Put the number back. --- */
    sprintf (buffer, "%f", (float) num2);
    TrimTrailingZeros (buffer);
    TrimLeadingZeros (buffer);
    gtk_label_set_text (GTK_LABEL (label), buffer);
}


void HandleBinaryOperation ()
{
    char buffer[BUF_SIZE];
    float num2;

    /* --- Get number in the field. --- */
    num2 = atof (gtk_label_get_text (GTK_LABEL (label)));

    /* --- Calculate based on previous command. --- */
    switch (prevCmd) {
        case '+':
            num1 = num1 + num2;               
            break;

        case '-':
            num1 = num1 - num2;               
            break;

        case '*':
            num1 = num1 * num2;               
            break;

        case '/':
            num1 = num1 / num2;               
            break;

        case '=':
            num1 = num2;
            break;

        default:
            num1 = num2;
            break;
    }

    /* --- Put the number back. --- */
    sprintf (buffer, "%f", (float) num1);
    TrimTrailingZeros (buffer);
    TrimLeadingZeros (buffer);
    gtk_label_set_text (GTK_LABEL (label), buffer);
}


/*
 * button_clicked
 *
 * widget - button pressed.
 * data - button label.
 *
 * Button was pressed, handle it.
*/
void button_clicked (GtkWidget *widget, gpointer data)
{
    char ch = *((char *) data);
    char *str;
    
    /* --- Get the button label --- */
    str = (char *) data;

    /* --- Entering a number... --- */
    if (FloatingPointChar (ch) && strlen (str) == 1) {

        HandleDigit (str, ch);

    } else {

        /* --- Clear? --- */
        if (strcmp (str, "CE") == 0) {
            gtk_label_set_text (GTK_LABEL (label), "0");
            return;

        /* --- BIG clear? --- */
        } else if (strcmp (str, "C") == 0) {
            prevCmd = (char) 0;
            lastChar = (char) 0;
            gtk_label_set_text (GTK_LABEL (label), "0");
            return;

        } else {

            /* --- Maybe it's a unary operator? --- */
            MaybeUnaryOperation (str);
        }

        /* --- See if there's a binary operation to do --- */
        HandleBinaryOperation ();

        prevCmd = ch;
    }
    lastChar = ch;
}

/*
 * CreateButton
 *
 * Create a button, assign event handlers, and attach the button to the
 * grid in the proper place.
*/
GtkWidget *CreateButton (GtkWidget *grid, char *szLabel, int row, int column)
{
    GtkWidget *button;

    /* --- Create the button --- */
    button = gtk_button_new_with_label (szLabel);

    /* --- We care if the button is clicked --- */
    g_signal_connect (G_OBJECT (button), "clicked",
                        G_CALLBACK (button_clicked), szLabel);

    /* --- Put the button in the grid in the right place. --- */
    	 gtk_grid_attach (GTK_GRID (grid), button, column, row, 1, 1);
    	 
    /* --- Make the button visible --- */
    gtk_widget_show (button);

    /* --- return the button. --- */
    return (button);
}



/*
 * CreateCalculatorButtons
 *
 * Create the buttons on the calculator from the grid we defined at the
 * beginning of this program.  The button pointers (handles) are stored
 * back in the grid so they can be referenced later.
*/
void CreateCalculatorButtons (GtkWidget *grid)
{
    int nIndex;

    /* --- Run through the list of buttons. --- */
    for (nIndex = 0; nIndex < nButtons; nIndex++) {

        /* --- Create a button --- */
        buttonList[nIndex].widget = 
                CreateButton (grid, 
                              buttonList[nIndex].szLabel, 
                              buttonList[nIndex].row, 
                              buttonList[nIndex].col);
    }
}

/*
 * main
 *
 * Program begins here
*/
int main (int argc, char *argv[])
{
    GtkWidget *window;
    GtkWidget *grid;

    /* --- GTK initialization --- */
    gtk_init (&argc, &argv);

    /* --- Create the calculator window --- */
    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);

    /* --- Give the window a title. --- */
    gtk_window_set_title (GTK_WINDOW (window), "Calculator");

    /* --- Set the window size. --- */
    gtk_widget_set_size_request (window, 200, 200);

    /* --- We care if a key is pressed --- */
    g_signal_connect (G_OBJECT (window), "key_press_event",
                        G_CALLBACK (key_press), NULL);

    /* --- You should always remember to connect the delete event
     *     to the main window. --- */
    g_signal_connect (G_OBJECT (window), "delete_event",
                        G_CALLBACK (CloseAppWindow), NULL);

    /* --- Create a 5x5 grid for the items in the calculator. --- */
    grid = gtk_grid_new (); 
	 gtk_grid_set_row_homogeneous(GTK_GRID(grid), TRUE);
	 gtk_grid_set_column_homogeneous(GTK_GRID(grid), TRUE);

    /* --- Create the calculator buttons. --- */
    CreateCalculatorButtons (grid);

    /* --- Create the calculator LED --- */
    label = gtk_label_new ("0");
	 gtk_label_set_xalign (GTK_LABEL (label), 1);
	 /*--- 水平方向X居右,垂直方面Y居中 ---*/
	 gtk_label_set_yalign (GTK_LABEL (label), 0.5);

    /* --- Add label to the grid --- */
    gtk_grid_attach (GTK_GRID (grid), label, 0, 0, 4, 1);
    
    gtk_widget_show (label);
  
    /* --- Make them visible --- */
    gtk_container_add (GTK_CONTAINER (window), grid);
    gtk_widget_show (grid);
    gtk_widget_show (window);

    /* --- Grab focus for the keystrokes --- */
    //gtk_widget_grab_focus (buttonList[0].widget);

    gtk_main ();
    return (0);
}

效果图如下
在这里插入图片描述

参考文章:
《GTK的计算器》
https://blog.csdn.net/zhouzhouzf/article/details/17097999

《编译错误“ undefined reference to ‘sqrt‘ ”解决方法小结》
https://blog.csdn.net/wangqingchuan92/article/details/115261070

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/710534.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数学建模——插值(上)

本文是面向数学建模准备的&#xff0c;是介绍性文章&#xff0c;没有过多关于原理的说明&#xff01;&#xff01;&#xff01; 插值方法简介 插值问题 已知区间[a,b]上有系列观测值(xi,yi),i0,1,2,…,n&#xff0c;求一条曲线把这些点依次连接起来&#xff0c;称为插值&#…

在idea中高并发下的分布式锁以及解决方法

案例:1.互联网秒杀 2.抢优惠卷 3.接口幂 引入pom文件 <packaging>war</packaging><dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.2.8.RELEA…

分布式软件架构——客户端缓存

浏览器的客户端缓存 当万维网刚刚出现的时候&#xff0c;浏览器的缓存机制差不多就已经存在了。在 HTTP 协议设计之初&#xff0c;人们便确定了服务端与客户端之间“无状态”&#xff08;Stateless&#xff09;的交互原则&#xff0c;即要求客户端的每次请求是独立的&#xff…

MySQL环境搭建(Windows电脑)

MySQL环境搭建-Windows电脑篇 软件获取&#xff1a; 搜索gzh【李桥桉】&#xff0c;需要win电脑安装包&#xff0c;回复【win-MS】。 搜索gzh【李桥桉】&#xff0c;需要mac电脑安装包&#xff0c;回复【mac-MS】。 注意&#xff1a;确保电脑为64位系统&#xff08;不是的话需要…

华为手环8相册表盘使用指南

随着科技的发展&#xff0c;智能手环已经成为越来越多人的选择。华为手环8作为一款备受好评的智能手环&#xff0c;不仅具备精准的监测功能&#xff0c;还拥有丰富的表盘样式。本文将向您介绍华为手环8如何使用相册表盘&#xff0c;通过这一功能&#xff0c;您可以轻松地将您的…

Windows 打开cmd/dos窗口的12种方式(全网最全)

文章目录 1. 从开始菜单的应用列表打开2. 从搜索打开3. 从运行打开4. 从文件资源管理器打开5. 从C:\Windows\System32\cmd.exe打开6. 从桌面>快捷方式打开&#xff08;需自己创建&#xff09;7. 从任务栏>快捷方式打开&#xff08;需自己创建&#xff09;8. 从开始菜单&g…

TV快应用系列——1.ExtScreen框架快速入门

系列文章目录 TV快应用系列——1.ExtScreen框架快速入门 ExtScreen框架快速入门 系列文章目录前言一、ExtScreen简介整体结构扩展屏和应用的区别 二、安装和环境配置1.安装编辑工具2.安装Vue开发环境1.1.1安装 Node1.1.2安装配置 npm下载安装npmnpm 设置淘宝镜像安装 vue-cli&…

图像分割的大变革:从SAM(分割一切)到FastSAM、MobileSAM

前言 SAM就是一类处理图像分割任务的通用模型。与以往只能处理某种特定类型图片的图像分割模型不同&#xff0c;SAM可以处理所有类型的图像。 在SAM出现前&#xff0c;基本上所有的图像分割模型都是专有模型。比如&#xff0c;在医学领域&#xff0c;有专门分割核磁图像的人工…

『DotNetBrowser』在.Net中的浏览器嵌入组件,该选择DotNetBrowser 还是 CefSharp?

&#x1f4e3;读完这篇文章里你能收获到 全方位对比DotNetBrowser 和 CefSharp的优缺点 文章目录 一、引言二、引擎三、架构1. CefSharp架构2. DotNetBrowser架构 四、对比1. 稳定性和内存使用2. 应用程序域3. AnyCPU4. H.264, AAC5. 安全6. Visual Studio设计器7. 嵌入应用程…

八、c++学习(加餐4:深入分析new和delete)

经过了两篇的类和对象分析&#xff0c;我们这一篇再次加餐&#xff0c;对new和malloc的分析&#xff0c;malloc的源码不在这篇介绍&#xff0c;会放到linux篇的内存池专题&#xff0c;所以我们这篇只要分析new。 这篇的主要目的就是&#xff0c;对象是怎么new出来的&#xff0…

技术干货——Selenium Python使用技巧(三)

目录 处理不同情况的等待 网页中的滚动操作 使用Selenium放大和缩小 查找元素的大小 获取元素的X和Y坐标 使用自定义配置文件禁用JavaScript 设置手动代理设置 总结&#xff1a; 处理不同情况的等待 在Selenium自动化测试中网页可能需要花费一些时间来加载&#xff0c;…

MybatisPlus从入门到精通-基础篇

文章目录 一、概述二、快速入门2.1 数据库准备2.2 创建springboot工程2.3 实体类准备2.4 测试MybatisPlus 三、MP常用配置3.1 设置表映射规则3.2 设置主键生成策略3.3 设置字段映射关系3.4 设置字段和列名的驼峰映射3.5 日志 四、基本使用4.1 增加&#xff08;插入&#xff09;…

TF卡/U盘扩容

1. 问题 在使用大于镜像、对TF卡/U盘烧录镜像以后&#xff0c;TF卡/U盘会出现一部分的空闲内存无法被使用&#xff0c;导致出现使用空间不足的报错&#xff0c;或运行大型项目不成功。 注意&#xff1a;本教程仅针对自行烧录镜像的用户&#xff0c;TF卡/U盘内如有出厂镜像则可…

【数据挖掘】时间序列教程【四】

3.3 划分变体 我们可以对上述 的主模型采用方差分析方法,并将中的总变异分解为 为残差平方和和可归因于各种频率的变化。 第二行是可能的,因为平方的所有交叉项都等于零,即对于所有 ,

基于JavaSwing的五子棋游戏设计

点击以下链接获取源码&#xff1a; https://download.csdn.net/download/qq_64505944/87987074?spm1001.2014.3001.5503 运行截图&#xff1a;

4.22. 卷积定理

1. 时域&#xff1a; 我们知道卷积运算是为了求系统的零状态响应的&#xff0c;即&#xff0c;如果输入给系统的信号是f(t)&#xff0c;系统函数是h(t)&#xff0c;那系统的输出是什么&#xff1f; 就是按照上述方式卷积得到 那上述的卷积在频率域是什么呢&#xff1f; 2. 卷积…

windows系统下的nvm环境安装

1、下载 https://github.com/coreybutler/nvm-windows/releases 直接下载zip包 并安装 2、安装 注意&#xff1a;尽量按照默认路径安装 否则可能出现 nvm 安装完成 后面下载使用node的时候有问题 3、安装完成检测 打开cmd命令 输入 nvm -v出现版本号 则安装成功 4、se…

FullGC调优100倍,掌握这3招,吊打JVM调优

前言&#xff1a; 在40岁老架构师尼恩的读者社区&#xff08;50&#xff09;中&#xff0c;很多小伙伴拿不到offer&#xff0c;或者拿不到好的offer。 尼恩经常给大家 优化项目&#xff0c;优化简历&#xff0c;挖掘技术亮点。 在指导简历的过程中&#xff0c; 线上问题排查…

【实用教程】教你一招 IDE 中比较骚的操作技巧!

我靠&#xff0c;这是个高手&#xff01;这真是个高手&#xff01; IDEA 有个很牛逼的功能&#xff0c;那就是后缀补全&#xff08;不是自动补全&#xff09;&#xff0c;很多人竟然不知道这个操作&#xff0c;还在手动敲代码。 这个功能可以使用代码补全来模板式地补全语句&…

02_04_02实时调度类_线程优先级代码实战

知识回忆 基础知识 Linux内核当中有3种调度策略: . SCHED_ OTHER分时调度策略;(普通进程) SCHED_ FIFO 实时调度策略,先到先服务; SCHED RR实时调度策略&#xff0c;时间片轮转。 备注:如果有相同优先级的实时进程(根据优先级计算的调度权值是一样的)已经准备好&#xff0c;FI…