You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

customtkinter点击按钮报错TypeError: 'str' object is not callable

问题描述

测试customtkinter模块过程中,已经写完测试GUI界面、按钮点击后触发的蛋糕价格与尺寸计算逻辑,点击按钮时程序抛出异常,错误信息如下:

C:\Users\Jacek\Desktop>python test.py
Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Python\Python38-32\lib\tkinter\__init__.py", line 1883, in __call__
    return self.func(*args)
  File "C:\Python\Python38-32\lib\site-packages\customtkinter\widgets\ctk_button.py", line 390, in clicked
    self.function()
TypeError: 'str' object is not callable

报错栈指向customtkinter库内部源码,不属于自行编写的250行业务代码范围,排查所有变量类型未发现异常,完整测试代码如下:

import tkinter
import customtkinter

customtkinter.set_appearance_mode("dark")  # Modes: system (default), light, dark
customtkinter.set_default_color_theme("blue")  # Themes: blue (default), dark-blue, green

gui = customtkinter.CTk()  # create CTk window like you do with the Tk window
gui.geometry("520x420")
gui.title("Layer cake calculator")


# FRAMES CONFIGURATION

frame_left = customtkinter.CTkFrame(master=gui,
                                    width=180,
                                    corner_radius=0)
frame_left.grid(row=0, column=0, sticky="nswe")

frame_right = customtkinter.CTkFrame(master=gui,
                                     width=180,)
frame_right.grid(row=0, column=1, sticky="nswe", padx=20, pady=20)


# WELCOME label

welcome_label = customtkinter.CTkLabel(master=frame_left,
                                       text="Welcome to bday cake calculator!",
                                       text_font=("Arial", 12)).grid(row=1,
                                                                     column=0,
                                                                     pady=10,
                                                                     padx=10)


# HOW MANY PORTIONS entry

portion_label = customtkinter.CTkLabel(master=frame_left,
                                       text="How many portions?").grid(row=2,
                                                                       column=0,
                                                                       sticky="w")
portion_entry = customtkinter.CTkEntry(master=frame_left,
                                        width=100).grid(row=3,
                                                        column=0,
                                                        sticky="w",
                                                        padx=20,
                                                        pady=5)



# PRICE entry

price_label = customtkinter.CTkLabel(master=frame_left, text="Price per person?").grid(row=4,
                                                                                       column=0,
                                                                                       sticky="w")
price_entry = customtkinter.CTkEntry(master=frame_left,
                             width=100).grid(row=5, column=0, sticky="w", padx=20, pady=5)


# WHICH FORM label

form_label = customtkinter.CTkLabel(master=frame_left, text="Which form?").grid(row=6,
                                                                                column=0,
                                                                                sticky="w",
                                                                                pady=5)
form_combobox = customtkinter.CTkComboBox(master=frame_left,
                                     width=100,
                                     values=["Round", "Square", "Rectangle"]).grid(row=7,
                                                                                   column=0,
                                                                                   sticky="w",
                                                                                   pady=5,
                                                                                   padx=20)


# MORE INFO

more_info_label = customtkinter.CTkLabel(master=frame_left, text="More info:").grid(row=8,
                                                                                    column=0,
                                                                                    sticky="w",
                                                                                    pady=5)


# GLUTENFREE checkbox

gf = tkinter.BooleanVar()
gf_check = customtkinter.CTkCheckBox(master=frame_left,
                          variable=gf,
                          text="Gluten free?")
gf_check.deselect()
gf_check.grid(row=9, column=0, sticky="w", padx=20, pady=5)


# BOX INCLUDED checkbox

box = tkinter.BooleanVar()
box_check = customtkinter.CTkCheckBox(master=frame_left,
                           variable=box,
                           text="Box included?")
box_check.deselect()
box_check.grid(row=10, column=0, sticky="w", padx=20, pady=5)

# FUNCTIONS

def print_test():  # TEST FUNCTION
    print(portion_entry.get())
    print(price_entry.get())
    print(form_combobox.get())              ####ACTIVE
    print(gf.get())
    print(box.get())


def price_calculator():  # Price for the cake
    portion = int(portion_entry.get())
    price_per_person = int(price_entry.get())
    price_calc = portion * price_per_person

    if gf.get():
        price_calc += (portion * 2)

    if box.get():
        box_price = 0
        if portion <= 20:
            box_price = 7  # TODO sprawdzić ceny opakowań
        elif portion <= 30:
            box_price = 10
        elif portion <= 40:
            box_price = 15
        elif portion > 40:
            box_price = 20
        price_calc += box_price

    print("Prize for cake: ", price_calc, " zł")
    if box.get():
        print("That includes box price -", box_price, " zł")

    # if gf.get():
    #     print("And gf bonus: ", gf_bonus, " zł")


def round_calc():  # Round cake size calculator
    portion = int(portion_entry.get())
    pi = round(math.pi, 2)
    one_piece = 22.8

    def circle_field_calc(portion):
        circle_field = portion * one_piece
        return circle_field

    def d_calc(portion, circle_field):
        d = 2 * math.sqrt(circle_field / pi)
        d = round(d)
        return [d, circle_field]

    if portion < 31:  # cake with one layer
        print("Diameter size in cm = ", d_calc(portion, circle_field_calc(portion))[0])
    elif 31 <= portion <= 50:  # cake with two layers
        first_layer = d_calc(portion, circle_field_calc(portion))[1] * 0.65  # 65 % of cake field is first layer field
        second_layer = d_calc(portion, circle_field_calc(portion))[1] * 0.35  # 35 % of cake field is second layer field
        first_d = d_calc(portion, first_layer)[0]  # calculating d in first layer
        second_d = d_calc(portion, second_layer)[0]  # calculating d in second layer
        print("Diameter size of first layer = ", first_d, "cm,\n",
              "\t\t\t\tand second layer =", second_d, "cm.")
    elif 51 <= portion <= 75:  # cake with three layers
        first_layer = d_calc(portion, circle_field_calc(portion))[1] * 0.465
        second_layer = d_calc(portion, circle_field_calc(portion))[1] * 0.32
        third_layer = d_calc(portion, circle_field_calc(portion))[1] * 0.24
        first_d = d_calc(portion, first_layer)[0]
        second_d = d_calc(portion, second_layer)[0]
        third_d = d_calc(portion, third_layer)[0]
        print("Diameter size of first layer = ", first_d, "cm,\n",
              "\t\t\t\tsecond layer =", second_d, "cm,\n",
              "\t\t\t\tand third layer =", third_d, "cm.")



def one_portion_field(side):
    one_portion_field = side ** 2
    return one_portion_field


def square_calc():
    portion = int(portion_entry.get())
    square_cake_size = one_portion_field(6) * portion

    if portion <= 30:
        cake_side = math.sqrt(square_cake_size)
        print("Side of square cake: ", round(cake_side), " cm")
    elif 31 < portion <= 50:
        square_1 = square_cake_size * 0.65
        square_2 = square_cake_size * 0.35
        cake_side_1 = round(math.sqrt(square_1))
        cake_side_2 = round(math.sqrt(square_2))
        print("Side of first layer: ", round(cake_side_1), "cm,\n",
              "\tand second layer: ", round(cake_side_2), "cm,\n")
    elif 51 <= portion <= 75:
        square_1 = square_cake_size * 0.46
        square_2 = square_cake_size * 0.32
        square_3 = square_cake_size * 0.24
        cake_side_1 = round(math.sqrt(square_1))
        cake_side_2 = round(math.sqrt(square_2))
        cake_side_3 = round(math.sqrt(square_3))
        print("Side of first layer: ", round(cake_side_1), "cm,\n",
              "\tsecond layer: ", round(cake_side_2), "cm,\n",
              "\tand third layer: ", round(cake_side_3), "cm,\n")



def rectangle_calc():
    portion = int(portion_entry.get())
    one_portion_field(6)
    cake_size = one_portion_field(6) * portion
    cake_side_a = round(math.sqrt(cake_size / 0.7))
    cake_side_b = round(cake_side_a - 0.3 * cake_side_a)

    if portion > 25:
        layer_1 = cake_size * 0.65
        layer_2 = cake_size * 0.35
        cake_side_a_1 = round(math.sqrt(layer_1 / 0.7))
        cake_side_b_1 = round(cake_side_a_1 - 0.3 * cake_side_a_1)
        cake_side_a_2 = round(math.sqrt(layer_2 / 0.7))
        cake_side_b_2 = round(cake_side_a_2 - 0.3 * cake_side_a_2)
        print("Sides of first layer: ", round(cake_side_a_1), " cm X ", round(cake_side_b_1), "cm,\n",
              "\t\tand second layer: ", round(cake_side_a_2), " cm X ", round(cake_side_b_2), "cm,\n")
    elif portion > 45:
        layer_1 = cake_size * 0.46
        layer_2 = cake_size * 0.32
        layer_3 = cake_size * 0.24
        cake_side_a_1 = round(math.sqrt(layer_1 / 0.7))
        cake_side_b_1 = round(cake_side_a_1 - 0.3 * cake_side_a_1)
        cake_side_a_2 = round(math.sqrt(layer_2 / 0.7))
        cake_side_b_2 = round(cake_side_a_2 - 0.3 * cake_side_a_2)
        cake_side_a_3 = round(math.sqrt(layer_3 / 0.7))
        cake_side_b_3 = round(cake_side_a_3 - 0.3 * cake_side_a_3)
        print("Sides of first layer: ", round(cake_side_a_1), " cm X ", round(cake_side_b_1), "cm,\n",
              "\t\tsecond layer: ", round(cake_side_a_2), " cm X ", round(cake_side_b_2), "cm,\n",
              "\t\tthird layer: ", round(cake_side_a_3), " cm X ", round(cake_side_b_3), "cm,\n")


def button_func():
    price_calculator()
    if form_combobox.get("active") == "Round":
        round_calc()
    elif form_combobox.get("active") == "Square":
        square_calc()
    elif form_combobox.get("active") == "Rectangle":
        rectangle_calc()


# BUTTON

button = customtkinter.CTkButton(master=frame_left, text="Enter", command="print_test").grid(row=11, column=0, padx=20, pady=15)

gui.mainloop()
#python test.py
解决方案

代码里存在多个会触发报错的问题,逐个修复即可:

  • 当前直接触发TypeError的根因:按钮的command参数传入了字符串"print_test",而customtkinter/tkinter要求这个参数传入可调用的函数对象,不能加引号把函数名变成字符串。另外已经写了整合所有计算逻辑的button_func,直接传这个函数即可,不要加括号、不要加引号。
    # 错误写法
    button = customtkinter.CTkButton(master=frame_left, text="Enter", command="print_test").grid(row=11, column=0, padx=20, pady=15)
    # 修正后
    button = customtkinter.CTkButton(master=frame_left, text="Enter", command=button_func)
    button.grid(row=11, column=0, padx=20, pady=15)
    
  • 控件赋值写法错误:所有Label、Entry、ComboBox控件都是直接在实例化后链式调用.grid(),这种写法会让变量保存的是grid()的返回值None,后续调用.get()方法时会直接报NoneType has no attribute get。所有控件要先实例化赋值给变量,再单独调用布局方法,以输入框为例:
    # 错误写法
    portion_entry = customtkinter.CTkEntry(master=frame_left, width=100).grid(row=3, column=0, sticky="w", padx=20, pady=5)
    # 修正后
    portion_entry = customtkinter.CTkEntry(master=frame_left, width=100)
    portion_entry.grid(row=3, column=0, sticky="w", padx=20, pady=5)
    
    welcome_label、portion_label、price_label、price_entry、form_label、form_combobox、more_info_label全部要按这个规则修改。
  • 缺少模块导入:计算逻辑里大量使用math.pi、math.sqrt,代码开头没有导入math模块,运行计算会触发NameError,在导入部分加上import math即可。
  • 下拉框取值方法错误:button_func和print_test里写的form_combobox.get("active")是tkinter原生Listbox的写法,customtkinter的CTkComboBox直接调用无参数的.get()就能拿到当前选中值,把所有form_combobox.get("active")改成form_combobox.get()。
  • 矩形蛋糕计算的判断顺序错误:rectangle_calc()里先判断portion > 25,后面的portion >45分支永远不会触发(大于45的数必然满足大于25的条件),把判断顺序调换,先判断数值更大的区间:
    # 修正后的判断顺序
    if portion > 45:
        # 三层蛋糕计算逻辑
    elif portion > 25:
        # 两层蛋糕计算逻辑
    

所有问题修复后程序即可正常运行。

内容的提问来源于stack exchange,提问作者olenka

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 20:24:29