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

Tkinter按钮Y轴≥200时不显示的Bug修复请求

问题描述

开发基于Tkinter的Osu!风格程序时遇到Bug:当按钮Y轴坐标设置为200或更高时,按钮无法在屏幕上显示。推测可能和标题界面的放大标题有关,按钮无法显示在标题下方区域。

程序运行说明:

  • 启动程序进入标题界面,点击“Start”切换到游戏界面;
  • 游戏界面应随机生成带数字的彩色按钮,点击按钮会生成新的随机按钮;
  • 按钮不显示的情况随机出现,多次运行才可能正常显示。

用户代码如下:

from tkinter import *
import random

global counter
counter = -1

global color_counter
color_counter = -1

win = Tk()

Titlescreen = Frame(win)
Gamescreen = Frame(win)
Deathscreen = Frame(win)

# Page 1

H1 = Label(Titlescreen, text="Osu!", font=('Helvatical bold',100))
H1.grid(row=0, column=1)

btn1 = Button(Titlescreen, text='Start', command=lambda:Gamescreen.tkraise())
btn1.grid(row=1, column=1)

#Page 2

class rectangle():
   def __init__(self, location, number, row, column, color):
       self.location = location
       self.number = number
       self.row = row
       self.column = column
       self.color = color



 #write under here the parameters for rectangle


 numbers = ['1','2','3','4','5','6','7','8','9']

 x= list(range(20, 380))


 y= list(range(20, 380)) 

 colors = ['red','blue','green','yellow','purple','orange','pink']

 


 def click():
     circle_button.grid_forget()
     circle()


 global circle
 def circle():
     global counter
     global color_counter
     counter += 1
     if counter == 9:
         counter = 0
         color_counter += 1

     user = rectangle(Gamescreen, numbers[counter], random.choice(x), random.choice(y), 
     colors[color_counter])
     print(random.choice(x))
     print(random.choice(y))
     global circle_button
     circle_button = Button(user.location,text=user.number, bg=user.color, command=click)


     circle_button.place(x=random.choice(x),y=random.choice(y), anchor = CENTER)
  circle()


  #Page 3

  Lb1 = Label(Deathscreen, text='GAME OVER', font=('Helvatical bold',50))
  Lb1.grid(row=0,column=1)

  btn3 = Button(Deathscreen, text='Retry', command=lambda:Gamescreen.tkraise())
  btn3.grid(row=1, column=1)

  btn4 = Button(Deathscreen, text='Exit', command=lambda:Titlescreen.tkraise())
  btn4.grid(row=2, column=1)

  Titlescreen.grid(row=0, column=0, sticky='nsew')
  Gamescreen.grid(row=0, column=0, sticky='nsew')
  Deathscreen.grid(row=0, column=0, sticky='nsew')


  Titlescreen.tkraise()
  win.geometry('400x400')
  win.title('Control panel')
  win.resizable(False, False)


  win.mainloop()
问题分析与修复方案

核心问题

  1. Frame未适配窗口尺寸:三个Frame虽然设置了sticky='nsew',但主窗口未配置网格权重,导致Frame无法自动填充整个400x400窗口。Gamescreen的初始尺寸过小,Y坐标200以上的按钮会被裁剪。
  2. 重复生成随机坐标:circle()函数中两次调用random.choice()生成坐标,导致打印的坐标和按钮实际位置不一致,增加调试难度。
  3. 索引逻辑错误:color_counter初始值为-1,第一次调用colors[color_counter]虽不会报错(Python允许负索引),但不符合从第一个颜色开始的逻辑;且未处理颜色索引超出列表长度的情况。
  4. 布局方法不匹配:按钮用place()布局,click()中却调用grid_forget(),无法正确移除旧按钮。

修复代码

from tkinter import *
import random

counter = -1
color_counter = 0  # 修正初始值,从第一个颜色开始

win = Tk()

# 配置主窗口网格权重,让Frame填充整个窗口
win.grid_rowconfigure(0, weight=1)
win.grid_columnconfigure(0, weight=1)

Titlescreen = Frame(win)
Gamescreen = Frame(win)
Deathscreen = Frame(win)

# 给每个Frame配置内部网格权重,确保内容自适应
for frame in [Titlescreen, Gamescreen, Deathscreen]:
    frame.grid_rowconfigure(0, weight=1)
    frame.grid_columnconfigure(0, weight=1)

# Page 1
H1 = Label(Titlescreen, text="Osu!", font=('Helvetica bold', 100))
H1.grid(row=0, column=1)

btn1 = Button(Titlescreen, text='Start', command=lambda: Gamescreen.tkraise())
btn1.grid(row=1, column=1)

# Page 2
class rectangle():
    def __init__(self, location, number, x, y, color):
        self.location = location
        self.number = number
        self.x = x
        self.y = y
        self.color = color

numbers = ['1','2','3','4','5','6','7','8','9']
x_range = list(range(20, 380))
y_range = list(range(20, 380))
colors = ['red','blue','green','yellow','purple','orange','pink']

circle_button = None  # 初始化全局按钮变量

def click():
    global circle_button
    if circle_button:
        circle_button.destroy()  # 销毁旧按钮,避免布局残留
    circle()

def circle():
    global counter, color_counter, circle_button
    counter += 1
    if counter == len(numbers):
        counter = 0
        color_counter += 1
        # 颜色索引超出范围时重置
        if color_counter == len(colors):
            color_counter = 0

    # 只生成一次随机坐标,保证打印值和实际位置一致
    rand_x = random.choice(x_range)
    rand_y = random.choice(y_range)
    user = rectangle(Gamescreen, numbers[counter], rand_x, rand_y, colors[color_counter])
    print(f"X: {rand_x}, Y: {rand_y}")

    circle_button = Button(user.location, text=user.number, bg=user.color, command=click)
    circle_button.place(x=rand_x, y=rand_y, anchor=CENTER)

circle()

# Page 3
Lb1 = Label(Deathscreen, text='GAME OVER', font=('Helvetica bold',50))
Lb1.grid(row=0, column=1)

btn3 = Button(Deathscreen, text='Retry', command=lambda: Gamescreen.tkraise())
btn3.grid(row=1, column=1)

btn4 = Button(Deathscreen, text='Exit', command=lambda: Titlescreen.tkraise())
btn4.grid(row=2, column=1)

# 布局三个Frame
Titlescreen.grid(row=0, column=0, sticky='nsew')
Gamescreen.grid(row=0, column=0, sticky='nsew')
Deathscreen.grid(row=0, column=0, sticky='nsew')

Titlescreen.tkraise()
win.geometry('400x400')
win.title('Control panel')
win.resizable(False, False)

win.mainloop()

修复说明

  • 通过配置主窗口和Frame的网格权重,让Gamescreen完全填充400x400窗口,Y坐标200以上的按钮可正常显示;
  • 统一随机坐标生成逻辑,确保打印的坐标和按钮实际位置一致;
  • 修正color_counter的初始值和循环逻辑,避免索引异常;
  • 改用destroy()移除旧按钮,匹配place()布局的操作逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 14:34:54