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

为Tkinter中DiscardFrame添加垂直滚动功能的实现方案

Tkinter Scrollbar for DiscardFrame in Canasta Game GUI Not Working

I'm developing a Canasta game GUI using Tkinter with the following requirements:

  • When a card button in MeldFrame is clicked, the card should be added to DiscardFrame.
  • When there are too many cards in DiscardFrame, a scrollbar should allow viewing all content.

I tried implementing this with canvas2 and scrollBar2, but the scrollbar isn't working as expected. Here's a simplified version of my code:

import tkinter as tk
from tkinter import ttk

class CanastaGUI(tk.Tk):
    def __init__(self):
        super().__init__()
        self.title("Canasta Game")
        
        # Meld Frame
        self.meld_frame = ttk.LabelFrame(self, text="Meld")
        self.meld_frame.pack(side=tk.LEFT, padx=10, pady=10, fill=tk.Y)
        
        # Sample cards in MeldFrame
        for i in range(10):
            card_btn = ttk.Button(self.meld_frame, text=f"Card {i}", command=lambda idx=i: self.add_to_discard(idx))
            card_btn.pack(pady=2)
        
        # Discard Frame with attempted scrollbar
        self.discard_container = ttk.LabelFrame(self, text="Discard Pile")
        self.discard_container.pack(side=tk.RIGHT, padx=10, pady=10, fill=tk.BOTH, expand=True)
        
        self.scrollBar2 = ttk.Scrollbar(self.discard_container, orient=tk.VERTICAL)
        self.scrollBar2.pack(side=tk.RIGHT, fill=tk.Y)
        
        self.canvas2 = tk.Canvas(self.discard_container, yscrollcommand=self.scrollBar2.set)
        self.canvas2.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        
        self.discard_frame = ttk.Frame(self.canvas2)
        self.canvas2.create_window((0,0), window=self.discard_frame, anchor=tk.NW)
        
        self.scrollBar2.config(command=self.canvas2.yview)
        
    def add_to_discard(self, card_idx):
        card_btn = ttk.Button(self.discard_frame, text=f"Card {card_idx}")
        card_btn.pack(pady=2)
        # Missing scroll region update here

if __name__ == "__main__":
    app = CanastaGUI()
    app.mainloop()

The issue is that when I add more cards than fit in the DiscardFrame, the scrollbar doesn't activate, and I can't scroll to see the hidden cards.


Solution

The core problem is that the canvas doesn't update its scroll region when the inner discard_frame grows as new cards are added. Here's the fixed code with key improvements:

import tkinter as tk
from tkinter import ttk

class CanastaGUI(tk.Tk):
    def __init__(self):
        super().__init__()
        self.title("Canasta Game")
        
        # Meld Frame
        self.meld_frame = ttk.LabelFrame(self, text="Meld")
        self.meld_frame.pack(side=tk.LEFT, padx=10, pady=10, fill=tk.Y)
        
        # Sample cards in MeldFrame
        for i in range(20):
            card_btn = ttk.Button(self.meld_frame, text=f"Card {i}", command=lambda idx=i: self.add_to_discard(idx))
            card_btn.pack(pady=2)
        
        # Discard Frame with working scrollbar
        self.discard_container = ttk.LabelFrame(self, text="Discard Pile")
        self.discard_container.pack(side=tk.RIGHT, padx=10, pady=10, fill=tk.BOTH, expand=True)
        
        self.scrollBar2 = ttk.Scrollbar(self.discard_container, orient=tk.VERTICAL)
        self.scrollBar2.pack(side=tk.RIGHT, fill=tk.Y)
        
        self.canvas2 = tk.Canvas(self.discard_container, yscrollcommand=self.scrollBar2.set)
        self.canvas2.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        
        self.discard_frame = ttk.Frame(self.canvas2)
        self.canvas2.create_window((0,0), window=self.discard_frame, anchor=tk.NW)
        
        # Bind frame size changes to update canvas scroll region
        self.discard_frame.bind("<Configure>", self.update_scroll_region)
        
        self.scrollBar2.config(command=self.canvas2.yview)
        
    def add_to_discard(self, card_idx):
        card_btn = ttk.Button(self.discard_frame, text=f"Card {card_idx}")
        card_btn.pack(pady=2)
        
    def update_scroll_region(self, event):
        # Update canvas to recognize full extent of inner frame content
        self.canvas2.configure(scrollregion=self.canvas2.bbox("all"))

if __name__ == "__main__":
    app = CanastaGUI()
    app.mainloop()

Key Fixes:

  1. Bind Frame Size Changes: Added a <Configure> event binding to the inner discard_frame that triggers whenever the frame's size updates (e.g., when new cards are added).
  2. Update Scroll Region: The update_scroll_region method sets the canvas's scrollregion to match the full bounding box of all content inside the canvas, making the scrollbar aware of all cards in the discard pile.
  3. Proper Container Resizing: Ensured the discard_container uses fill=tk.BOTH and expand=True to resize with the window, which keeps the scrollbar functional as the window changes size.

Now, when you add more cards than fit in the discard pile, the scrollbar will activate automatically, allowing you to scroll through all cards.

内容的提问来源于stack exchange,提问作者نظامی گنجوی

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 00:00:31