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

Python Tkinter图片按钮问题求助:不显示+点击无响应+状态切换

解决方案

问题1:图片不显示+点击无响应

核心原因是Tkinter的PhotoImage对象如果没有持久引用,会被Python垃圾回收机制销毁,函数式结构下局部变量生命周期短,进一步加剧了这个问题。你的command绑定逻辑本身没问题,主要问题出在图片引用丢失。

修复要点:

  • 创建按钮时,将图片对象绑定到按钮自身属性上,延长其生命周期。
  • 调整图片加载逻辑,避免临时变量被回收。

问题2:按钮双状态切换

Tkinter原生Button没有直接的activeimage属性,需要通过绑定鼠标按下/释放事件实现状态切换:

  • 提前加载正常状态和点击状态的两张图片。
  • 绑定<ButtonPress-1>事件切换为点击状态图片,<ButtonRelease-1>事件切换回正常状态图片,同时保留原有的点击逻辑。

修改后的完整代码

import pyodbc
import pandas as pd
import os
import tkinter as tk
from PIL import ImageTk


# DB connector
conn = pyodbc.connect('DRIVER={ODBC Driver 17 for SQL Server};'
                      'SERVER=onyx1905;'
                      'DATABASE=DW_15;'
                      'Trusted_Connection=yes')

# variables
name = os.getlogin()
cursor = conn.cursor()
running = True
bg_color_1 = "#205E61"
bg_button = "#1B4E51"
bg_button_ac = "#FFD966"

def clear_widgets(frame):
    for widget in frame.winfo_children():
        widget.destroy()

def load_frame_insert():
    print("Hi XYZ")

def load_main_frame():
    clear_widgets(frame_insert)
    frame_main.tkraise()
    frame_main.pack_propagate(False)

    # widget frame_main logo
    logo_image = ImageTk.PhotoImage(file="assets/xrdl_logo.png")
    logo_widget = tk.Label(frame_main, image=logo_image, bg=bg_color_1)
    logo_widget.image = logo_image
    logo_widget.pack()

    # label on 1st frame
    tk.Label(
        frame_main,
        text=(f"          Hi {name}, please choose an action        "),
        bg=bg_button,
        fg="white",
        font=("TkMenuFont", 12)
    ).pack(pady=10)

    # 加载按钮的两张状态图片
    img_normal = tk.PhotoImage(file="assets/insert_data.png").subsample(1, 1)
    img_clicked = tk.PhotoImage(file="assets/insert_data2.png").subsample(1, 1)

    # 定义图片切换函数
    def on_press(event):
        event.widget.config(image=img_clicked)
    
    def on_release(event):
        event.widget.config(image=img_normal)
        load_frame_insert()  # 释放时执行原点击逻辑

    # 创建按钮
    btn = tk.Button(
        frame_main,
        image=img_normal,
        bd=0,
        relief="groove",
        compound=tk.CENTER,
        bg=bg_color_1,
        fg="yellow",
        activeforeground="pink",
        activebackground=bg_color_1,
        font=("TkMenuFont", 12),
        cursor="hand2",
        text=""
    )
    # 保存图片引用,防止被垃圾回收
    btn.img_normal = img_normal
    btn.img_clicked = img_clicked
    # 绑定状态切换事件
    btn.bind("<ButtonPress-1>", on_press)
    btn.bind("<ButtonRelease-1>", on_release)
    btn.pack(pady=5)

# ini for app
main_app = tk.Tk()
main_app.title("SRD Loader")
main_app.eval("tk::PlaceWindow . center")

x = main_app.winfo_screenwidth() // 3
y = int(main_app.winfo_screenheight() * 0.1)
main_app.geometry('500x600+' + str(x) + '+' + str(y))

# frame look
frame_main = tk.Frame(main_app, width=500, height=600, bg=bg_color_1)
frame_insert = tk.Frame(main_app, width=500, height=600, bg=bg_color_1)

for frame in (frame_main, frame_insert):
    frame.grid(row=0, column=0)

load_main_frame()
main_app.mainloop()

conn.close()

关键修改说明

  1. 图片引用保存:将两张状态图片绑定到按钮对象的属性上,避免被Python垃圾回收机制销毁。
  2. 事件绑定实现状态切换:通过鼠标按下/释放事件切换图片,同时在释放时执行原有的load_frame_insert()逻辑,确保点击功能正常。
  3. 简化冗余代码:移除了无用的全局变量声明和独立图片加载函数,直接在按钮创建逻辑中处理图片,代码更简洁。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 21:46:07