GTK+/Kalkulator w C++

Jednym z powodów, dla których nie wybiera się użycia biblioteki GTK+ na rzecz innych jest to, że nie dostarcza ona obiektowego interfejsu.
Nie oznacza to, że nie można programować obiektowo np. w C++ z użyciem GTK+. W celu zademonstrowania jak można to zrobić, przepiszemy nasz kalkulator w języku C++.
Posiadamy dwie klasy, jedną na mechanizmy samego kalkulatora, drugą dziedziczącą po pierwszej opisującą tylko mechanizmy samego interfejsu graficznego. Najważniejszy jest tu fakt rozdzielenia kodu programu kalkulatora przez kod budowy interfejsu użytkownika. Ten ostatni dzięki dziedziczeniu po klasie bazowej naszego programu ma bezpośredni dostęp do jego metod. Tworząc okno kalkulatora nasz program posiada już funkcję realizujące właściwe liczenie.



kalkulator.hpp zawiera deklaracje klasy opisującej zadania jakie ma spełniać kalkulator, bez interfejsu graficznego.
Zmiany w organizacji kodu:

  • nowy typ wyliczeniowy btn_id zastępuje umowne wartości dla zmiennej prev_button, obecnie zmienna ta jest typu btn_id. Ponieważ wartościom zmiennej prev_button typu btn_id dla przycisków numerycznych z klawiatury kalkulatora odpowiada ta sama liczba jaką reprezentuje przycisk (np. wartość Button_5 = 5). Wykorzystywaliśmy to już poprzednio w funkcji obsługi każdego przycisku numerycznego do wstawiania odpowiadającej mu liczby na wyświetlaczu. W celu ułatwienia tego zadania zdefiniowano nową funkcje:
    • const char* _btn_id_to_char(btn_id val); - zamienia wartość typu btn_id na char*
  • podobnie zdefiniowano nowy typ dla zmiennej operation. Dodano dwie nowe funkcje konwertujące:
    • const char* _operation_id_to_char(operation_id val); - zamienia wartość typu operation_id na char* (wykorzystywana w celach debugujących)
    • btn_id _operation_id_to_btn_id(operation_id val); - zamienia wartość typu operation_id na btn_id (używa się jej w funkcjach obsługi działań przycisków +, -, *, /, na podstawie wywołanego działania ustawiana jest zmienna prev_button)
  • funkcja void __debug(const gchar* event,bool data); zastępuje poprzednią void info (Kalkulator * pkalkulator, gchar* event).
  • poprzednią funkcję licz() nazwano void calculate(bool);

#include <gtk/gtk.h>

enum btn_id
{
  Button_1 = 1,  Button_2 = 2,  Button_3 = 3,  Button_4 = 4,  Button_5 = 5,
  Button_6 = 6,  Button_7 = 7,  Button_8 = 8,  Button_9 = 9,  Button_0 = 0,
  Button_add = 10,  Button_sub = 11,  Button_multi = 12,  Button_div = 13,
  Button_result = 14,
  Button_comma = 15,  Button_back = 16,  Button_clear = 17,
  NoSelectBtn = 20
};
enum operation_id
{
  Add = 1, Sub = 2, Multi = 3, Div = 4, NoSelectOprt = 5
};

class Kalkulator
{
  private:
    GString *value1;
    GString *value2;
    operation_id operation;
    operation_id prev_operation;
    gboolean is_value1;
    gboolean is_value2;
    gboolean is_result;
    btn_id prev_button;

  public:
    Kalkulator();
    ~Kalkulator();
    const char*  _btn_id_to_char(btn_id val);
    const char*  _operation_id_to_char(operation_id val);
    btn_id       _operation_id_to_btn_id(operation_id val);
    void __debug(const gchar* event,bool data);
    void calculate(bool);
    char* get_value1();
    void  set_value1(const gchar *val);
    bool  del_value1();
    char* get_value2();
    void  set_value2(const gchar *val);
    bool  del_value2();
    bool  get_is_value1() {return is_value1;};
    void  set_is_value1(bool val) {is_value1=val;};
    bool  get_is_value2() {return is_value2;};
    void  set_is_value2(bool val) {is_value2=val;};
    bool  get_is_result() {return is_result;};
    void  set_is_result(bool val) {is_result=val;};
    operation_id get_operation() {return operation;};
    void  set_operation(operation_id val) {operation=val;};
    operation_id get_prev_operation() {return prev_operation;};
    void  set_prev_operation(operation_id val) {prev_operation=val;};
    btn_id get_prev_button() {return prev_button;};
    void  set_prev_button(btn_id val) {prev_button=val;};
    
};


kalkulator.cpp zawiera definicje metod klasy Kalkulator.
Zmiany w organizacji kodu:

  • podczas tworzenia obiektu kalkulatora w konstruktorze nadajemy składowym neutralne wartości
  • funkcja __debug() oferuje dwa poziomy informowania, wyświetla zawartość składowych oraz zdarzenie jakie im towarzyszy, bądź tylko samo zdarzenie.
  • przekazywana wartość prev_operation_priv funkcji calculate() informuje ją o tym czy powinna wykonać obecne działanie czy poprzednie, umożliwia to wielokrotne wykonywanie działań na przemian.

#include <stdlib.h>
#include "kalkulator.hpp"


#define DEBUG
#define INFO
using namespace std;


Kalkulator::Kalkulator()
{
  #ifdef INFO
  __debug("Kalkulator konstruktor",false);
  #endif
  value1 = NULL;
  value2 = NULL;
  operation = NoSelectOprt;
  prev_operation = NoSelectOprt;
  is_value1 = FALSE;
  is_value2 = FALSE;
  is_result = FALSE;
  prev_button = NoSelectBtn;
}

Kalkulator::~Kalkulator()
{
  
  #ifdef INFO
  __debug("Kalkulator destruktor",false);
  #endif
}

const char* Kalkulator::_btn_id_to_char(btn_id val)
{
  return   val==Button_1 ? "1" :
           val==Button_2 ? "2" :
           val==Button_3 ? "3" :
           val==Button_4 ? "4" :
           val==Button_5 ? "5" :
           val==Button_6 ? "6" :
           val==Button_7 ? "7" :
           val==Button_8 ? "8" :
           val==Button_9 ? "9" :
           val==Button_0 ? "0" :
           val==Button_add ? "10" :
           val==Button_sub ? "11" :
           val==Button_multi ? "12" :
           val==Button_div ? "13" :
           val==Button_result ? "14" :
           val==Button_comma ? "15" :
           val==Button_back ? "16" :
           val==Button_clear ? "17" :
           "NoSelectBtn(20)";
}

const char* Kalkulator::_operation_id_to_char(operation_id val)
{
  return   val==Add ? "+" :
           val==Sub ? "-" :
           val==Multi ? "*" :
           val==Div ? "/" :
           "NoSelectOprt(5)";
}

btn_id Kalkulator::_operation_id_to_btn_id(operation_id val)
{
  return   val==Add ? Button_add :
           val==Sub ? Button_sub :
           val==Multi ? Button_multi : 
           val==Div ? Button_div :
           NoSelectBtn;
}

void Kalkulator::__debug(const gchar* event, bool data)
{
  if (data)
    printf (
"\n =============\n \
event: %s \n \
 - - - - -\n \
Struktura:\n \
  value1: %s \n \
  value2: %s \n \
  operation: %d \n \
  is_value1: %d \n \
  is_value2: %d \n \
  is_result: %d \n \
  prev_button: %d \n \
  prev_operation: %d \n \
- - - - -\n",
      event,
      is_value1? value1->str :"",
      is_value2? value2->str :"",
      operation,
      is_value1,
      is_value2,
      is_result,
      prev_button,
      prev_operation);
  else
    cout << event << endl;
}

void Kalkulator::calculate(bool prev_operation_priv)
{
  double d_value1=0,
         d_value2=0,
         d_result=0;
  int len, test(0);
  char s_result[50];

  // char* -> double
  d_value1 = strtod( value1->str, NULL );
  d_value2 = strtod( value2->str, NULL );
  
  if (prev_operation_priv)
  {
    test = prev_operation==Add ? 1 :
           prev_operation==Sub ? 2 :
           prev_operation==Multi ? 3 :
           prev_operation==Div ? 4 :
           NoSelectOprt;
  }
  else
  {
    
    test = operation==Add ? 1 :
           operation==Sub ? 2 :
           operation==Multi ? 3 :
           operation==Div ? 4 :
           NoSelectOprt;
  }
  switch(test)
  {
  case 1:
    d_result = d_value1 + d_value2;
    break;
  case 2:
    d_result = d_value1 - d_value2;
    break;
  case 3:
    d_result = d_value1 * d_value2;
    break;
  case 4:
    if ( d_value2 != 0.0 )
      d_result = d_value1 / d_value2;
    else
      d_result = d_value1;
    break;
  case 5:
    // Checkit!
    break;
  }

  // double -> char*
  len = sprintf( s_result, "%g", d_result );
  // można to spr.
  // if ( !len ) ...
  set_value1(s_result);
  set_is_result(true);
  
  #ifdef DEBUG
  printf ("calculateby to %g , %g wynik to: %g \n",d_value1,d_value2,d_result);
  #endif
}

char* Kalkulator::get_value1()
{
  if (is_value1) 
    return value1->str;
  else 
    return NULL;
}

void Kalkulator::set_value1(const gchar *val) 
{
  if (is_value1)
  {
    g_string_free(value1,TRUE);
    value1 = g_string_new(val);
  }
  else
  {
    value1 = g_string_new(val);
    is_value1 = TRUE;
  }
}

bool Kalkulator::del_value1()
{
  if (is_value1)
  {
    g_string_free(value1,TRUE);
    is_value1 = FALSE;
    return TRUE;
  }
  else
    return FALSE;
}

char* Kalkulator::get_value2()
{
  if (is_value2) 
    return value2->str;
  else 
    return NULL;
}

void Kalkulator::set_value2(const gchar *val) 
{
  if (is_value2)
  {
    g_string_free(value2,TRUE);
    value2 = g_string_new(val);
  }
  else
  {
    value2 = g_string_new(val);
    is_value2 = TRUE;
  }
}

bool Kalkulator::del_value2()
{
  if (is_value2)
  {
    g_string_free(value2,TRUE);
    is_value2 = FALSE;
    return TRUE;
  }
  else
    return FALSE;
}


gui.hpp zawiera definicje klasy odpowiadającej za zadania realizowane przez graficzny interfejs użytkownika kalkulatora. Jednocześnie dziedziczy po klasie opisującej ogólnie kalkulator, co w sumie daje połączenie zadań realizowanych przez kalkulator oraz interfejsu graficznego do obsługi kalkulatora. Publiczne metody init(int, char**), build(), run() stanowią programistyczny interfejs do uruchomienia całego programu. Pierwsza z nich inicjuje GTK+, druga tworzy potrzebne kontrolki, lecz ich nie wyświetla. Ostatnia metoda run() wyświetla stworzone okna oraz wywołuje główną pętle programu w GTK+.


#include "kalkulator.cpp"

class GUIKalkulator: public Kalkulator
{
  private:
    GtkWidget *mainwindow;
    GtkWidget *table;
    GtkWidget *entry;
    GtkWidget *button1;
    GtkWidget *button2;
    GtkWidget *button3;
    GtkWidget *button4;
    GtkWidget *button5;
    GtkWidget *button6;
    GtkWidget *button7;
    GtkWidget *button8;
    GtkWidget *button9;
    GtkWidget *button0;
    GtkWidget *buttoncomma;
    GtkWidget *buttonback;
    GtkWidget *buttonclear;
    GtkWidget *buttonadd;
    GtkWidget *buttonsub;
    GtkWidget *buttonmulti;
    GtkWidget *buttondiv;
    GtkWidget *buttonresult;
    // funkcje zwrotne
    static gboolean delete_event(GtkWidget *widget, GdkEvent *event, gpointer data);
    static void destroy(GtkWidget *widget, gpointer data);
    static void btn_1_clicked(GtkWidget *widget, gpointer data);
    static void btn_2_clicked(GtkWidget *widget, gpointer data);
    static void btn_3_clicked(GtkWidget *widget, gpointer data);
    static void btn_4_clicked(GtkWidget *widget, gpointer data);
    static void btn_5_clicked(GtkWidget *widget, gpointer data);
    static void btn_6_clicked(GtkWidget *widget, gpointer data);
    static void btn_7_clicked(GtkWidget *widget, gpointer data);
    static void btn_8_clicked(GtkWidget *widget, gpointer data);
    static void btn_9_clicked(GtkWidget *widget, gpointer data);
    static void btn_0_clicked(GtkWidget *widget, gpointer data);
    static void btn_comma_clicked(GtkWidget *widget, gpointer data);
    static void btn_back_clicked(GtkWidget *widget, gpointer data);
    static void btn_clear_clicked(GtkWidget *widget, gpointer data);
    static void btn_add_clicked(GtkWidget *widget, gpointer data);
    static void btn_sub_clicked(GtkWidget *widget, gpointer data);
    static void btn_multi_clicked(GtkWidget *widget, gpointer data);
    static void btn_div_clicked(GtkWidget *widget, gpointer data);
    static void btn_result_clicked(GtkWidget *widget, gpointer data);
    // obsłuwa wszystkich przycisków numerycznych: 1,2,3,4,5,6,7,8,9,0
    void _numeric_btn_clicked_event(btn_id button);
    // obsługa wszytskich przycisków działń: +,-,*,/
    void _calculate_btn_clicked_event(operation_id operation);
    
  public:
    GUIKalkulator();
    ~GUIKalkulator();
    void init(int, char**);
    void build();
    void run();
};


gui.cpp wprowadzono tu nową zastępczą funkcje gtk_editable_insert_text() dla gtk_entry_append_text(), ponieważ jest ona wyprowadzana z API GTK+. Funkcja ta różni się od poprzedniej tym, że wstawia tekst w określonej przez ostatni parametr pozycji a nie na koniec ciągu znaków.


#include "gui.hpp"
#include <string.h>

#define DEBUG
#define INFO



GUIKalkulator::GUIKalkulator()
{
  #ifdef INFO 
  __debug("GUIKalkulator konstruktor",false);
  #endif
}

GUIKalkulator::~GUIKalkulator()
{
  #ifdef INFO 
  __debug("GUIKalkulator destruktor",false);
  #endif
}

void GUIKalkulator::init(int argc, char** argv)
{
  #ifdef INFO 
  __debug("GUIKalkulator init()",false);
  #endif
  gtk_init(&argc, &argv);
}

void GUIKalkulator::build()
{
  #ifdef INFO 
  __debug("GUIKalkulator bulid()",false);
  #endif
  mainwindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 
  g_signal_connect(G_OBJECT(mainwindow), "delete_event",
                   G_CALLBACK(delete_event), this);
 
  g_signal_connect(G_OBJECT(mainwindow), "destroy",
                   G_CALLBACK(destroy), this);
 
  gtk_container_set_border_width(GTK_CONTAINER(mainwindow), 5);
  gtk_window_set_title(GTK_WINDOW(mainwindow), "kalkulator");
  gtk_window_set_resizable( GTK_WINDOW(mainwindow), FALSE );
  
  // tabela
  /*
        0/0 - 1 - 2 - 3 - 4 - 5 - 6
        1 | _ | _ | _ | _ | _ | _ |
        2 | _ | _ | _ | _ | _ | _ |
        3 | _ | _ | _ | _ | _ | _ |
        4 | _ | _ | _ | _ | _ | _ |
   */
  table = gtk_table_new (4, 6, TRUE);
  gtk_container_add ( GTK_CONTAINER (mainwindow),
            table);

  // entry
  entry = gtk_entry_new ( );
  gtk_entry_set_alignment ( GTK_ENTRY( entry ), 1);
  gtk_editable_set_editable ( GTK_EDITABLE( entry ), FALSE);
  // 0,6 - szerokość od 0 do 6
  // 0,1 - wysokość od 0 do 1
  gtk_table_attach_defaults ( GTK_TABLE (table),
                entry, 0, 6, 0, 1 );
  
  // przyciski 1
  // 0,1 - szerokość od 0 do 1
  // 1,2 - wysokość od 1 do 2
  button1 = gtk_button_new_with_label ("1");
  g_signal_connect (G_OBJECT (button1), "clicked",
              G_CALLBACK (btn_1_clicked), this);
  gtk_table_attach_defaults ( GTK_TABLE (table),
                button1, 0, 1, 1, 2);
  
  // przyciski 2
  button2 = gtk_button_new_with_label ("2");
  g_signal_connect (G_OBJECT (button2), "clicked",
              G_CALLBACK (btn_2_clicked), this);
  gtk_table_attach_defaults ( GTK_TABLE (table),
                button2, 1, 2, 1, 2);
  
  // przyciski 3
  button3 = gtk_button_new_with_label ("3");
  g_signal_connect (G_OBJECT (button3), "clicked",
               G_CALLBACK (btn_3_clicked), this);
  gtk_table_attach_defaults ( GTK_TABLE (table),
                button3, 2, 3, 1, 2);
  
  // drugi wiersz
  // przyciski 4
  button4 = gtk_button_new_with_label ("4");
  g_signal_connect (G_OBJECT (button4), "clicked",
              G_CALLBACK (btn_4_clicked), this);
  gtk_table_attach_defaults ( GTK_TABLE (table),
                button4, 0, 1, 2, 3);
  
  // przyciski 5
  button5 = gtk_button_new_with_label ("5");
  g_signal_connect (G_OBJECT (button5), "clicked",
              G_CALLBACK (btn_5_clicked), this);
  gtk_table_attach_defaults ( GTK_TABLE (table),
                button5, 1, 2, 2, 3);
  
  // przyciski 6
  button6 = gtk_button_new_with_label ("6");
  g_signal_connect (G_OBJECT (button6), "clicked",
              G_CALLBACK (btn_6_clicked), this);
  gtk_table_attach_defaults ( GTK_TABLE (table),
                button6, 2, 3, 2, 3);
  
  // trzeci wiersz
  // przyciski 7
  button7 = gtk_button_new_with_label ("7");
  g_signal_connect (G_OBJECT (button7), "clicked",
              G_CALLBACK (btn_7_clicked), this);
  gtk_table_attach_defaults ( GTK_TABLE (table),
                button7, 0, 1, 3, 4);
  
  // przyciski 8
  button8 = gtk_button_new_with_label ("8");
  g_signal_connect (G_OBJECT (button8), "clicked",
              G_CALLBACK (btn_8_clicked), this);
  gtk_table_attach_defaults ( GTK_TABLE (table),
                button8, 1, 2, 3, 4);
  
  // przyciski 9
  button9 = gtk_button_new_with_label ("9");
  g_signal_connect (G_OBJECT (button9), "clicked",
        G_CALLBACK (btn_9_clicked), this);
  gtk_table_attach_defaults ( GTK_TABLE (table),
                button9, 2, 3, 3, 4);
  
  // przyciski 0
  button0 = gtk_button_new_with_label ("0");
  g_signal_connect (G_OBJECT (button0), "clicked",
              G_CALLBACK (btn_0_clicked), this);
  gtk_table_attach_defaults ( GTK_TABLE (table),
                button0, 3, 4, 3, 4);
  
  // przyciski <-
  buttonback = gtk_button_new_with_label ("<-");
  g_signal_connect (G_OBJECT (buttonback), "clicked",
              G_CALLBACK (btn_back_clicked), this);
  gtk_table_attach_defaults ( GTK_TABLE (table),
                buttonback, 3, 4, 2, 3);
  
  // przyciski C
  buttonclear = gtk_button_new_with_label ("C");
  g_signal_connect (G_OBJECT (buttonclear), "clicked",
              G_CALLBACK (btn_clear_clicked), this);
  gtk_table_attach_defaults ( GTK_TABLE (table),
                buttonclear, 3, 4, 1, 2);
  
  // przyciski +
  buttonadd = gtk_button_new_with_label ("+");
  g_signal_connect (G_OBJECT (buttonadd), "clicked",
              G_CALLBACK (btn_add_clicked), this);
  gtk_table_attach_defaults ( GTK_TABLE (table),
                buttonadd, 4, 5, 1, 2);
  
  // przyciski -
  buttonsub = gtk_button_new_with_label ("-");
  g_signal_connect (G_OBJECT (buttonsub), "clicked",
              G_CALLBACK (btn_sub_clicked), this);
  gtk_table_attach_defaults ( GTK_TABLE (table),
                buttonsub, 4, 5, 2, 3);
  
  // przyciski *
  buttonmulti = gtk_button_new_with_label ("*");
  g_signal_connect (G_OBJECT (buttonmulti), "clicked",
              G_CALLBACK (btn_multi_clicked), this);
  gtk_table_attach_defaults ( GTK_TABLE (table),
                buttonmulti, 4, 5, 3, 4);
  
  // przyciski /
  buttondiv = gtk_button_new_with_label ("/");
  g_signal_connect (G_OBJECT (buttondiv), "clicked",
              G_CALLBACK (btn_div_clicked), this);
  gtk_table_attach_defaults ( GTK_TABLE (table),
                buttondiv, 5, 6, 1, 2);
   
  // przyciski =
  buttonresult = gtk_button_new_with_label ("=");
  g_signal_connect (G_OBJECT (buttonresult), "clicked",
              G_CALLBACK (btn_result_clicked), this);
  gtk_table_attach_defaults ( GTK_TABLE (table),
                buttonresult, 5, 6, 3, 4);

  // przyciski ,
  buttoncomma = gtk_button_new_with_label (",");
  g_signal_connect (G_OBJECT (buttoncomma), "clicked",
              G_CALLBACK (btn_comma_clicked), this);
  gtk_table_attach_defaults ( GTK_TABLE (table),
                buttoncomma, 5, 6, 2, 3);
}

void GUIKalkulator::run()
{
  #ifdef INFO 
  __debug("GUIKalkulator run()",false);
  #endif
  gtk_widget_show_all(mainwindow);
  gtk_main();
}

gboolean GUIKalkulator::delete_event(GtkWidget *widget, GdkEvent *event, gpointer data)
{
  GUIKalkulator *gui_kalkulator = static_cast<GUIKalkulator*>(data);
  #ifdef INFO 
  gui_kalkulator->__debug("GUIKalkulator delete_event()",false);
  #endif
  gui_kalkulator->set_prev_button(Button_1);
  return FALSE;
}

void GUIKalkulator::destroy(GtkWidget *widget, gpointer data)
{
  #ifdef INFO 
  static_cast<GUIKalkulator*>(data)->__debug("GUIKalkulator destroy(gtk_main_quit)",false);
  #endif
  gtk_main_quit();
}

void GUIKalkulator::_numeric_btn_clicked_event(btn_id button)
{
  const char *number = _btn_id_to_char(button);
  #ifdef INFO 
  __debug("GUIKalkulator _numeric_btn_clicked_event()",false);
  g_print("clicked: %s\n",number);
  #endif
  int len(0);
  
  if (get_is_result() && get_prev_button() == Button_result)
  {
    if (get_is_value1())
      del_value1();
    if (get_is_value2())
      del_value2();
    
    set_operation(NoSelectOprt);
    set_prev_operation(NoSelectOprt);
    set_is_result(FALSE);
    set_prev_button(NoSelectBtn);
  
    gtk_entry_set_text(GTK_ENTRY(entry),"");
  }
  else if (get_is_result())
  {
    gtk_entry_set_text(GTK_ENTRY(entry),"");
    set_is_result(FALSE);
  }
  len = strlen(GTK_ENTRY(entry)->text);
  gtk_editable_insert_text(GTK_EDITABLE(entry),number,1,&len);

  set_prev_button(button);
}

void GUIKalkulator::_calculate_btn_clicked_event(operation_id operation)
{
  #ifdef INFO 
  __debug("GUIKalkulator _calculate_btn_clicked_event()",false);
  g_print("clicked: %s\n",_operation_id_to_char(operation));
  #endif
  
  gint8 test = 0,
        prev_operation_tmp = FALSE;
  gchar *text_entry = GTK_ENTRY(entry)->text;
  
  // +,-,*,/
  set_operation(operation);

  // test
  if (get_is_value1() == FALSE && 
      get_is_value2() == FALSE &&
      strlen(text_entry) > 0)
  {
    // nalezy ustawić value1
    test = 1;
  }
  if (get_is_value1() == TRUE && 
      get_is_value2() == FALSE &&
      strlen(text_entry) > 0 &&
      get_prev_button() != Button_add &&
      get_prev_button() != Button_sub &&
      get_prev_button() != Button_multi &&
      get_prev_button() != Button_div &&
      get_prev_button() != Button_result &&
      get_prev_button() != Button_comma)
  {
    // ustawic value2 i obcalculateyć wynik
    test = 2;
  }

  switch (test)
  {
    case 1:
      set_value1(gtk_entry_get_text(GTK_ENTRY(entry)));
      gtk_entry_set_text(GTK_ENTRY(entry),"");
      break;

    case 2:
      set_value2(gtk_entry_get_text(GTK_ENTRY(entry)));

      // gdy po wielokrotnych operacji następuje zmiana
      // wynik obcalculateamy według poprzednio wybranej operacji
      // np. 5 + 5 (10)- 5 = 15
      if (get_operation() != get_prev_operation())
        prev_operation_tmp = TRUE;

      calculate(prev_operation_tmp);
      del_value2();
      /*
       *  kalkulator->value1 (wynik)
       *  kalkulator->value2 (puste)
       */

      gtk_entry_set_text(GTK_ENTRY(entry), get_value1());
      break;
  }

  set_prev_button(_operation_id_to_btn_id(operation));
  
  // zabezpiecza nas przed tym: 
  // np. 1 + 5 * daje w wyniku 5 ponieważ wykonał rodzaj operacji 
  // domyślny dla obecnie (statnlio) wciśniętego przycisku, czyli *
  set_prev_operation(get_operation());
  
  #ifdef DEBUG
  __debug("GUIKalkulator _calculate_btn_clicked_event()",true);
  #endif
}

void GUIKalkulator::btn_1_clicked(GtkWidget *widget, gpointer data)
{
  static_cast<GUIKalkulator*>(data)->_numeric_btn_clicked_event(Button_1);
}

void GUIKalkulator::btn_2_clicked(GtkWidget *widget, gpointer data)
{
  static_cast<GUIKalkulator*>(data)->_numeric_btn_clicked_event(Button_2);
}

void GUIKalkulator::btn_3_clicked(GtkWidget *widget, gpointer data)
{
  static_cast<GUIKalkulator*>(data)->_numeric_btn_clicked_event(Button_3);
}

void GUIKalkulator::btn_4_clicked(GtkWidget *widget, gpointer data)
{
  static_cast<GUIKalkulator*>(data)->_numeric_btn_clicked_event(Button_4);
}

void GUIKalkulator::btn_5_clicked(GtkWidget *widget, gpointer data)
{
  static_cast<GUIKalkulator*>(data)->_numeric_btn_clicked_event(Button_5);
}

void GUIKalkulator::btn_6_clicked(GtkWidget *widget, gpointer data)
{
  static_cast<GUIKalkulator*>(data)->_numeric_btn_clicked_event(Button_6);
}

void GUIKalkulator::btn_7_clicked(GtkWidget *widget, gpointer data)
{
  static_cast<GUIKalkulator*>(data)->_numeric_btn_clicked_event(Button_7);
}

void GUIKalkulator::btn_8_clicked(GtkWidget *widget, gpointer data)
{
  static_cast<GUIKalkulator*>(data)->_numeric_btn_clicked_event(Button_8);
}

void GUIKalkulator::btn_9_clicked(GtkWidget *widget, gpointer data)
{
  static_cast<GUIKalkulator*>(data)->_numeric_btn_clicked_event(Button_9);
}

void GUIKalkulator::btn_0_clicked(GtkWidget *widget, gpointer data)
{
  static_cast<GUIKalkulator*>(data)->_numeric_btn_clicked_event(Button_0);
}

void GUIKalkulator::btn_comma_clicked(GtkWidget *widget, gpointer data)
{
  GUIKalkulator *gui_kalkulator = static_cast<GUIKalkulator*>(data);
  int len(0);
  #ifdef INFO 
  gui_kalkulator->__debug("GUIKalkulator clicked: ,",false);
  #endif
  len = strlen(GTK_ENTRY(gui_kalkulator->entry)->text);
  gtk_editable_insert_text(GTK_EDITABLE(gui_kalkulator->entry),",",1,&len);
  //gtk_entry_append_text(GTK_ENTRY(entry),",");
  
  gui_kalkulator->set_prev_button(Button_comma);
}

void GUIKalkulator::btn_back_clicked(GtkWidget *widget, gpointer data)
{
  GUIKalkulator *gui_kalkulator = static_cast<GUIKalkulator*>(data);
  GString *tmp=NULL;
  #ifdef INFO 
  gui_kalkulator->__debug("GUIKalkulator clicked: <-",false);
  #endif
  tmp = g_string_new(gtk_entry_get_text(GTK_ENTRY(gui_kalkulator->entry)));
  tmp = g_string_truncate(tmp,tmp->len-1);
  gtk_entry_set_text(GTK_ENTRY(gui_kalkulator->entry), g_string_free(tmp,FALSE));
  
  gui_kalkulator->set_prev_button(Button_back);
}

void GUIKalkulator::btn_clear_clicked(GtkWidget *widget, gpointer data)
{
  GUIKalkulator *gui_kalkulator = static_cast<GUIKalkulator*>(data);
  #ifdef INFO 
  gui_kalkulator->__debug("GUIKalkulator clicked: C",false);
  #endif
  if (gui_kalkulator->get_is_value1())
    gui_kalkulator->del_value1(); 
  if (gui_kalkulator->get_is_value2())
    gui_kalkulator->del_value2(); 
  
  gui_kalkulator->set_operation(NoSelectOprt);
  gui_kalkulator->set_prev_operation(NoSelectOprt);
  gui_kalkulator->set_is_result(FALSE);
  gui_kalkulator->set_prev_button(NoSelectBtn);
  
  gtk_entry_set_text(GTK_ENTRY(gui_kalkulator->entry),"");

  gui_kalkulator->set_prev_button(Button_clear);
  
  #ifdef DEBUG
  gui_kalkulator->__debug("GUIKalkulator clicked: C",true);
  #endif
}

void GUIKalkulator::btn_add_clicked(GtkWidget *widget, gpointer data)
{
  static_cast<GUIKalkulator*>(data)->_calculate_btn_clicked_event(Add);
}

void GUIKalkulator::btn_sub_clicked(GtkWidget *widget, gpointer data)
{
  static_cast<GUIKalkulator*>(data)->_calculate_btn_clicked_event(Sub);
}

void GUIKalkulator::btn_multi_clicked(GtkWidget *widget, gpointer data)
{
  static_cast<GUIKalkulator*>(data)->_calculate_btn_clicked_event(Multi);
}

void GUIKalkulator::btn_div_clicked(GtkWidget *widget, gpointer data)
{
  static_cast<GUIKalkulator*>(data)->_calculate_btn_clicked_event(Div);
}

void GUIKalkulator::btn_result_clicked(GtkWidget *widget, gpointer data)
{
  GUIKalkulator *gui_kalkulator = static_cast<GUIKalkulator*>(data);
  gchar *text_entry = GTK_ENTRY(gui_kalkulator->entry)->text;
  #ifdef INFO 
  gui_kalkulator->__debug("GUIKalkulator clicked: =",false);
  #endif

  if (gui_kalkulator->get_is_value1() == TRUE && 
      gui_kalkulator->get_is_value2() == FALSE &&
      strlen (text_entry) > 0 &&
      gui_kalkulator->get_prev_button() != Button_add &&
      gui_kalkulator->get_prev_button() != Button_sub &&
      gui_kalkulator->get_prev_button() != Button_multi &&
      gui_kalkulator->get_prev_button() != Button_div &&
      gui_kalkulator->get_prev_button() != Button_result &&
      gui_kalkulator->get_prev_button() != Button_comma) 
  {
    gui_kalkulator->set_value2(gtk_entry_get_text(GTK_ENTRY(gui_kalkulator->entry)));
    
    gui_kalkulator->calculate(FALSE);
    gui_kalkulator->del_value2();
    /*
     *  kalkulator->value1 (wynik)
     *  kalkulator->value2 (puste)
     */
    
    gtk_entry_set_text(GTK_ENTRY(gui_kalkulator->entry), gui_kalkulator->get_value1());
  }
  
  gui_kalkulator->set_prev_button(Button_result);
  
  #ifdef DEBUG
  gui_kalkulator->__debug("GUIKalkulator clicked: =",true); 
  #endif
}


main.cpp główny program, korzysta z implementacji naszego kalkulatora.


/* 
 * Autor: Grzegorz Kuczyński
 * Data:  29 kwietnia 2009
 */
 
#include <iostream>
#include "gui.cpp"

int main(int argc, char *argv[])
{
  GUIKalkulator *gui_kalkulator = new GUIKalkulator;
  
  gui_kalkulator->init(argc,argv);
  gui_kalkulator->build();
  gui_kalkulator->run();
  
  delete gui_kalkulator;
  
  return 0;
}


Makefile plik definiujący zasady kompilacji.

CC = g++

CFLAGS = -Wall			 	\
	-DG_DISABLE_DEPRECATED 	 	\
	-DGDK_DISABLE_DEPRECATED 	\
	-DGDK_PIXBUF_DISABLE_DEPRECATED \
	-DGTK_DISABLE_DEPRECATED

kalkulatorCPP: main.cpp
	$(CC) main.cpp -o kalkulatorCPP $(CFLAGS) `pkg-config gtk+-2.0 --cflags --libs`

clean: 
	rm -f *.o kalkulatorCPP