【发布时间】:2020-08-05 03:24:27
【问题描述】:
我正在尝试为我的应用构建更复杂的 GUI。我正在尝试使用 .grid() 在框架内放置按钮。但是,每当我尝试创建一个以框架为根的按钮时,我都会收到"AttributeError: object has no attribute 'tk'"。我见过人们编写 GUI 类(即 class Frame(tk.Frame)),这给我的代码带来了更多问题。我应该如何创建按钮并将它们放置在框架内,而不必从头开始重写我的大部分类?
当我将一个按钮设置为“master”时,它工作正常。但是,如果它植根于“action_frame”,那就是我收到错误的时候。
计算器.py
# -*- coding: utf-8 -*-
import tkinter as tk
from math import *
from classes_GUI import ButtonBlock, LabelBlock, TextBlock, FrameBlock
from classes_calculator import ActionBlock
# Store input number
def storeInput(entry_text, result_text, action, array):
numb = 0.0
try:
numb = float(entry_text.retrieveTextInput())
except:
print('Please enter a valid number')
return
calc_action = ActionBlock(numb, action)
array.append(calc_action)
entry_text.clearText()
num = calc_action.returnNumber()
act = calc_action.returnAction()
input_texts = dict([
(1, ' + ' + str(num)),
(2, ' - ' + str(num)),
(3, ' * ' + str(num)),
(4, ' / ' + str(num)),
(5, ' + 1/' + str(num)),
(6, ' + ' + str(num) + '^2')
])
result_text.changeText(input_texts[act])
# Calculate result
def calcResult(entry_text, result_text, array):
result = 0.0
for calc in array:
action = calc.returnAction()
num = calc.returnNumber()
if action == 1:
result += num
elif action == 2:
result -= num
elif action == 3:
result *= num
elif action == 4:
result /= num
elif action == 5:
result += 1.0 / num
elif action == 6:
result += num ** 2
entry_text.clearText()
result_text.changeText(str(result), True)
# Create a new calculator instance
def exeCalc():
action_blocks = []
button_blocks = []
frame_blocks = []
label_blocks = []
text_blocks = []
# Create GUI
master = tk.Tk()
master.title('Calculator')
# Create frames
action_frame = FrameBlock(master, 30, 30, 1, 6)
frame_blocks.append(action_frame)
for f in frame_blocks:
f.createFrame()
# Create GUI labels
title_label = LabelBlock(master, 20, 2, 'n', 0, 0, 'center', 'Calculator')
label_blocks.append(title_label)
entry_label = LabelBlock(master, 20, 2, 'n', 1, 0, 'center', 'Enter:')
label_blocks.append(entry_label)
result_label = LabelBlock(master, 20, 2, 'n', 2, 0, 'center', 'Result:')
label_blocks.append(result_label)
for l in label_blocks:
l.createLabel()
# Create GUI text
entry_text = TextBlock(master, 20, 2, 1, 1, 'normal', '')
text_blocks.append(entry_text)
result_text = TextBlock(master, 20, 2, 2, 1, 'disabled', '0')
text_blocks.append(result_text)
for t in text_blocks:
t.createText()
# Create GUI buttons
close_button = ButtonBlock(master, 6, 2, 3, 0, 'Close',
lambda: master.destroy())
button_blocks.append(close_button)
add_button = ButtonBlock(frame_blocks[0], 4, 2, 0, 0, '+',
lambda: storeInput(text_blocks[0], text_blocks[1], 1, action_blocks))
button_blocks.append(add_button)
subtract_button = ButtonBlock(frame_blocks[0], 4, 2, 0, 1, '-',
lambda: storeInput(text_blocks[0], text_blocks[1], 2, action_blocks))
button_blocks.append(subtract_button)
multiply_button = ButtonBlock(frame_blocks[0], 4, 2, 0, 2, 'x',
lambda: storeInput(text_blocks[0], text_blocks[1], 3, action_blocks))
button_blocks.append(multiply_button)
divide_button = ButtonBlock(frame_blocks[0], 4, 2, 1, 0, '/',
lambda: storeInput(text_blocks[0], text_blocks[1], 4, action_blocks))
button_blocks.append(divide_button)
fraction_button = ButtonBlock(frame_blocks[0], 4, 2, 1, 1, '1/x',
lambda: storeInput(text_blocks[0], text_blocks[1], 5,
action_blocks))
button_blocks.append(fraction_button)
square_block = ButtonBlock(frame_blocks[0], 4, 2, 1, 2, 'x^2',
lambda: storeInput(text_blocks[0], text_blocks[1], 6,
action_blocks))
button_blocks.append(square_block)
equal_button = ButtonBlock(frame_blocks[0], 4, 2, 2, 0, '=',
lambda: calcResult(text_blocks[0], text_blocks[1], action_blocks))
button_blocks.append(equal_button)
for b in button_blocks:
b.createButton()
master.mainloop()
classes_GUI.py
# -*- coding: utf-8 -*-
import tkinter as tk
# Create a base data block
class BaseBlock():
def __init__(self, root, width, height, txt):
self.root = root
self.width = width
self.height = height
self.txt = txt
# Create a inner data block
class InnerBlock(BaseBlock):
def __init__(self, root, width, height, row, column, txt):
super().__init__(root, width, height, txt)
self.g_row = row
self.g_column = column
# Create a data block for a button
class ButtonBlock(InnerBlock):
def __init__(self, root, width, height, row, column, txt, command=None):
super().__init__(root, width, height, row, column, txt)
self.command = command
def createButton(self):
button = tk.Button(self.root, text=self.txt, width=self.width,
height=self.height, command=self.command)
button.grid(row=self.g_row, column=self.g_column)
return button
# Create a frame data block
class FrameBlock(InnerBlock):
def __init__(self, root, width, height, row, column, txt=None):
super().__init__(root, width, height, row, column, txt)
def createFrame(self):
frame = tk.Frame(self.root, width=self.width, height=self.height)
frame.grid(row=self.g_row, column=self.g_column)
return frame
# Create a data block for a window
class LabelBlock(InnerBlock):
def __init__(self, root, width, height, anchor, row, column, justify, txt):
super().__init__(root, width, height, row, column, txt)
self.anchor = anchor
self.justify = justify
def createLabel(self):
label = tk.Label(self.root, width=self.width, height=self.height,
anchor=self.anchor, justify=self.justify, text=self.txt)
label.grid(row=self.g_row, column=self.g_column)
return label
# Create a data block for text
class TextBlock(InnerBlock):
def __init__(self, root, width, height, row, column, state, txt):
super().__init__(root, width, height, row, column, txt)
self.state = state
self.text = None
def createText(self):
self.text = tk.Text(self.root, width=self.width, height=self.height)
self.text.insert(tk.END, self.txt)
self.text.grid(row=self.g_row, column=self.g_column)
self.text.config(state=self.state)
return self.text
# Clear text
def clearText(self):
self.text.delete('1.0', 'end')
# Change text
def changeText(self, new_txt, clear=False):
self.text.config(state='normal')
if clear:
self.clearText()
self.text.insert(tk.END, new_txt)
self.text.config(state='disabled')
# Retrieve input from text box
def retrieveTextInput(self):
text_input = self.text.get('1.0', 'end')
return text_input
【问题讨论】:
-
请包含回溯消息。
标签: python tkinter widget attributeerror