calculator.c

来自「开发linux应用-用gtk+和gdk开发linux图形用户界面应用--的实例」· C语言 代码 · 共 531 行

C
531
字号
/* * Calculator.c * * Example showing different widgets in use. **/#include "gtk/gtk.h"#include <math.h>#include <ctype.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 *labelText;    char buffer[BUF_SIZE];    int  len;    /* --- And they just did a command --- */    if (Command (lastChar)) {        /* --- Clear the digit field --- */        gtk_label_set (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 --- */    gtk_label_get (GTK_LABEL (label), &labelText);    strcpy (buffer, labelText);    /* --- 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 (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 *labelText;    char buffer[BUF_SIZE];    float num2;    /* --- Get number in the field. --- */    gtk_label_get (GTK_LABEL (label), &labelText);    num2 = atof (labelText);    /* --- 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 (GTK_LABEL (label), buffer);}void HandleBinaryOperation (){    char buffer[BUF_SIZE];    char *labelText;    float num2;    /* --- Get number in the field. --- */    gtk_label_get (GTK_LABEL (label), &labelText);    num2 = atof (labelText);    /* --- 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 (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 (GTK_LABEL (label), "0");            return;        /* --- BIG clear? --- */        } else if (strcmp (str, "C") == 0) {            prevCmd = (char) 0;            lastChar = (char) 0;            gtk_label_set (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 * table in the proper place.*/GtkWidget *CreateButton (GtkWidget *table, 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 --- */    gtk_signal_connect (GTK_OBJECT (button), "clicked",                        GTK_SIGNAL_FUNC (button_clicked), szLabel);    /* --- Put the button in the table in the right place. --- */    gtk_table_attach (GTK_TABLE (table), button,                       column, column+1,                       row, row + 1,                       GTK_FILL | GTK_EXPAND,                       GTK_FILL | GTK_EXPAND,                       5, 5);    /* --- Make the button visible --- */    gtk_widget_show (button);    /* --- return the button. --- */    return (button);}/* * CreateCalculatorButtons * * Create the buttons on the calculator from the table we defined at the * beginning of this program.  The button pointers (handles) are stored * back in the table so they can be referenced later.*/void CreateCalculatorButtons (GtkWidget *table){    int nIndex;    /* --- Run through the list of buttons. --- */    for (nIndex = 0; nIndex < nButtons; nIndex++) {        /* --- Create a button --- */        buttonList[nIndex].widget =                 CreateButton (table,                               buttonList[nIndex].szLabel,                               buttonList[nIndex].row,                               buttonList[nIndex].col);    }}/* * main * * Program begins here*/int main (int argc, char *argv[]){    GtkWidget *window;    GtkWidget *table;    /* --- 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_usize (window, 200, 200);    /* --- We care if a key is pressed --- */    gtk_signal_connect (GTK_OBJECT (window), "key_press_event",                        GTK_SIGNAL_FUNC (key_press), NULL);    /* --- You should always remember to connect the delete event     *     to the main window. --- */    gtk_signal_connect (GTK_OBJECT (window), "delete_event",                        GTK_SIGNAL_FUNC (CloseAppWindow), NULL);    /* --- Create a 5x5 table for the items in the calculator. --- */    table = gtk_table_new (5, 5, TRUE);     /* --- Create the calculator buttons. --- */    CreateCalculatorButtons (table);    /* --- Create the calculator LED --- */    label = gtk_label_new ("0");    gtk_misc_set_alignment (GTK_MISC (label), 1, .5);    /* --- Add label to the table --- */    gtk_table_attach_defaults (GTK_TABLE (table), label,                               0, 4, 0, 1);    gtk_widget_show (label);      /* --- Make them visible --- */    gtk_container_add (GTK_CONTAINER (window), table);    gtk_widget_show (table);    gtk_widget_show (window);    /* --- Grab focus for the keystrokes --- */    //gtk_widget_grab_focus (buttonList[0].widget);    gtk_main ();    return (0);}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?