1 Star 0 Fork 0

linzichang/ProCalc

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
ProCalc.py 23.97 KB
一键复制 编辑 原始数据 按行查看 历史
linzichang 提交于 2021-11-19 16:05 . init
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576
# -*- coding: utf-8 -*-
# An calculator for Programmer
__author__ = 'Zichang Lin'
from tkinter import *
from tkinter import ttk
import tkinter.messagebox
import tkinter.colorchooser
import re
import struct
import math
import ctypes
import os
class CalcUI:
def __init__(self):
root = Tk()
root.title("ProCalc 1.1")
self.bit_labels = []
self.bit_buttons = []
self.bit_vars = []
self.display = {}
self.computing = 0
self.bit_done = 0
self.value_size = IntVar()
self.value_size.set(64)
self.value_format = IntVar()
self.value_format.set(16)
self.bit_color = '#87CEFA'
screenwidth = root.winfo_screenwidth()
screenheight = root.winfo_screenheight()
width = 1010
height = 450
size = '%dx%d+%d+%d' % (width, height, (screenwidth - width) / 2, (screenheight - height) / 2)
root.geometry(size)
def resource_path(relative):
if hasattr(sys, '_MEIPASS'):
return os.path.join(sys._MEIPASS, relative)
return os.path.join(relative)
ico_path = resource_path(r'ooopic.ico')
if os.path.exists(ico_path):
root.iconbitmap(default=ico_path)
self.create_menu(root)
self.create_bit_area(root)
self.create_calculator(root)
self.create_display(root)
root.resizable(False, False)
root.mainloop()
def create_menu(self, root):
menu = Menu(root)
menu.add_command(label="Help", command=self.help)
menu.add_command(label="About", command=self.about)
root['menu'] = menu
def bit_click(self, index):
s = self.bit_vars[index].get()
v = 1 ^ int(s)
self.bit_vars[index].set(str(v))
if v == 1:
self.bit_buttons[index]['relief'] = SOLID
self.bit_buttons[index]['bg'] = self.bit_color
else:
self.bit_buttons[index]['relief'] = RAISED
self.bit_buttons[index]['bg'] = 'SystemButtonFace'
cur = self.display['DEC'].get()
if cur == '':
cur = '0'
new_v = int(cur) ^ (1 << index)
if new_v == 0:
self.clean()
else:
self.bit_done = 1
self.display['DEC'].set(str(new_v))
def create_bit_area(self, root):
area = ttk.Frame(root)
area.grid(column=0, row=0, columnspan=2)
frames = []
for x in [0, 1]:
for y in [0, 1, 2, 3, 4, 5, 6, 7]:
f = ttk.Frame(area, height=60, width=122, borderwidth=2, relief=SUNKEN)
f.grid(row=x, column=y, padx=2, pady=2)
f.grid_propagate(0)
frames.insert(0, f)
nr = 0
for frame in frames:
for n in [3, 2, 1, 0]:
t = "%02d" % nr
lb = ttk.Label(frame, text=t)
lb.grid(row=0, column=n, padx=3, pady=1)
bit = StringVar()
bit.set('0')
b = Button(frame, textvariable=bit, height=1, width=2, anchor=CENTER,
command=lambda index=nr: self.bit_click(index))
b.grid(row=1, column=n, padx=3, pady=1)
nr = nr + 1
self.bit_labels.append(lb)
self.bit_buttons.append(b)
self.bit_vars.append(bit)
def clean(self):
self.computing = 1
for text in self.display.values():
text.set('')
for index in range(self.value_size.get()):
self.bit_vars[index].set('0')
self.bit_buttons[index]['relief'] = RAISED
self.bit_buttons[index]['bg'] = 'SystemButtonFace'
self.computing = 0
def create_calculator(self, root):
calc = ttk.Frame(root, width=70, relief=GROOVE)
calc.grid(row=1, column=0, columnspan=3, sticky=W, padx=8, pady=4, ipady=1)
process_prev = Label(calc, text='', width=66, height=2, background='white', anchor='e', relief=SUNKEN)
process_prev.grid(row=0, columnspan=12, sticky=W)
process_now = Label(calc, text='0', width=66, height=2, anchor='e', relief=SUNKEN)
process_now.grid(row=1, columnspan=12, sticky=W)
reset = True
operation = False
format_mapping = {
16: 'HEX',
10: 'DEC',
8: 'OCT',
2: 'BIN'
}
def copy_click():
root.clipboard_clear()
root.clipboard_append(process_now['text'])
def paste_click():
number = root.clipboard_get()
key = format_mapping.get(self.value_format.get())
if self.check(number, key):
number = number.replace('0x', '').replace('0X', '')
process_now['text'] = number
else:
print('Error: Input Invalid!\n')
tkinter.messagebox.showerror('Error', 'Input Invalid!')
print(number)
menu = tkinter.Menu(process_now, tearoff=False)
menu.add_command(label="复制", command=copy_click)
menu.add_command(label="粘贴", command=paste_click)
def show_menu(event):
menu.post(event.x_root, event.y_root)
process_now.bind("<Button-3>", show_menu)
Button(calc, text='Copy', width=8, command=copy_click).grid(row=2, column=2)
Button(calc, text='Paste', width=8, command=paste_click).grid(row=2, column=4)
pattern = re.compile(r'[0-9A-F]+')
def add_prefix(matched):
matched_str = matched.group()
if self.value_format.get() == 16:
return '0x' + matched_str
elif self.value_format.get() == 10:
return matched_str
elif self.value_format.get() == 8:
return '0o' + matched_str
elif self.value_format.get() == 2:
return '0b' + matched_str
def calc_callback(num):
global reset
global operation
def calculate():
str_in = re.sub(pattern, add_prefix, process_prev['text']+process_now['text'])
count = 0
for c in str_in:
if c == '(':
count += 1
elif c == ')':
count -= 1
if count != 0:
print('Error: Parentheses is Unbalanced!\n')
tkinter.messagebox.showerror('Error', 'Parentheses is Unbalanced!')
return -1
try:
result = eval(str_in)
except SyntaxError:
print('Error: Expression Syntax Error!\n')
tkinter.messagebox.showerror('Error', 'Expression Syntax Error!')
return -1
except ZeroDivisionError:
print('Error: Division By Zero!\n')
tkinter.messagebox.showerror('Error', 'Division by Zero!')
return -1
if self.value_size.get() == 64:
result = ctypes.c_longlong(math.floor(result)).value
u_result = ctypes.c_ulonglong(math.floor(result)).value
else:
result = ctypes.c_int(math.floor(result)).value
u_result = ctypes.c_uint(math.floor(result)).value
if result > 0:
self.display['DEC'].set(str(result))
else:
self.display['-DEC'].set(str(result))
output = ''
if self.value_format.get() == 10:
output = str(result)
elif self.value_format.get() == 16:
output = hex(u_result)
elif self.value_format.get() == 8:
output = oct(u_result)
elif self.value_format.get() == 2:
output = bin(u_result)
process_now['text'] = output
return 0
if num == 'Clean':
process_prev['text'] = ''
process_now['text'] = '0'
self.clean()
return
if num == 'Swap':
if calculate() == 0:
cur_str = self.display['DEC'].get()
if int(cur_str) != '0':
if self.value_size.get() == 64:
self.display['DEC'].set(struct.unpack('Q', struct.pack('>Q', int(cur_str)))[0])
if self.value_size.get() == 32:
self.display['DEC'].set(struct.unpack('L', struct.pack('>L', int(cur_str)))[0])
if self.value_format.get() == 10:
if self.display['-DEC'].get() != '':
process_now['text'] = self.display['-DEC'].get()
else:
process_now['text'] = self.display['DEC'].get()
elif self.value_format.get() == 16:
process_now['text'] = self.display['HEX'].get()
elif self.value_format.get() == 8:
process_now['text'] = self.display['OCT'].get()
elif self.value_format.get() == 2:
process_now['text'] = self.display['BIN'].get()
return
if num == 'Delete':
if process_now['text'][-1] == '<' or process_now['text'][-1] == '>':
process_now['text'] = process_now['text'][0:-2]
else:
process_now['text'] = process_now['text'][0:-1]
return
if num in '=':
if calculate() == 0:
process_prev['text'] = ''
reset = True
return
if process_now['text'] == '0' or reset is True:
if num in ['<<', '>>', '|', '^', '~', '&', '%', '/', '*', '-', '+']:
process_prev['text'] = process_now['text'] + num
else:
process_now['text'] = num
reset = False
else:
if operation is True:
if num in ['<<', '>>', '|', '^', '~', '&', '%', '/', '*', '-', '+']:
if process_prev['text'][-1] in ['|', '^', '~', '&', '%', '/', '*', '-', '+']:
process_prev['text'] = process_prev['text'][0:-1] + num
elif process_prev['text'][-2:] in ['<<', '>>']:
process_prev['text'] = process_prev['text'][0:-2] + num
else:
process_now['text'] = num
else:
if num in ['<<', '>>', '|', '^', '~', '&', '%', '/', '*', '-', '+']:
process_prev['text'] = process_prev['text'] + process_now['text'] + num
else:
process_now['text'] = process_now['text'] + num
if num in ['<<', '>>', '|', '^', '~', '&', '%', '/', '*', '-', '+']:
operation = True
else:
operation = False
button_text = ['<<', '>>', '|', '^', '~', '&',
'(', ')', '%', 'Swap', 'Delete', 'Clean',
'A', 'B', '7', '8', '9', '/',
'C', 'D', '4', '5', '6', '*',
'E', 'F', '1', '2', '3', '-']
button_hex = []
button_dec = []
button_oct = []
for i in range(5):
for j in range(6):
n = button_text[i * 6 + j]
b = Button(calc, text=n, width=8, command=lambda x=n: calc_callback(x))
b.grid(row=i + 3, column=j)
if n in ['A', 'B', 'C', 'D', 'E', 'F']:
button_hex.append(b)
b['state'] = DISABLED
b['relief'] = GROOVE
elif n in ['9', '8']:
button_dec.append(b)
elif n in ['7', '6', '5', '4', '3', '2']:
button_oct.append(b)
button_text = ['0', '=', '+']
for i in range(3):
b = Button(calc, text=button_text[i], width=8, command=lambda x=button_text[i]: calc_callback(x))
b.grid(row=8, column=3 + i)
def size_change():
if self.value_size.get() == 64:
for x in range(32, 64):
self.bit_buttons[x]['state'] = NORMAL
self.bit_buttons[x]['relief'] = RAISED
self.bit_labels[x]['state'] = NORMAL
elif self.value_size.get() == 32:
s = self.display['DEC'].get()
if s != '':
d_value = int(s) & 0xffffffff
self.display['DEC'].set(str(d_value))
for x in range(32, 64):
self.bit_buttons[x]['state'] = DISABLED
self.bit_buttons[x]['relief'] = GROOVE
self.bit_buttons[x]['bg'] = 'SystemButtonFace'
self.bit_labels[x]['state'] = DISABLED
self.bit_vars[x].set('0')
r_64 = Radiobutton(calc, text='64bit', variable=self.value_size, value=64, command=size_change)
r_64.grid(row=3, column=6, padx=4, sticky=W)
r_64.select()
r_32 = Radiobutton(calc, text='32bit', variable=self.value_size, value=32, command=size_change)
r_32.grid(row=4, column=6, padx=4, sticky=W)
def format_change():
for x in button_hex + button_dec + button_oct:
x['state'] = NORMAL
x['relief'] = RAISED
if self.value_format.get() <= 10:
for x in button_hex:
x['state'] = DISABLED
x['relief'] = GROOVE
if self.value_format.get() <= 8:
for x in button_dec:
x['state'] = DISABLED
x['relief'] = GROOVE
if self.value_format.get() <= 2:
for x in button_oct:
x['state'] = DISABLED
x['relief'] = GROOVE
i = 5
for k, v in format_mapping.items():
r = Radiobutton(calc, text=v, variable=self.value_format, value=k, command=format_change)
r.grid(row=i, column=6, padx=4, sticky=W)
i += 1
if v == 'DEC':
r.select()
checked = StringVar()
def check_change():
c = checked.get()
if c == 'CheckOn':
root.wm_attributes('-topmost', 1)
if c == 'CheckOff':
root.wm_attributes('-topmost', 0)
top_selector = Checkbutton(calc, text='On The Top', width=12, relief=RAISED, variable=checked,
onvalue='CheckOn', offvalue='CheckOff', command=check_change)
top_selector.grid(row=8, column=1, columnspan=2, sticky=SE, padx=1)
top_selector.deselect()
def color_setting():
(rgb, hx) = tkinter.colorchooser.askcolor()
self.bit_color = hx
for index in range(self.value_size.get()):
b_value = self.bit_vars[index].get()
if b_value == '1':
self.bit_buttons[index]['bg'] = self.bit_color
Button(calc, text='Button Color', width=12, command=color_setting).grid(row=8, column=0, columnspan=2, sticky=W)
def display_change(self, key):
def transform(d_value):
neg = 0
if d_value < 0:
self.display['-DEC'].set(str(d_value))
if self.value_size.get() == 64:
neg = struct.unpack('Q', struct.pack('q', d_value))[0]
if self.value_size.get() == 32:
neg = struct.unpack('L', struct.pack('l', d_value))[0]
d_value = int(neg)
else:
if self.value_size.get() == 64:
neg = struct.unpack('q', struct.pack('Q', d_value))[0]
if self.value_size.get() == 32:
neg = struct.unpack('l', struct.pack('L', d_value))[0]
if int(neg) < 0:
self.display['-DEC'].set(neg)
else:
self.display['-DEC'].set('')
self.display['HEX'].set(hex(d_value)[2:])
self.display['DEC'].set(str(d_value))
self.display['OCT'].set(oct(d_value)[2:])
self.display['BIN'].set(bin(d_value)[2:])
self.display['GiB'].set(str(math.floor(d_value/1024/1024/1024)))
self.display['MiB'].set(str(math.floor(d_value/1024/1024)))
self.display['KiB'].set(str(math.floor(d_value/1024)))
shift = 0
if self.bit_done == 0:
while shift < self.value_size.get():
bit = (d_value >> shift) & 1
self.bit_vars[shift].set(str(bit))
if bit == 1:
self.bit_buttons[shift]['relief'] = SOLID
self.bit_buttons[shift]['bg'] = self.bit_color
else:
self.bit_buttons[shift]['relief'] = RAISED
self.bit_buttons[shift]['bg'] = 'SystemButtonFace'
shift += 1
self.bit_done = 0
def input_to_value(case, text):
switcher = {
'HEX': lambda x: int(x, 16),
'DEC': lambda x: int(x),
'-DEC': lambda x: int(x),
'OCT': lambda x: int(x, 8),
'BIN': lambda x: int(x, 2),
'GiB': lambda x: int(x) * 1024 * 1024 * 1024,
'MiB': lambda x: int(x) * 1024 * 1024,
'KiB': lambda x: int(x) * 1024
}
func = switcher.get(case)
return func(text)
if self.computing == 0:
self.computing = 1
s = self.display[key].get()
s = s.replace('0x', '').replace('0X', '')
if s != '':
if s == '-':
self.computing = 0
return
v = input_to_value(key, s)
transform(v)
else:
for value in self.display.values():
value.set('')
for index in range(self.value_size.get()):
self.bit_vars[index].set('0')
self.bit_buttons[index]['relief'] = RAISED
self.bit_buttons[index]['bg'] = 'SystemButtonFace'
self.computing = 0
elif self.computing == 1:
pass
pattern_hex = re.compile(r'\A[0-9a-fA-F]+\Z')
pattern_dec = re.compile(r'\A[0-9]+\Z')
pattern_neg_dec = re.compile(r'^(-)([0-9])*$')
pattern_oct = re.compile(r'\A[0-7]+\Z')
pattern_bin = re.compile(r'\A[0-1]+\Z')
def check(self, content, key):
size = self.value_size.get()
if content == '':
return True
if key == 'HEX':
content = content.replace('0x', '').replace('0X', '')
if self.pattern_hex.match(content):
if size == 64 and len(content) <= 16:
return True
elif size == 32 and len(content) <= 8:
return True
return False
if key == 'DEC':
if self.pattern_dec.match(content):
if size == 64 and int(content) <= 18446744073709551615:
return True
if size == 32 and int(content) <= 4294967295:
return True
return False
if key == '-DEC':
if self.pattern_neg_dec.match(content):
if content == '-':
return True
elif size == 64 and int(content) >= -9223372036854775808:
return True
elif size == 32 and int(content) >= -2147483648:
return True
return False
if key == 'OCT':
if self.pattern_oct.match(content):
if size == 64 and int(content, 8) <= 0o1777777777777777777777:
return True
if size == 32 and int(content, 8) <= 0o37777777777:
return True
return False
if key == 'BIN':
if self.pattern_bin.match(content):
if size == 64 and len(content) <= 64:
return True
if size == 32 and len(content) <= 32:
return True
return False
if key == 'GiB':
if self.pattern_dec.match(content):
if size == 64 and int(content) <= 17179869184:
return True
if size == 32 and int(content) <= 3:
return True
return False
if key == 'MiB':
if self.pattern_dec.match(content):
if size == 64 and int(content) <= 17592186044416:
return True
if size == 32 and int(content) <= 4095:
return True
return False
if key == 'KiB':
if self.pattern_dec.match(content):
if size == 64 and int(content) <= 18014398509481984:
return True
if size == 32 and int(content) <= 4194303:
return True
return False
def create_display(self, root):
display = ttk.Frame(root, width=60, relief=GROOVE)
display.grid(row=1, column=1, sticky=E)
text = ['HEX', 'DEC', '-DEC', 'OCT', 'BIN', 'GiB', 'MiB', 'KiB']
def label_set(value, border):
if border == 'high' and int(value) < bit_low.get():
scale_high.set(bit_low.get())
elif border == 'low' and int(value) > bit_high.get():
scale_low.set(bit_high.get())
value_all = self.display['DEC'].get()
if value_all != '':
v = (int(value_all) & ((1 << (bit_high.get() + 1)) - 1)) >> bit_low.get()
value_part.set(hex(v))
bit_high = IntVar()
bit_low = IntVar()
value_part = StringVar()
scale_high = Scale(display, from_=63, to=0, orient=HORIZONTAL, variable=bit_high,
command=lambda v, x='high': label_set(v, x))
scale_high.set(63)
scale_high.grid(row=0, column=1, padx=8, pady=4, sticky=E)
entry_middle = Entry(display, width=18, textvariable=value_part)
entry_middle.grid(row=0, column=2, padx=8, pady=4, sticky=SE)
scale_low = Scale(display, from_=63, to=0, orient=HORIZONTAL, variable=bit_low,
command=lambda v, x='low': label_set(v, x))
scale_low.set(0)
scale_low.grid(row=0, column=3, padx=8, pady=4, sticky=E)
check_cmd = root.register(self.check)
for n, t in enumerate(text):
ttk.Label(display, text=t).grid(row=n+1, column=0, padx=8, pady=4)
s = StringVar()
s.set('')
s.trace('w', lambda a, b, c, key=t: self.display_change(key))
entry = Entry(display, textvariable=s, width=65, validate='key',
validatecommand=(check_cmd, '%P', t))
entry.grid(row=n+1, column=1, padx=8, pady=4, columnspan=3)
self.display[t] = s
Label(display, text='Author: Lin Zichang 00527239').grid(row=9, column=2, columnspan=8, sticky=S, pady=4)
@staticmethod
def help():
tkinter.messagebox.showinfo('ProCalc Help', 'TODO: Help Document by Lin Zichang 00527239')
@staticmethod
def about():
tkinter.messagebox.showinfo('About ProCalc', 'Programmer Calculator 1.1 by Lin Zichang 00527239')
if __name__ == "__main__":
CalcUI()
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Python
1
https://gitee.com/linzichang/pro-calc.git
git@gitee.com:linzichang/pro-calc.git
linzichang
pro-calc
ProCalc
master

搜索帮助

23e8dbc6 1850385 7e0993f3 1850385