Welcome!

By registering with us, you'll be able to discuss, share and private message with other members of our community.

SignUp Now!
  • Guest, before posting your code please take these rules into consideration:
    • It is required to use our BBCode feature to display your code. While within the editor click < / > or >_ and place your code within the BB Code prompt. This helps others with finding a solution by making it easier to read and easier to copy.
    • You can also use markdown to share your code. When using markdown your code will be automatically converted to BBCode. For help with markdown check out the markdown guide.
    • Don't share a wall of code. All we want is the problem area, the code related to your issue.


    To learn more about how to use our BBCode feature, please click here.

    Thank you, Code Forum.

Python calculator works fine but after one operation its result is always 0

FastFooDD

New Coder
Python:
from customtkinter import *
import tkinter.messagebox
app = CTk()
app.geometry("420x500")
app.resizable(False, False)
set_appearance_mode("dark")
tempLabel = ""
valuesInt = ""
valuesInt2 = ""
i = 0
i2 = 0
symbol = ""
#[FUNCTIONS]
def labelUpdate(button):
    global tempLabel
    tempLabel += button.cget("text")
    resultLabel.configure(text=tempLabel)
def clear():
    global valuesInt
    global valuesInt2
    global tempLabel
    global i
    global i2
    resultLabel.configure(text="")
    tempLabel = ""
    valuesInt = ""
    valuesInt2 = ""
    i = 0
    i2 = 0

def result():
    global i
    global i2
    global tempLabel
    global symbol
    global valuesInt
    global valuesInt2
    resultNumber = 0
    if symbol == "+":
                resultNumber = valuesInt + int(valuesInt2)
    elif symbol == "-":
                resultNumber = valuesInt - int(valuesInt2)
    elif symbol == "x":
                resultNumber = valuesInt * int(valuesInt2)
    elif symbol == "÷":
                resultNumber = valuesInt / int(valuesInt2)
    else:
          resultNumber = resultNumber
    resultLabel.configure(text=resultNumber)
    print(resultNumber)
    tempLabel = ""
    valuesInt = ""
    valuesInt2 = ""
    i = 0
    i2 = 0
def valueAppend(button):
    global i2
    global i
    global tempLabel
    global symbol
    global valuesInt
    global valuesInt2
  
    try:
        intText = int(button.cget("text"))
        if i2 == 0:
            valuesInt += str(intText)
        elif i2 != 0:
            valuesInt = int(valuesInt)
            valuesInt2 += str(intText)
    except:
        i2 += 1
        if i == 0:
            symbol += button.cget("text")
            i += 1
        elif i >= 1:
            tempLabel = tempLabel[:-1]
            resultLabel.configure(text=tempLabel)
            tkinter.messagebox.showwarning("error", "you can only put one symbol per operation")
      
#[BUTTONS, LABELS ETC.]
resultLabel = CTkLabel(master=app, text="...", font=("Arial", 50))
resultLabel.place(x=80, y=30)
number1 = CTkButton(master=app, text="1", font=("Arial", 25), height=90, width=100, bg_color="transparent",
                     fg_color="transparent", corner_radius=32, border_color="#511880", border_width=5, command=lambda: [labelUpdate(number1), valueAppend(number1)])
number1.place(x=10, y=130)
number2 = CTkButton(master=app, text="2", font=("Arial", 25), height=90, width=100, bg_color="transparent",
                     fg_color="transparent", corner_radius=32, border_color="#511880", border_width=5, command=lambda: [labelUpdate(number2), valueAppend(number2)])
number2.place(x=115, y=130)
number3 = CTkButton(master=app, text="3", font=("Arial", 25), height=90, width=100, bg_color="transparent",
                     fg_color="transparent", corner_radius=32, border_color="#511880", border_width=5, command=lambda: [labelUpdate(number3), valueAppend(number3)])
number3.place(x=220, y=130)
number4 = CTkButton(master=app, text="4", font=("Arial", 25), height=90, width=100, bg_color="transparent",
                     fg_color="transparent", corner_radius=32, border_color="#511880", border_width=5, command=lambda: [labelUpdate(number4), valueAppend(number4)])
number4.place(x=10, y=230)
number5 = CTkButton(master=app, text="5", font=("Arial", 25), height=90, width=100, bg_color="transparent",
                     fg_color="transparent", corner_radius=32, border_color="#511880", border_width=5, command=lambda: [labelUpdate(number5), valueAppend(number5)])
number5.place(x=115, y=230)
number6 = CTkButton(master=app, text="6", font=("Arial", 25), height=90, width=100, bg_color="transparent",
                     fg_color="transparent", corner_radius=32, border_color="#511880", border_width=5, command=lambda: [labelUpdate(number6), valueAppend(number6)])
number6.place(x=220, y=230)
number7 = CTkButton(master=app, text="7", font=("Arial", 25), height=90, width=100, bg_color="transparent",
                     fg_color="transparent", corner_radius=32, border_color="#511880", border_width=5, command=lambda: [labelUpdate(number7), valueAppend(number7)])
number7.place(x=10, y=330)
number8 = CTkButton(master=app, text="8", font=("Arial", 25), height=90, width=100, bg_color="transparent",
                     fg_color="transparent", corner_radius=32, border_color="#511880", border_width=5, command=lambda: [labelUpdate(number8), valueAppend(number8)])
number8.place(x=115, y=330)
number9 = CTkButton(master=app, text="9", font=("Arial", 25), height=90, width=100, bg_color="transparent",
                     fg_color="transparent", corner_radius=32, border_color="#511880", border_width=5, command=lambda: [labelUpdate(number9), valueAppend(number9)])
number9.place(x=220, y=330)
#---------------------------------------
clearButton = CTkButton(master=app, text="Clear", font=("Arial", 20), height=65, width=100, bg_color="transparent",
                     fg_color="transparent", corner_radius=32, border_color="#511880", border_width=3, command=clear)
clearButton.place(x=10, y= 430)
equalsButton = CTkButton(master=app, text="=", font=("Arial", 20), height=65, width=100, bg_color="transparent",
                     fg_color="transparent", corner_radius=32, border_color="#511880", border_width=3, command=result)
equalsButton.place(y=430, x=130)
plusButton = CTkButton(master=app, text="+", font=("Arial", 20), height=100, width=65, bg_color="transparent",
                     fg_color="transparent", corner_radius=32, border_color="#511880", border_width=3, command=lambda: [labelUpdate(plusButton), valueAppend(plusButton)])
plusButton.place(y=390, x=335)
minusButton = CTkButton(master=app, text="-", font=("Arial", 20), height=100, width=65, bg_color="transparent",
                     fg_color="transparent", corner_radius=32, border_color="#511880", border_width=3, command=lambda: [labelUpdate(minusButton), valueAppend(minusButton)])
minusButton.place(y=285, x=340)
multiplyButton = CTkButton(master=app, text="x", font=("Arial", 20), height=100, width=65, bg_color="transparent",
                     fg_color="transparent", corner_radius=32, border_color="#511880", border_width=3, command=lambda: [labelUpdate(multiplyButton), valueAppend(multiplyButton)])
multiplyButton.place(y=180, x=340)
divButton = CTkButton(master=app, text="÷", font=("Arial", 20), height=100, width=65, bg_color="transparent",
                     fg_color="transparent", corner_radius=32, border_color="#511880", border_width=3, command=lambda: [labelUpdate(divButton), valueAppend(divButton)])
divButton.place(y=75, x=340)
app.mainloop()
 
It's probable line 57 and 58. You are setting them to zero. Try changing the vales of one or both and see what happens. I recommend that you find another way other than using global as well.



It's line 41
resultNumber = 0
 
Last edited:
I was wondering about all the globals as well. That does like a recipe for trouble. But it's not the issue here.
A bit of debugging showed me that if I first do a multiply and then a divide, the first time symbol has the value * but the second time it has the value */ ! And that is why from the second time the result is always zero.
Without understanding your program logic, I quickly saw that you are appending every symbol to the last :

Python:
symbol += button.cget("text")

Change that to

Python:
symbol = button.cget("text")

and you'll see it works much better 😎

Do consider adding a button for zero as well.
 
I could not resist clearing up this rather convoluted code. Key changes:
  • Combine functions labelUpdate and valueAppend into one function enter (since they are always called together)
  • Use only 3 global variables: operation, value1 and value2. There is really no need for more.
  • Use string search rather than exception handling to check input
The overall idea : keep it simple and minimal 😉

Python:
from customtkinter import *
import tkinter.messagebox
app = CTk()
app.geometry("420x500")
set_appearance_mode("dark")
app.resizable(False, False)

operation = ""
value1 = ""
value2 = ""

def enter(button):
    global operation
    global value1
    global value2

    char = button.cget("text")
    if ( char in "+-/x" ):
        if ( operation == "" ):
            operation = char
        else:
            tkinter.messagebox.showwarning("error", "you can only use one operation")
        return
      
    if ( operation == "" ):
        value1 += char
        resultLabel.configure(text=value1)
    else:
        value2 += char
        resultLabel.configure(text=value2)
      
def calculate():

    global operation
    global value1
    global value2

    result = 0
  
    if operation == "+":
        result = int(value1) + int(value2)
    elif operation == "-":
        result = int(value1) - int(value2)
    elif operation == "x":
        result = int(value1) * int(value2)
    elif operation == "/":
        result = int(value1) / int(value2)
    else:
        result = 0
        
    resultLabel.configure(text=result)
    value1 = ""
    value2 = ""
    operation = ""

def clear():
    global operation
    global value1
    global value2

    resultLabel.configure(text="0")
    value1 = ""
    value2 = ""
    operation = ""
  
    
#[BUTTONS, LABELS ETC.]
resultLabel = CTkLabel(master=app, text="0", font=("Arial", 50))
resultLabel.place(x=80, y=30)

number1 = CTkButton(master=app, text="1", font=("Arial", 25), height=90, width=100, bg_color="transparent",
                     fg_color="transparent", corner_radius=32, border_color="#511880", border_width=5, command=lambda: [enter(number1)])
number1.place(x=10, y=130)
number2 = CTkButton(master=app, text="2", font=("Arial", 25), height=90, width=100, bg_color="transparent",
                     fg_color="transparent", corner_radius=32, border_color="#511880", border_width=5, command=lambda: [enter(number2)])
number2.place(x=115, y=130)
number3 = CTkButton(master=app, text="3", font=("Arial", 25), height=90, width=100, bg_color="transparent",
                     fg_color="transparent", corner_radius=32, border_color="#511880", border_width=5, command=lambda: [enter(number3)])
number3.place(x=220, y=130)
number4 = CTkButton(master=app, text="4", font=("Arial", 25), height=90, width=100, bg_color="transparent",
                     fg_color="transparent", corner_radius=32, border_color="#511880", border_width=5, command=lambda: [enter(number4)])
number4.place(x=10, y=230)
number5 = CTkButton(master=app, text="5", font=("Arial", 25), height=90, width=100, bg_color="transparent",
                     fg_color="transparent", corner_radius=32, border_color="#511880", border_width=5, command=lambda: [enter(number5)])
number5.place(x=115, y=230)
number6 = CTkButton(master=app, text="6", font=("Arial", 25), height=90, width=100, bg_color="transparent",
                     fg_color="transparent", corner_radius=32, border_color="#511880", border_width=5, command=lambda: [enter(number6)])
number6.place(x=220, y=230)
number7 = CTkButton(master=app, text="7", font=("Arial", 25), height=90, width=100, bg_color="transparent",
                     fg_color="transparent", corner_radius=32, border_color="#511880", border_width=5, command=lambda: [enter(number7)])
number7.place(x=10, y=330)
number8 = CTkButton(master=app, text="8", font=("Arial", 25), height=90, width=100, bg_color="transparent",
                     fg_color="transparent", corner_radius=32, border_color="#511880", border_width=5, command=lambda: [enter(number8)])
number8.place(x=115, y=330)
number9 = CTkButton(master=app, text="9", font=("Arial", 25), height=90, width=100, bg_color="transparent",
                     fg_color="transparent", corner_radius=32, border_color="#511880", border_width=5, command=lambda: [enter(number9)])
number9.place(x=220, y=330)
#---------------------------------------
clearButton = CTkButton(master=app, text="Clear", font=("Arial", 20), height=65, width=100, bg_color="transparent",
                     fg_color="transparent", corner_radius=32, border_color="#511880", border_width=3, command=clear)
clearButton.place(x=10, y= 430)
equalsButton = CTkButton(master=app, text="=", font=("Arial", 20), height=65, width=100, bg_color="transparent",
                     fg_color="transparent", corner_radius=32, border_color="#511880", border_width=3, command=calculate)
equalsButton.place(y=430, x=130)
plusButton = CTkButton(master=app, text="+", font=("Arial", 20), height=100, width=65, bg_color="transparent",
                     fg_color="transparent", corner_radius=32, border_color="#511880", border_width=3, command=lambda: [enter(plusButton)])
plusButton.place(y=390, x=335)
minusButton = CTkButton(master=app, text="-", font=("Arial", 20), height=100, width=65, bg_color="transparent",
                     fg_color="transparent", corner_radius=32, border_color="#511880", border_width=3, command=lambda: [enter(minusButton)])
minusButton.place(y=285, x=340)
multiplyButton = CTkButton(master=app, text="x", font=("Arial", 20), height=100, width=65, bg_color="transparent",
                     fg_color="transparent", corner_radius=32, border_color="#511880", border_width=3, command=lambda: [enter(multiplyButton)])
multiplyButton.place(y=180, x=340)
divButton = CTkButton(master=app, text="/", font=("Arial", 20), height=100, width=65, bg_color="transparent",
                     fg_color="transparent", corner_radius=32, border_color="#511880", border_width=3, command=lambda: [enter(divButton)])
divButton.place(y=75, x=340)
app.mainloop()
 
Here is my approach.
I have bound the keys to enter input. Both the return key and keypad enter will calculate. The ESC key will clear.

Python:
from decimal import Decimal
import customtkinter as tk

tk.set_appearance_mode('dark')

class Calc:
    ''' Class for performing operations '''

    def valid(self, arg):
        ''' Method for validating input '''
        if arg.isalpha() or arg in ['#','@','!','$','&','=','^','%']:
            return False
        else:
            return True

    def insert(self, arg, val):
        ''' Method for inserting into text field '''
        arg.insert('end', val)

    def calculate(self, arg):
        ''' Method for calculating '''
        values = arg.get()
        # eval is considered a security risk and not recommended.
        # For this simple example should be ok
        if values:
            result = eval(values)
            if isinstance(result, float):
                result = Decimal(result).normalize()
            else:
                result = result 
            arg.delete(0, 'end')
            arg.insert('end', result)

    def clear(self, entry):
        ''' Method for clearing entry field '''
        entry.delete(0, 'end')

# Initialize the Calc class
action = Calc()

app = tk.CTk()
app.geometry('+300+300')
app.columnconfigure(0, weight=1)
app.rowconfigure(1, weight=1)

# For validating input
_valid = app.register(action.valid)

# Create the entry field
entry = tk.CTkEntry(app, font=('arial', 48, 'normal'), justify='right')
entry.grid(column=0, row=0, sticky='new', padx=8, pady=5)
entry.focus()
entry.configure(validate='key', validatecommand=(_valid, '%S'))

# Container for holding the buttons
container = tk.CTkFrame(app)
container.grid(column=0, row=1, sticky='news', padx=8, pady=5)

# Make the buttons even in size
for i in range(3):
    container.grid_columnconfigure(i, weight=3, uniform='btns')
    container.grid_rowconfigure(i, weight=3, uniform='btns')

# Empty list to hold the buttons
buttons = []

# Set some iter variables
col, row, i = 0, 0, 0

# List holding the button text
numbers = [7,8,9,'*',4,5,6,'/',1,2,3,'+',0,'.','=','-']

# List for changing text color of operators
special = ['+','-','*','/','=']

# Create the buttons and add to the list
for key in numbers:
    color = 'orange' if key in special else 'white'
    buttons.append(tk.CTkButton(container, text=key, font=('arial', 28, 'normal'), cursor='hand2', \
        fg_color='transparent', border_color='slategray', corner_radius=15, bg_color='transparent', \
        border_width=5, text_color=color, hover_color='#555555'))
    buttons[i].grid(column=col, row=row, sticky='news', padx=4, pady=4)
    if col >= 3:
        row += 1
        col = 0
    else:
        col += 1
    i += 1

# Add the clear button
buttons.append(tk.CTkButton(container, text='Clear', font=('arial', 28, 'normal'), cursor='hand2', \
    border_color='slategray', corner_radius=15, bg_color='transparent', fg_color='transparent', \
        border_width=5, text_color='tomato', hover_color='#555555'))
buttons[16].grid(column=0, columnspan=4, row=15, sticky='news', padx=4, pady=4)

# Setup the button commands
for button in buttons:
    if button.cget('text') not in ('Clear', '='):
        button.configure(command=lambda var=button.cget('text'): action.insert(entry, var))
    elif button.cget('text') == 'Clear':
        button.configure(command=lambda: action.clear(entry))
    else:
        button.configure(command=lambda:action.calculate(entry))

# Bind the buttons
app.bind('<Return>', lambda event: action.calculate(entry))
app.bind('<KP_Enter>', lambda event: action.calculate(entry))
app.bind('<Escape>', lambda event: action.clear(entry))

app.mainloop()
 
Last edited:
Edited the script a little. Used MVC modal and did away with tkinter messagebox by creating a toplevel window.
Python:
from decimal import Decimal
import customtkinter as tk

tk.set_appearance_mode('dark')

class ErrorPage:
    ''' Class create a error page using a toplevel window. '''
    def __init__(self, parent):
        self.parent = parent

    def error(self):
        self.parent.withdraw()
        self.window = tk.CTkToplevel(None)
        self.window.geometry('500x200+350+350')
        self.window.configure(fg_color='gray96')
        self.window.title('Error!')

        text = 'That character is not allowed.\nPlease enter only numbers.'.strip()

        label = tk.CTkLabel(self.window, text=text, font=(None, 28, 'normal'), \
            bg_color='transparent', text_color='red', justify='left')
        label.pack(fill='both', expand=True, pady=2)

        self.button = tk.CTkButton(self.window, text='OK', cursor='hand2', command=self.close)
        self.button.pack(pady=(2,8))

        self.window.bind('<Return>', self.close)
        self.window.bind('<KP_Enter>', self.close)

        self.window.protocol('WM_DELETE_WINDOW',self.close)

    def close(self, event=None):
        self.window.destroy()
        self.parent.deiconify()
        

class Calc:
    ''' Class for performing operations '''
    def __init__(self, parent):
        self.error = ErrorPage(parent)
        

    def valid(self, arg):
        ''' Method for validating input '''
        if arg.isalpha() or arg in ['#','@','!','$','&','=','^','%']:
            self.error.error()
            return False
        else:
            return True

    def insert(self, arg, val):
        ''' Method for inserting into text field '''
        arg.insert('end', val)

    def calculate(self, arg):
        ''' Method for calculating '''
        values = arg.get()
        # eval is considered a security risk and not recommended.
        # For this simple example should be ok
        if values:
            result = eval(values)

            if isinstance(result, float):
                result = Decimal(result).normalize()
            else:
                result = result

            arg.delete(0, 'end')
            arg.insert('end', result)

    def clear(self, entry):
        ''' Method for clearing entry field '''
        entry.delete(0, 'end')


class View:
    def __init__(self, parent):
        ''' Class for creating the display '''
        self.parent = parent
        parent.geometry('+300+300')
        parent.columnconfigure(0, weight=1)
        parent.rowconfigure(1, weight=1)
        parent.title('Custom Tkinter Calculator')

        # Entry field
        self.entry = tk.CTkEntry(app, font=('arial', 48, 'normal'), justify='right')
        self.entry.grid(column=0, row=0, sticky='new', padx=12, pady=9)
        self.entry.focus()
        
        # Container for holding the buttons
        container = tk.CTkFrame(app)
        container.grid(column=0, row=1, sticky='news', padx=8, pady=5)

        # Make the buttons even in size
        for i in range(3):
            container.grid_columnconfigure(i, weight=3, uniform='btns')
            container.grid_rowconfigure(i, weight=3, uniform='btns')

        # Empty list to hold the buttons
        self.buttons = []

        # Set some iter variables
        col, row, i = 0, 0, 0

        # List holding the button text
        numbers = [7,8,9,'*',4,5,6,'/',1,2,3,'+',0,'.','=','-']

        # List for changing text color of operators
        special = ['+','-','*','/','=']

        # Create the buttons and add to the list
        for key in numbers:
            color = 'orange' if key in special else 'white'
            self.buttons.append(tk.CTkButton(container, text=key, font=('arial', 28, 'normal'), cursor='hand2', \
                fg_color='transparent', border_color='slategray', corner_radius=15, bg_color='transparent', \
                border_width=5, text_color=color, hover_color='#555555'))
            self.buttons[i].grid(column=col, row=row, sticky='news', padx=4, pady=4)
            if col >= 3:
                row += 1
                col = 0
            else:
                col += 1
            i += 1

        # Add the clear button
        self.buttons.append(tk.CTkButton(container, text='Clear', font=('arial', 28, 'normal'), cursor='hand2', \
            border_color='slategray', corner_radius=15, bg_color='transparent', fg_color='transparent', \
                border_width=5, text_color='tomato', hover_color='#555555'))
        self.buttons[16].grid(column=0, columnspan=4, row=15, sticky='news', padx=4, pady=4)

class Controller:
    ''' Class handles the communications between Calc and View classes '''
    def __init__(self, calc, view):
        self.calc = calc
        self.view = view

        # For validaing input. We only want numbers and the operators
        self._valid = app.register(self.calc.valid)
        self.view.entry.configure(validate='key', validatecommand=(self._valid, '%S'))

        # Setup the button commands
        for button in self.view.buttons:
            if button.cget('text') not in ('Clear', '='):
                button.configure(command=lambda var=button.cget('text'): self.calc.insert(self.view.entry, var))
            elif button.cget('text') == 'Clear':
                button.configure(command=lambda: self.calc.clear(self.view.entry))
            else:
                button.configure(command=lambda:self.calc.calculate(self.view.entry))

        # Bind the buttons
        self.view.parent.bind('<Return>', lambda event: self.calc.calculate(self.view.entry))
        self.view.parent.bind('<KP_Enter>', lambda event: self.calc.calculate(self.view.entry))
        self.view.parent.bind('<Escape>', lambda event: self.calc.clear(self.view.entry))

app = tk.CTk()
Controller(Calc(app), View(app))
app.mainloop()
 
Impressive. Whether it helps the OP, if (s)he is still there, I am not sure. Personally I don't think all this abstraction makes the calculator any easier to understand and maintain. But I guess it depends on what you are used to. For novice users, probably not the optimal approach way to go.

I am intrigued by this syntax color = 'orange' if key in special else 'white' which reminds me of something you had in good old Algol. Since then, most all modern languages have it like this color = key in special ? 'orange' : 'white' but I guess the Python designers explicitly wanted to be different from everybody else. I sometimes get the feeling this was extremely important to them.
 
but I guess the Python designers explicitly wanted to be different from everybody else. I sometimes get the feeling this was extremely important to them.
You are probably right. I think it's good for a quick option for a variable with either a left or right (so to speak). I agree that my code is not really for beginners. I get carried away sometimes when I see the potential of some coding. It's also the first time i have tried customtkinter. I usually prefer tkinter itself but, it does have some things tkinter doesn't. Placeholder text being one.
 

New Threads

Latest posts

Buy us a coffee!

Back
Top Bottom