ButtonBox

A calculator - the buttons are enclosed in horizontal ButtonBoxes.

Code used to generate this example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
from gi.repository import Gtk
import sys


class MyWindow(Gtk.ApplicationWindow):

    def __init__(self, app):
        Gtk.Window.__init__(self, title="Calculator", application=app)
        self.set_default_size(350, 200)
        self.set_border_width(10)

        # an entry
        self.entry = Gtk.Entry()
        # with an initial text
        self.entry.set_text('0')
        # text aligned on the right
        self.entry.set_alignment(1)
        # the text in the entry cannot be modified writing in it
        self.entry.set_can_focus(False)

        # a grid
        grid = Gtk.Grid()
        grid.set_row_spacing(5)

        # to attach the entry
        grid.attach(self.entry, 0, 0, 1, 1)

        # the labels for the buttons
        buttons = [7, 8, 9, '/',
                   4, 5, 6, '*',
                   1, 2, 3, '-',
                   'C', 0, '=', '+']

        # each row is a ButtonBox, attached to the grid
        for i in range(4):
            hbox = Gtk.ButtonBox.new(Gtk.Orientation.HORIZONTAL)
            hbox.set_spacing(5)
            grid.attach(hbox, 0, i + 1, 1, 1)
            # each ButtonBox has 4 buttons, connected to the callback function
            for j in range(4):
                button = Gtk.Button(label=buttons[i * 4 + j])
                button.set_can_focus(False)
                button.connect("clicked", self.button_clicked)
                hbox.add(button)

        # some variables for the calculations
        self.first_number = 0
        self.second_number = 0
        self.counter = 0
        self.operation = ""

        # add the grid to the window
        self.add(grid)

    # callback function for all the buttons
    def button_clicked(self, button):
        # for the operations
        if button.get_label() == '+':
            self.counter += 1
            if self.counter > 1:
                self.do_operation()
            self.entry.set_text('0')
            self.operation = "plus"
        elif button.get_label() == '-':
            self.counter += 1
            if self.counter > 1:
                self.do_operation()
            self.entry.set_text('0')
            self.operation = "minus"
        elif button.get_label() == '*':
            self.counter += 1
            if self.counter > 1:
                self.do_operation()
            self.entry.set_text('0')
            self.operation = "multiplication"
        elif button.get_label() == '/':
            self.counter += 1
            if self.counter > 1:
                self.do_operation()
            self.entry.set_text('0')
            self.operation = "division"
        # for =
        elif button.get_label() == '=':
            self.do_operation()
            self.entry.set_text(str(self.first_number))
            self.counter = 1
        # for Cancel
        elif button.get_label() == 'C':
            self.first_number = 0
            self.second_number = 0
            self.counter = 0
            self.entry.set_text('')
            self.operation = ""
        # for a digit button
        else:
            new_digit = int(button.get_label())
            if self.entry.get_text() == 'error':
                number = 0
            else:
                number = int(self.entry.get_text())
            number = number * 10 + new_digit
            if self.counter == 0:
                self.first_number = number
            else:
                self.second_number = number
            self.entry.set_text(str(number))

    def do_operation(self):
        if self.operation == "plus":
            self.first_number += self.second_number
        elif self.operation == "minus":
            self.first_number -= self.second_number
        elif self.operation == "multiplication":
            self.first_number *= self.second_number
        elif self.operation == "division":
            try:
                self.first_number /= self.second_number
            except ZeroDivisionError:
                self.first_number = 0
                self.second_number = 0
                self.counter = 0
                self.entry.set_text('error')
                self.operation = ""
                return
        else:
            self.first_number = 0
            self.second_number = 0
            self.counter = 0
            self.entry.set_text('error')


class MyApplication(Gtk.Application):

    def __init__(self):
        Gtk.Application.__init__(self)

    def do_activate(self):
        win = MyWindow(self)
        win.show_all()

    def do_startup(self):
        Gtk.Application.do_startup(self)

app = MyApplication()
exit_status = app.run(sys.argv)
sys.exit(exit_status)

Useful methods for a ButtonBox widget

  • The layout of the ButtonBox are set with set_layout(layout), where layout can be Gtk.ButtonBoxStyle.SPREAD (buttons are evenly spread across the box), Gtk.ButtonBoxStyle.EDGE (buttons are placed at the edges of the box), Gtk.ButtonBoxStyle.START (buttons are grouped towards the start of the box), Gtk.ButtonBoxStyle.END (buttons are grouped towards the end of the box), Gtk.ButtonBoxStyle.CENTER (buttons are centered in the box).

  • set_child_secondary(button, is_secondary) sets whether button should appear in a secondary group of children. A typical use of a secondary child is the help button in a dialog. This group appears after the other children if the style is START, SPREAD or EDGE, and before the other children if the style is END. If the style is START or END, then the secondary children are aligned at the other end of the button box from the main children. For the other styles, they appear immediately next to the main children.

  • set_child_non_homogeneous(button, is_non_homogeneous) sets whether the child is exempted from homogeneous sizing. Default value is False.

  • set_spacing(spacing) sets the spacing, in pixels, between the buttons of the box.

API References

In this sample we used the following: