Add buttons for number system conversion in Python

39 Views Asked by At

I need help with number system conversion. I want to add 4 buttons in the first row named "DEC", "BIN", "OCT" and "HEX". When I click any of the buttons I want them to be written out. For example I click DEC and it types out DEC(which will be the base of the number I will put in), then I put in a number with the number buttons, and lastly I choose another number conversion button for example BIN(which is the target base of the number I input) and when I click the equal button it gives me the number in binary form. I want it to be able to see if the number I put in is really decimal (or any of the other values). If it's not, it gives an error, if it is it gives me the result. For example: BIN111HEX, click equal button and it gives me 7. I hope I was clear. Thanks. :)

This is my current code:

from tkinter import *
from tkinter import filedialog
import tkinter.messagebox
import math

root = Tk()
root.geometry("650x400+300+300")
root.title("Scientific Calculator")
switch = None

#numbers
def btn1_clicked():
    if disp.get() == '0':
        disp.delete(0, END)
    pos = len(disp.get())
    disp.insert(pos, '1')
def btn2_clicked():
    if disp.get() == '0':
        disp.delete(0, END)
    pos = len(disp.get())
    disp.insert(pos, '2')
def btn3_clicked():
    if disp.get() == '0':
        disp.delete(0, END)
    pos = len(disp.get())
    disp.insert(pos, '3')
def btn4_clicked():
    if disp.get() == '0':
        disp.delete(0, END)
    pos = len(disp.get())
    disp.insert(pos, '4')
def btn5_clicked():
    if disp.get() == '0':
        disp.delete(0, END)
    pos = len(disp.get())
    disp.insert(pos, '5')
def btn6_clicked():
    if disp.get() == '0':
        disp.delete(0, END)
    pos = len(disp.get())
    disp.insert(pos, '6')
def btn7_clicked():
    if disp.get() == '0':
        disp.delete(0, END)
    pos = len(disp.get())
    disp.insert(pos, '7')
def btn8_clicked():
    if disp.get() == '0':
        disp.delete(0, END)
    pos = len(disp.get())
    disp.insert(pos, '8')
def btn9_clicked():
    if disp.get() == '0':
        disp.delete(0, END)
    pos = len(disp.get())
    disp.insert(pos, '9')
def btn0_clicked():
    if disp.get() == '0':
        disp.delete(0, END)
    pos = len(disp.get())
    disp.insert(pos, '0')

#operations
def btnp_clicked():
    pos = len(disp.get())
    disp.insert(pos, '+')
def btnm_clicked():
    pos = len(disp.get())
    disp.insert(pos, '-')
def btnml_clicked():
    pos = len(disp.get())
    disp.insert(pos, '*')
def btnd_clicked():
    pos = len(disp.get())
    disp.insert(pos, '/')    
def bl_clicked():
    pos = len(disp.get())
    disp.insert(pos, '(')
def br_clicked():
    pos = len(disp.get())
    disp.insert(pos, ')')
def sqr_clicked():
    try:
        ans = float(disp.get())
        ans = math.sqrt(ans)
        disp.delete(0, END)
        disp.insert(0, str(ans))
    except Exception:
        tkinter.messagebox.showerror("Value Error", "Check your values and operators")
def pow_clicked():
    pos = len(disp.get())
    disp.insert(pos, '**')
def mod_clicked():
    pos = len(disp.get())
    disp.insert(pos, '%')
def dot_clicked():
    pos = len(disp.get())
    disp.insert(pos, '.')
def btneq_clicked():
    try:
        ans = disp.get()
        ans = eval(ans)
        disp.delete(0, END)
        disp.insert(0, ans)
    except:
        tkinter.messagebox.showerror("Value Error", "Check your values and operators")

#deletion
def del_clicked():
    pos = len(disp.get())
    display = str(disp.get())
    if display == '':
        disp.insert(0, '0')
    elif display == ' ':
        disp.insert(0, '0')
    elif display == '0':
        pass
    else:
        disp.delete(0, END)
        disp.insert(0, display[0:pos-1])
def btnc_clicked(*args):
    disp.delete(0, END)
    disp.insert(0, '0')

#branje datoteke
def dat_clicked():
    file_path = filedialog.askopenfilename(filetypes=[('Text Files', '*.txt')])
    
    if file_path:
        with open(file_path, 'r') as file:
            content = file.read().replace('\n', '')
            disp.delete(0, END)  # Clear previous content
   
            pos = len(disp.get())
            disp.insert(pos, content)


data = StringVar()
disp = Entry(root, font="Verdana 20", fg="black", bg="mistyrose", bd=4, justify=RIGHT, insertbackground="#abbab1", cursor="arrow")
disp.pack(expand=TRUE, fill=BOTH)

# Row 1 Buttons
btnrow1 = Frame(root, bg="#000000")
btnrow1.pack(expand=TRUE, fill=BOTH)
mod_btn = Button(btnrow1, text="%", font="Segoe 21", relief=GROOVE, bd=0, command=mod_clicked, fg="white", bg="#333333")
mod_btn.pack(side=LEFT, expand=TRUE, fill=BOTH)
btn1 = Button(btnrow1, text="1", font="Segoe 23", relief=GROOVE, bd=0, command=btn1_clicked, fg="white", bg="#333333")
btn1.pack(side=LEFT, expand=TRUE, fill=BOTH)
btn2 = Button(btnrow1, text="2", font="Segoe 23", relief=GROOVE, bd=0, command=btn2_clicked, fg="white", bg="#333333")
btn2.pack(side=LEFT, expand=TRUE, fill=BOTH)
btn3 = Button(btnrow1, text="3", font="Segoe 23", relief=GROOVE, bd=0, command=btn3_clicked, fg="white", bg="#333333")
btn3.pack(side=LEFT, expand=TRUE, fill=BOTH)
btnp = Button(btnrow1, text="+", font="Segoe 23", relief=GROOVE, bd=0, command=btnp_clicked, fg="white", bg="#333333")
btnp.pack(side=LEFT, expand=TRUE, fill=BOTH)




# Row 2 Buttons
btnrow2 = Frame(root)
btnrow2.pack(expand=TRUE, fill=BOTH)
bl_btn = Button(btnrow2, text=" ( ", font="Segoe 21", relief=GROOVE, bd=0, command=bl_clicked, fg="white", bg="#333333")
bl_btn.pack(side=LEFT, expand=TRUE, fill=BOTH)
br_btn = Button(btnrow2, text=" ) ", font="Segoe 21", relief=GROOVE, bd=0, command=br_clicked, fg="white", bg="#333333")
br_btn.pack(side=LEFT, expand=TRUE, fill=BOTH)
btn4 = Button(btnrow2, text="4", font="Segoe 23", relief=GROOVE, bd=0, command=btn4_clicked, fg="white", bg="#333333")
btn4.pack(side=LEFT, expand=TRUE, fill=BOTH)
btn5 = Button(btnrow2, text="5", font="Segoe 23", relief=GROOVE, bd=0, command=btn5_clicked, fg="white", bg="#333333")
btn5.pack(side=LEFT, expand=TRUE, fill=BOTH)
btn6 = Button(btnrow2, text="6", font="Segoe 23", relief=GROOVE, bd=0, command=btn6_clicked, fg="white", bg="#333333")
btn6.pack(side=LEFT, expand=TRUE, fill=BOTH)
btnm = Button(btnrow2, text="-", font="Segoe 23", relief=GROOVE, bd=0, command=btnm_clicked, fg="white", bg="#333333")
btnm.pack(side=LEFT, expand=TRUE, fill=BOTH)




# Row 3 Buttons
btnrow3 = Frame(root)
btnrow3.pack(expand=TRUE, fill=BOTH)
sqr_btn = Button(btnrow3, text=" √x ", font="Segoe 18", relief=GROOVE, bd=0, command=sqr_clicked, fg="white", bg="#333333")
sqr_btn.pack(side=LEFT, expand=TRUE, fill=BOTH)
pow_btn = Button(btnrow3, text="x^y", font="Segoe 17", relief=GROOVE, bd=0, command=pow_clicked, fg="white", bg="#333333")
pow_btn.pack(side=LEFT, expand=TRUE, fill=BOTH)
btn7 = Button(btnrow3, text="7", font="Segoe 23", relief=GROOVE, bd=0, command=btn7_clicked, fg="white", bg="#333333")
btn7.pack(side=LEFT, expand=TRUE, fill=BOTH)
btn8 = Button(btnrow3, text="8", font="Segoe 23", relief=GROOVE, bd=0, command=btn8_clicked, fg="white", bg="#333333")
btn8.pack(side=LEFT, expand=TRUE, fill=BOTH)
btn9 = Button(btnrow3, text="9", font="Segoe 23", relief=GROOVE, bd=0, command=btn9_clicked, fg="white", bg="#333333")
btn9.pack(side=LEFT, expand=TRUE, fill=BOTH)
btnml = Button(btnrow3, text="*", font="Segoe 23", relief=GROOVE, bd=0, command=btnml_clicked, fg="white", bg="#333333")
btnml.pack(side=LEFT, expand=TRUE, fill=BOTH)



# Row 4 Buttons
btnrow4 = Frame(root)
btnrow4.pack(expand=TRUE, fill=BOTH)
dat_btn_4 = Button(btnrow4, text="dat", font="Segoe 18", relief=GROOVE, bd=0, command=dat_clicked, fg="white", bg="#333333")
dat_btn_4.pack(side=LEFT, expand=TRUE, fill=BOTH)
dot_btn = Button(btnrow4, text=" • ", font="Segoe 21", relief=GROOVE, bd=0, command=dot_clicked, fg="white", bg="#333333")
dot_btn.pack(side=LEFT, expand=TRUE, fill=BOTH)
btnc = Button(btnrow4, text="C", font="Segoe 23", relief=GROOVE, bd=0, command=btnc_clicked, fg="white", bg="#333333")
btnc.pack(side=LEFT, expand=TRUE, fill=BOTH)
del_btn = Button(btnrow4, text="⌫", font="Segoe 20", relief=GROOVE, bd=0, command=del_clicked, fg="white", bg="#333333")
del_btn.pack(side=LEFT, expand=TRUE, fill=BOTH)
btn0 = Button(btnrow4, text="0", font="Segoe 23", relief=GROOVE, bd=0, command=btn0_clicked, fg="white", bg="#333333")
btn0.pack(side=LEFT, expand=TRUE, fill=BOTH)
btneq = Button(btnrow4, text="=", font="Segoe 23", relief=GROOVE, bd=0, command=btneq_clicked, fg="white", bg="#FA8072")
btneq.pack(side=LEFT, expand=TRUE, fill=BOTH)
btnd = Button(btnrow4, text="/", font="Segoe 23", relief=GROOVE, bd=0, command=btnd_clicked, fg="white", bg="#333333")
btnd.pack(side=LEFT, expand=TRUE, fill=BOTH)




root.mainloop()
1

There are 1 best solutions below

0
Tim Roberts On

I'm going to try to demonstrate a couple of things. You have a LARGE amount of repetitive coding here that is totally unnecessary. All of your buttons can be created by a single handler, with just a few options, because you can PASS the digit or operator in. You don't need separate buttons for them.

I've implemented your base conversions in a sneaky way. If you press a base button when there's nothing in the accumulator, then I just insert the Python base prefix (like "0x"). If there is something in the accumulator, I just do the evaluation and display it in the proper base. This is not foolproof, but it's pretty good.

I suppose you will want to add buttons for A, B, C, D, E and F next.

from tkinter import *
import tkinter.messagebox
import math

root = Tk()
root.geometry("650x400+300+300")
root.title("Scientific Calculator")
switch = None

#numbers
def btn_clicked(n):
    if disp.get() == '0':
        disp.delete(0, END)
    pos = len(disp.get())
    disp.insert(pos, n)

#operations
def op_clicked(op):
    pos = len(disp.get())
    disp.insert(pos, op)
def sqr_clicked():
    try:
        ans = float(disp.get())
        ans = math.sqrt(ans)
        disp.delete(0, END)
        disp.insert(0, str(ans))
    except Exception:
        tkinter.messagebox.showerror("Value Error", "Check your values and operators")
def btneq_clicked():
    try:
        ans = disp.get()
        ans = eval(ans)
        disp.delete(0, END)
        disp.insert(0, ans)
    except:
        tkinter.messagebox.showerror("Value Error", "Check your values and operators")

#deletion
def del_clicked():
    display = disp.get()
    pos = len(display)
    if not display or display==' ':
        disp.insert(0, '0')
    elif display == '0':
        pass
    else:
        disp.delete(0, END)
        disp.insert(0, display[0:pos-1])
def btnc_clicked(*args):
    disp.delete(0, END)
    disp.insert(0, '0')

#branje datoteke
def dat_clicked():
    file_path = filedialog.askopenfilename(filetypes=[('Text Files', '*.txt')])
    
    if file_path:
        with open(file_path, 'r') as file:
            content = file.read().replace('\n', '')
            disp.delete(0, END)  # Clear previous content
   
            pos = len(disp.get())
            disp.insert(pos, content)

prefix = {
    2: "0b",
    8: "0o",
    10: "",
    16: "0x"
};
convert = {
    2: bin,
    8: oct,
    10: int,
    16: hex
};

def set_base(n):
    display = disp.get()
    if not display or display=="0":
        disp.delete(0,END)
        disp.insert(0,prefix[n])
    else:
        try:
            ans = eval(display)
            ans = convert[n](ans)
            disp.delete(0, END)
            disp.insert(0, ans)
        except:
            tkinter.messagebox.showerror("Value Error", "Check your values and operators")
    

def make_btn(row, n, font=23, cb=None):
    font = f"Segoe {font}"
    if n.isdigit():
        btn = Button(row, text=n, font=font, relief=GROOVE, bd=0, command=lambda: btn_clicked(n), fg="white", bg="#333333")
    elif cb is not None:
        btn = Button(row, text=n, font=font, relief=GROOVE, bd=0, command=cb, fg="white", bg="#333333")
    else:
        btn = Button(row, text=n, font=font, relief=GROOVE, bd=0, command=lambda: op_clicked(n), fg="white", bg="#333333")
    btn.pack(side=LEFT, expand=TRUE, fill=BOTH)

data = StringVar()
disp = Entry(root, font="Verdana 20", fg="black", bg="mistyrose", bd=4, justify=RIGHT, insertbackground="#abbab1", cursor="arrow")
disp.pack(expand=TRUE, fill=BOTH)

btnrow1 = Frame(root, bg="#000000")
btnrow1.pack(expand=TRUE, fill=BOTH)
make_btn(btnrow1, "DEC", 21, lambda: set_base(10))
make_btn(btnrow1, "OCT", 21, lambda: set_base(8))
make_btn(btnrow1, "HEX", 21, lambda: set_base(16))
make_btn(btnrow1, "BIN", 21, lambda: set_base(2))

# Row 1 Buttons
btnrow1 = Frame(root, bg="#000000")
btnrow1.pack(expand=TRUE, fill=BOTH)
make_btn(btnrow1, "%", 21)
for i in "123+":
    make_btn(btnrow1, i)

# Row 2 Buttons
btnrow2 = Frame(root)
btnrow2.pack(expand=TRUE, fill=BOTH)
make_btn(btnrow2, "(", 21)
make_btn(btnrow2, ")", 21)
for i in "456-":
    make_btn(btnrow2, i, 23)

# Row 3 Buttons
btnrow3 = Frame(root)
btnrow3.pack(expand=TRUE, fill=BOTH)
make_btn(btnrow3, " √x ", 18, sqr_clicked)
make_btn(btnrow3, "x^y", 17)
for i in "789*":
    make_btn(btnrow3, i)

# Row 4 Buttons
btnrow4 = Frame(root)
btnrow4.pack(expand=TRUE, fill=BOTH)
make_btn(btnrow4, "dat", 18, dat_clicked)
make_btn(btnrow4, " • ", 21)
make_btn(btnrow4, "C", 23, btnc_clicked)
make_btn(btnrow4, "⌫", 20, del_clicked)
make_btn(btnrow4, "0")
make_btn(btnrow4, "=", 23, btneq_clicked)
make_btn(btnrow4, "/")

root.mainloop()

Here's an even more compact way to do it, which makes your layout more data-oriented:

layout = [
    (
        ("DEC", 21, lambda: set_base(10)),
        ("OCT", 21, lambda: set_base(8)),
        ("HEX", 21, lambda: set_base(16)),
        ("BIN", 21, lambda: set_base(2))
    ),
    (
        "%",
        "1",
        "2",
        "3",
        "+"
    ),
    (
        ("(", 21),
        (")", 21),
        "4",
        "5",
        "6",
        "-"
    ),
    (
        (" √x ", 18, sqr_clicked),
        ("x^y", 17),
        "7",
        "8",
        "9",
    ),
    (
        ("dat", 18, dat_clicked),
        (" • ", 21),
        ("C", 23, btnc_clicked),
        ("⌫", 20, del_clicked),
        "0",
        ("=", 23, btneq_clicked),
        "/"
    )
]

for row in layout:
    row1 = Frame(root, bg="#000000")
    row1.pack(expand=TRUE, fill=BOTH)
    for btn in row:
        if isinstance(btn,str):
            make_btn(row1, btn)
        else:
            make_btn(row1, *btn)

root.mainloop()