Проблемы с кнопками в tkinter
У меня странности с отображением кнопок. Когда я пытаюсь создать кнопки в цикле, используя TkMatrix возникают проблемы. У полученных кнопок разные тексты, но одинаковая команда. Подскажите, пожалуйста в чем проблема. И если знаете как исправить ,ответьте ,пожалуйста. можно ли исправить, не меняя кардинально программу.
from tkinter import *; from math import ceil, sqrt, floor, exp, log, acos, asin, atan, cos as radcos, sin as radsin, radians, gamma, pi, e, factorial, gcd, tan
from tkinter.messagebox import showerror as she, showinfo as shi; from random import *
from collections import Counter, deque, defaultdict
from functools import reduce, partialmethod, partial
from itertools import permutations, cycle, chain, starmap
sin = lambda x: round(radsin(radians(x)), ndigits=10)
cos = lambda x: round(radcos(radians(x)), ndigits=10)
tg = lambda x: round(tan(radians(x)), ndigits=10)
ctg = lambda x: 1 / tg(x)
cyc = [{i[0]: i[1]} for i in zip(['text', 'text', 'text'], ['Factorize mode', 'Normal mode', 'Engineer mode'])]
lasts = deque([None] * 10, maxlen=10)
w = lambda *theta: map(lambda x: dict(zip(['text', 'command'], (x[0], lambda: Enter(string=x[1])))), theta)
class FloatError(Exception):
pass
class FactorizationError(Exception):
pass
class UserButton(Button):
def __init__(self,Mat=None, coords=None, **kwargs):
self.coords = coords
self.Mat = Mat
super().__init__(**kwargs)
def tkinsert(self, **d):
x, y = self.coords
self.config(**d)
self.place(x=self.Mat.null_x + int(x * 30), y=self.Mat.null_y + int(y * 30))
class TkMatrix:
def __init__(self, tk, alpha, beta):
self.null_x = alpha + 200
self.null_y = beta
self.d = defaultdict(lambda: defaultdict(lambda: UserButton(Mat=self, master=tk, text='pass', bg='grey', command=lambda: None, width=2, height=1)))
self.mut = dict()
def __getitem__(self, key):
x, y = key
self.d[x][y].coords = key
return self.d[x][y]
def mutable(self, key, cyc):
self.mut[key] = cycle(cyc)
def transform(self):
for i, j in self.mut.items():
self[i].config(**next(j))
class JournalWiew(deque):
def __init__(self):
super().__init__(self, maxlen=10)
self.extend([None] * 10)
self.__name__ = 'Journal'
def __call__(self):
t = [(f'{a} : {b} : ', f'lasts[{c}]', ) for a, b, c in zip(self, lasts, range(-10, 0))]
t, theta = list(zip(*t))
e = [''] * 10
t = list(chain.from_iterable(zip(t, e)))
alpha = Toplevel(m)
alpha.title('Journal')
alpha.geometry('250x300')
t = '\n'.join(t)
fi = TkMatrix(alpha, -100, 0)
beta = Label(alpha, text=t, justify=LEFT, font='Arial 9')
beta.place(relx=0, rely=0)
"""fi[2, 0].tkinsert(text=theta[0], command=lambda: Enter(string=theta[0]),width=10)
fi[2, 1].tkinsert(text=theta[1], command=lambda: Enter(string=theta[1]),width=10)
fi[2, 2].tkinsert(text=theta[2], command=lambda: Enter(string=theta[2]),width=10)
fi[2, 3].tkinsert(text=theta[3], command=lambda: Enter(string=theta[3]), width=10)
fi[2, 4].tkinsert(text=theta[4], command=lambda: Enter(string=theta[4]), width=10)
fi[2, 5].tkinsert(text=theta[5], command=lambda: Enter(string=theta[5]), width=10)
fi[2, 6].tkinsert(text=theta[6], command=lambda: Enter(string=theta[6]), width=10)
fi[2, 7].tkinsert(text=theta[7], command=lambda: Enter(string=theta[7]), width=10)
fi[2, 8].tkinsert(text=theta[8], command=lambda: Enter(string=theta[8]), width=10)
fi[2, 9].tkinsert(text=theta[9], command=lambda: Enter(string=theta[9]), width=10)"""
for i, j in enumerate(theta):
a, b = i, f'Enter(string={j})'
fi[2, i].tkinsert(text=j, command=lambda: Enter(string=j), width=10)
print(a, b)
Journal = JournalWiew()
def binpow(a, b):
p = 1
while b != 0:
if b % 2 == 0:
a *= a
b //= 2
else:
p*= a
b-= 1
return p
def dict_power(n, q):
e = n
for i in e.keys():
e[i] *= q
return Factorisation(e, k=(e.k[0], e.k[1] * q))
class Factorization(Counter):
def __init__(self, n, k=None):
if isinstance(n, dict):
if not all(map(lambda x: isinstance(x, int), n.keys())): raise FactorizationError('Arg must be Factorization or int !=0')
self.update(n)
d = reduce(gcd, self.values()) if n else 1
self.k = self.root(d) + (d,) if k is None else k
else:
if not n: raise FactorizationError('Arg must be Factorization or int != 0')
r = n
d = 2
w = []
if n < 0:
w.append(-1)
n = n // -1
while d * d <= n:
if n % d == 0:
n //= d
w.append(d)
else:
d += 1
if n != 1:
w.append(n)
self.update(Counter(w))
d = reduce(gcd, self.values()) if n else 1
self.k = self.root(d) + (d,)
__add__ = lambda self, other: Factorization(self.n + other.n) if isinstance(other, Factorization) else Factorization(self.n + other)
__sub__ = lambda self, other: Factorization(self.n - other.n) if isinstance(other, Factorization) else Factorization(self.n - other)
__mul__ = lambda self, other: Factorization(Counter.__add__(self, other)) if isinstance(other, Factorization) else Factorization(self.n * other)
__truediv__ = lambda self, other: Factorization(Counter.__sub__(self, other)) if isinstance(other, Factorization) else Factorization(self.n // other)
__and__ = lambda self, other: Factorization(Counter.__and__(self, other))
__or__ = lambda self, other: Factorization(Counter.__or__(self, other))
__str__ = lambda self: F'Fctn({self.k[0]} ** {self.k[1]})'
__pow__ = lambda self, other: dict_power(self, other.n) if isinstance(other, Factorization) else dict_power(self, other)
__abs__ = lambda self: reduce(lambda x, y: x * y, self.keys())
@property
def n(self):return binpow(self.k[0], self.k[1])
@property
def divisors(self):
t, n = set(), self.n
p = int(sqrt(n))
for i in range(1, p + 1):
if n % i == 0:
t.add(i)
t.add(n // i)
return sorted(t)
def ndivs(self, n):
a = self.elements()
p = permutations(a, n)
return sorted(set(p))
def AG(self, *args, tofloat=False):
'''Average Geomethric'''
if not all(map(lambda x: isinstance(x, Factorization) or isinstance(x, int), args)): raise FactorizationError('All args must be Factorization or int')
q = self
for i in args:
q = q * i
w = len(args) + 1
return q.root(w, tofloat)
def numpow(self, key):
'''Maximal pow of key what is divisor of self.n'''
if key in self:
return self[key]
elif key in self.divisors:
a = Factorization(key)
b = a.keys()
s = set()
for i in b:
s.add(self[i] // a[i])
return min(s)
else:
return 0
def root(self, n, tofloat=False):
''' root of n pow of self'''
a, b = 1, 1
for i, j in self.items():
a *= i ** (j // n)
b *= i ** (j % n)
return ((a, (b, n)) if b > 1 else (a,)) if not tofloat else f'{a} * {b ** (1/n)}'
@property
def sumnum(self):return (sum(self.divisors), len(self.divisors))
sqrt = partialmethod(root, n=2)
cbrt = partialmethod(root, n=3)
def fromto(a, r):
if a != int(a): raise FloatError('Float converted to not 10 base')
a = int(a)
s = []
alphabet = ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z')
w = a >= 0
a = abs(a)
while a >= 1:
s.insert(0, alphabet[a % r])
a //= r
return '-' * -w + ''.join(s)
Fctn = Factorization
def main():
try:
a = r.get()
if a == '': return 1
r.delete(0, END)
q = a
a = a.replace('<', 'int(\'').replace('_', '\', ').replace('>', ')')
p = eval(a)
except Exception as w:
she(type(w).__name__, str(w))
else:
lasts.append(p)
Journal.append(q)
r.insert(END, p)
m = Tk()
Calc = TkMatrix(m, 100, 200)
m.title('Calculator')
m.geometry('600x400')
m.resizable(False, False)
lbl = Label(m,
text=""" Калькулятор имеющий функции перевода в разные системы счисления
Использует встроенные функции, бибилиотеки math, random
Также используется функция fromto(someint1, someint2),
Переводящая из десятичной с систему счисления с показателем someint2.
Fromto НЕ переводит числа типа float
Числа в недесятичной системе счисления записываются: <someint_base>
Причем число и показатель отделяются _.
Есть возможность рассмотрения факторизации числа, его делителей.
Вывод производится в строку ввода""")
lbl.grid(row=0, column=0)
Calc[-5, 1].tkinsert(text='Journal', command= lambda: Journal(), width=10)
x, y = Calc[-5, 1].coords
x1, y1 = Calc.null_x + 30 * x, Calc.null_y + 30 * y
lbl2 = Label(text='''Аргументы функций \nразделяются запятой.\nПри записи дробных чисел \nиспользуется точка.''', justify=LEFT, font='Times_new_roman 10')
lbl2.place(x=(x1-50), y=(y1+30))
r = Entry(m, bg='white', width=27)
r.place(x=(x1-50), y=(y1 - 30))
Enter = partial(r.insert, index=END)
Calc[0, 0].tkinsert(text=1, command=lambda: Enter(string=1))
Calc[1, 0].tkinsert(text=2, command=lambda: Enter(string=2))
Calc[2, 0].tkinsert(text=3, command=lambda: Enter(string=3))
Calc[3, 0].tkinsert(text='+', command=lambda: Enter(string='+'))
Calc[4, 0].tkinsert(text='.', command=lambda: Enter(string='.'))
Calc[5, 0].tkinsert(text='Backspace', command=lambda: r.delete(len(r.get())-1, END), width=10)
Calc[235/30, 0].tkinsert(text='j', command=lambda: Enter(string='j'))
Calc[0, 1].tkinsert(text=4, command=lambda: Enter(string=4))
Calc[1, 1].tkinsert(text=5, command=lambda: Enter(string=5))
Calc[2, 1].tkinsert(text=6, command=lambda: Enter(string=6))
Calc[3, 1].tkinsert(text='-', command=lambda: Enter(string='-'))
Calc[4, 1].tkinsert(text='sin', command=lambda: Enter(string='sin'))
Calc[5, 1].tkinsert(text='Delete all', command=lambda: r.delete(0, END), width=10)
Calc[235/30, 1].tkinsert(text='_', command=lambda: Enter(string='_'))
Calc[0, 2].tkinsert(text=7, command=lambda: Enter(string=7))
Calc[1, 2].tkinsert(text=8, command=lambda: Enter(string=8))
Calc[2, 2].tkinsert(text=9, command=lambda: Enter(string=9))
Calc[3, 2].tkinsert(text='*', command=lambda: Enter(string='*'))
Calc[4, 2].tkinsert(text='cos', command=lambda: Enter(string='cos'))
Calc[5, 2].tkinsert(text='Engineer mode', command=lambda: Calc.transform(), width=10)
Calc[235/30, 2].tkinsert(text='ft', command=lambda: Enter(string='fromto'))
Calc[0, 3].tkinsert(text=0, command=lambda: Enter(string=0))
Calc[1, 3].tkinsert(text='|x|', command=lambda: Enter(string='abs'))
Calc[2, 3].tkinsert(text='x^y', command=lambda: Enter(string='**'))
Calc[3, 3].tkinsert(text='/', command=lambda: Enter(string='/'))
Calc[4, 3].tkinsert(text='tg', command=lambda: Enter(string='tg'))
Calc[5, 3].tkinsert(text='round', command=lambda: Enter(string='round'), width=10)
Calc[235/30, 3].tkinsert(text='<', command=lambda: Enter(string='<'))
Calc[0, 4].tkinsert(text='//', command=lambda: Enter(string='//'))
Calc[1, 4].tkinsert(text='%', command=lambda: Enter(string='%'))
Calc[2, 4].tkinsert(text='(', command=lambda: Enter(string='('))
Calc[3, 4].tkinsert(text=',', command=lambda: Enter(string=','))
Calc[4, 4].tkinsert(text=')', command=lambda: Enter(string=')'))
Calc[5, 4].tkinsert(text='=', command=main, width=10)
Calc[235/30, 4].tkinsert(text='>', command=lambda: Enter(string='>'))
Calc[-5, 1].tkinsert(text='Journal', command= lambda: Journal(), width=10)
Calc.mutable((3, 0), w(('sqrt',) * 2, ('Fctn',) * 2, ('+',) * 2))
Calc.mutable((3, 1), w(('log',) * 2, ('&',) * 2, ('-',) * 2))
Calc.mutable((3, 2), w(('pi',) * 2, ('|',) * 2, ('*',) * 2))
Calc.mutable((3, 3), w(('e',) * 2, ('.root',) * 2, ('/',) * 2))
Calc.mutable((2, 3), w(['n!', 'factorial'],['M^', '.numpow' ], ['x^y', '**']))
Calc.mutable((0, 4), w(['gcd'] * 2, ['.AG'] * 2, ['//'] * 2))
Calc.mutable((1, 4), w(['e^x', 'exp'], ['.num', '.n'], ['%'] * 2))
Calc.mutable((235/30, 3), w(['<'] * 2, ['['] * 2, ['<'] * 2))
Calc.mutable((235/30, 4), w(['>'] * 2, [']'] * 2, ['>'] * 2))
Calc.mutable((5, 2), cyc)
m.mainloop()
Проблемы есть в методе JournalWiew.call Закомментирован работающий вариант.