NumSys Calculator by Azav

Iniciado por Azav, Enero 23, 2015, 04:16:23 AM

Tema anterior - Siguiente tema

0 Miembros y 1 Visitante están viendo este tema.

Numbering System Calculator by Azav

La semana pasada estuve investigando las representaciones ASCII de los caracteres, para las cuales se usan distintos sistemas numéricos (varían en su base). Los cuatro sistemas numéricos más usados son el binario, el octal, el decimal y el hexadecimal. Por ejemplo: la letra 'a' tiene por valor ASCII el numero 97 en el sistema decimal, o bien 1100001 en binario, o bien 141 en octal o bien 61 en hexadecimal (este último es que se usa en los editores de archivos ejecutables). Resulta que para entender mejor cómo se llevan a cabo las transformaciones de un sistema a otro creé esta herramienta , que también permite realizar operaciones (suma y resta) en los diversos sistemas numéricos. No es nada del otro mundo pero a mi me sirvió para entender mejor cómo funcionan estos sistemas.

La herramienta la programé en Python 3.4 y usé tkinter para la interfaz gráfica. Convertí el archivo .py a ejecutable usando py2exe. Captura (se ve un poco mal):


Source code:
Código: python
from tkinter import *
from tkinter import messagebox, ttk

def cambio_de_base(base, valorbase10):
caracteres = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
lista = [valorbase10]
while True:
division = valorbase10 // base
if division == 0:
break
else:
lista.append(division)
valorbase10 = division
lista.reverse()
valorbase2 = ''
for i in lista:
resto = i % base
valorbase2 += caracteres[resto:resto + 1]
return valorbase2

def cambio_a_decimal(base, valorbase):
caracteres = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
for char in valorbase:
if caracteres[:base].find(char) == -1:
return "ERROR"
j = len(valorbase)
k = -1
sumatoria = 0
for i in range(j):
valor_parcial = caracteres.find(valorbase[k:j]) * (base ** i)
sumatoria = sumatoria + valor_parcial
j = k
k = k - 1
return sumatoria


class Interfaz():
def __init__(self):
#Main Window
self.mainWindow = Tk()
self.mainWindow.geometry("450x250")
self.mainWindow.title("Azav's Numeric Calculator")
self.mainWindow.protocol("WM_DELETE_WINDOW", self.quit)

#ComboBoxs
ComboVar = StringVar()
self.Combo = ttk.Combobox(self.mainWindow, textvariable=ComboVar, width = "2", values=('+', '-'))
self.Combo.place(x=105, y=85)

#Textboxs
self.Sumando1 = Text(self.mainWindow, height = "0.7", width = "30", relief = "flat")
self.Sumando1.place(x=150, y=55)
self.Sumando2 = Text(self.mainWindow, height = "0.7", width = "30", relief = "flat")
self.Sumando2.place(x=150, y=85)
self.Suma = Text(self.mainWindow, height = "0.7", width = "30", relief = "flat")
self.Suma.place(x=150, y=140)

def start(self):
def Operate():
nro1 = self.Sumando1.get('1.0', 'end').strip().upper()
nro2 = self.Sumando2.get('1.0', 'end').strip().upper()
base = OptVar.get()
nro1_dec = cambio_a_decimal(base, nro1)
nro2_dec = cambio_a_decimal(base, nro2)
if nro1_dec == "ERROR":
messagebox.showwarning("Azav's Numeric Calculator", nro1 + " is not a valid value for base " + str(base) + ".")
return
if nro2_dec == "ERROR":
messagebox.showwarning("Azav's Numeric Calculator", nro2 + " is not a valid value for base " + str(base) + ".")
return
if self.Combo.get().strip() == '+':
resultado = nro1_dec + nro2_dec
else:
resultado = nro1_dec - nro2_dec
if resultado < 0:
messagebox.showwarning("Azav's Numeric Calculator", "Negative numbers are not supported.")
return
resultado_base = cambio_de_base(base, resultado)
self.Suma.delete('1.0', 'end')
self.Suma.insert('1.0', str(resultado_base))
info_list = []
if base != 2:
info_list.append("Binary result: " + str(cambio_de_base(2, resultado)))
if base != 8:
info_list.append("Octal result: " + str(cambio_de_base(8, resultado)))
if base != 10:
info_list.append("Decimal result: " + str(resultado))
if base != 16:
info_list.append("Hexdecimal result: " + str(cambio_de_base(16, resultado)))
info = ""
for i in info_list:
info = info + i + "\n"
lbInfo['text'] = info

def BaseConverter():
base = OptVar.get()
suma = self.Suma.get('1.0', 'end').strip().upper()
NewGUI = BaseConverterGUI()
NewGUI.txtBase.delete('1.0', 'end')
NewGUI.txtBase.insert('1.0', str(base))
exec("NewGUI.txt" + str(base) + ".delete('1.0', 'end')")
exec("NewGUI.txt" + str(base) + ".insert('1.0', suma)")
NewGUI.ConvertBases()
NewGUI.start()

#Combo Config
self.Combo.set('+')

#OptionButton
OptVar = IntVar()
opt1 = Radiobutton(self.mainWindow, text="Binary", width = "10", variable=OptVar, indicatoron=0, value=2).place(x=15, y=15)
opt2 = Radiobutton(self.mainWindow, text="Octal", width = "10", variable=OptVar, indicatoron=0, value=8).place(x=115, y=15)
opt3 = Radiobutton(self.mainWindow, text="Decimal", width = "10", variable=OptVar, indicatoron=0, value=10).place(x=215, y=15)
opt4 = Radiobutton(self.mainWindow, text="Hexdecimal", width = "10", variable=OptVar, indicatoron=0, value=16)
opt4.place(x=315, y=15)
opt4.select()

#Buttons
cmdCalcular = Button(self.mainWindow,  text = "Calculate", width = "10", height = "4", command = lambda:Operate()).place(x=15, y=55)
cmdBaseConverter = Button(self.mainWindow,  text = "Base Convert", width = "10", height = "1", command = lambda:BaseConverter()).place(x=15, y=140)

#Labels
lbLine = Label(self.mainWindow, text="__________________________________", font=("Courier New", 8)).place(x=150, y=110)
lbInfo = Label(self.mainWindow, text="", font=("Courier New", 10), justify="left")
lbInfo.place(x=15, y=180)

#Start
self.mainWindow.mainloop()

def quit(self):
if messagebox.askyesno("Azav's Numeric Calculator", "Are you sure you want to quit?"):
self.mainWindow.destroy()
self.mainWindow.quit()
quit()


class BaseConverterGUI():
def __init__(self):
#Main Window
self.mainWindow = Tk()
self.mainWindow.geometry("1100x500")
self.mainWindow.title("Azav's Numeric Calculator")

#TextBoxs
for i in range(2, 14):
exec('self.txt' + str(i) + ' = Text(self.mainWindow, height = "0.6", width = "30", relief = "flat")')
exec('self.txt' + str(i) + '.place(x=90, y=' + str(30 * i) + ')')
for i in range(14, 26):
exec('self.txt' + str(i) + ' = Text(self.mainWindow, height = "0.6", width = "30", relief = "flat")')
exec('self.txt' + str(i) + '.place(x=460, y=' + str(30 * (i - 12)) + ')')
for i in range(26, 37):
exec('self.txt' + str(i) + ' = Text(self.mainWindow, height = "0.6", width = "30", relief = "flat")')
exec('self.txt' + str(i) + '.place(x=830, y=' + str(30 * (i - 24)) + ')')

self.txtBase = Text(self.mainWindow, height = "0.6", width = "10", relief = "flat")
self.txtBase.place(x=575, y=470)
self.txtBase.insert('1.0', '10')

def start(self):
def DoConversion():
self.ConvertBases()

#Labels
for i in range(2, 14):
if i == 2 or i == 8 or i == 10:
color = ', fg = "red"'
else:
color = ''
exec('lb' + str(i) + ' = Label(self.mainWindow' + color + ', text="Base ' + str(i) + ':", font=("Courier New", 10)).place(x=20, y=' + str(30 * i) + ')')
for i in range(14, 26):
if i == 16:
color = ', fg = "red"'
else:
color = ''
exec('lb' + str(i) + ' = Label(self.mainWindow' + color + ', text="Base ' + str(i) + ':", font=("Courier New", 10)).place(x=390, y=' + str(30 * (i - 12)) + ')')
for i in range(26, 37):
exec('lb' + str(i) + ' = Label(self.mainWindow, text="Base ' + str(i) + ':", font=("Courier New", 10)).place(x=760, y=' + str(30 * (i - 24)) + ')')
lbBase = Label(self.mainWindow, text="Base:", font=("Courier New", 10)).place(x=520, y=470)

#Buttons
cmdCalcular = Button(self.mainWindow,  text = "Calculate", width = "25", command = lambda:DoConversion()).place(x=500, y=440)

#Start
self.mainWindow.mainloop()

def ConvertBases(self):
local_var = locals()
BaseGuia = self.txtBase.get('1.0', 'end').strip()
try:
int(BaseGuia)
except:
messagebox.showwarning("Azav's Numeric Calculator", "Base must be a number.")
return
if int(BaseGuia) < 2 or int(BaseGuia) > 36:
messagebox.showwarning("Azav's Numeric Calculator", "Base must be a value beetween 2 and 36.")
return
exec("valor = self.txt" + BaseGuia + ".get('1.0', 'end').strip().upper()", globals(), local_var)
base_decimal = cambio_a_decimal(int(BaseGuia), local_var['valor'])
if base_decimal == "ERROR":
messagebox.showwarning("Azav's Numeric Calculator", local_var['valor'] + " is not valid value for base " + BaseGuia + ".")
return
else:
for i in range(2, 37):
exec("self.txt" + str(i) + ".delete('1.0', 'end')")
exec("self.txt" + str(i) + ".insert('1.0', cambio_de_base(i, base_decimal))")


GUI = Interfaz()
GUI.start()

Lo importante son las dos funciones del inicio, el resto es pura interfaz.

¡Espero le sirva a alguien!

Muy bueno, ahora mismo leo el código pues se ve interesante y no sé apenas python ^^

Gracias :D



Bastante curioso el programa.  :o
Buen aporte. xD

Saludos!