Tkinter:将 canvas 个对象和按钮网格化在一起

Tkinter: gridding canvas objects and buttons together

我想在一个框架中显示 9 套卡片。每张卡片下方都有自己的按钮。我正在使用 SetCard.deal_card(position) 方法将卡片放置在 3x3 网格中的框架中(位置 0-8)。当我 运行 程序时,只有按钮出现。当我注释掉 pickButton.grid() 方法时,卡片就会出现。我不知道为什么我只能拥有一个而不能同时拥有两个。

from tkinter import *
import random

class SetCard(Canvas):

    def __init__(self,master,number,color,shape,shading):
        # create a 60x60 white canvas with a 5-pixel grooved border
        Canvas.__init__(self,master,width=100,height=160,bg='white',\
                        bd=5,relief=RAISED) #also relief = SUNKEN
        # store the valuelist and colorlist
        self.number = number
        self.color = color
        self.shape = shape
        self.shading = shading
        self.selected=False
        self.pickButton=Button(self,text="Pick me!", command=self.toggle_card)

    def deal_card(self,position):
        '''puts the given card into a position on the 3x3 grid of the frame'''
        self.draw_card()
        print("row: ",(position//3)*2)
        print("col: ",position%3)
        self.grid(row=(position//3)*2,column=position%3)
        self.pickButton.grid(row=((position//3)*2)+1,column= position %3)
        self.master.deck.pop(0)

    def toggle_card(self):
        self.selected=True
        self['bg']='gray'
        self['relief']=sunken

    def draw_card(self):
        '''draws the pips in the correct locations on the card'''
        # clear old pips first
        self.erase()
        # location of which pips should be drawn
        if self.number == 1:
            self.draw_pip(position=2)
        if self.number == 2:
            self.draw_pip(position=1)
            self.draw_pip(position=3)
        if self.number == 3:
            self.draw_pip(position=1)
            self.draw_pip(position=2)
            self.draw_pip(position=3)

    def draw_pip(self,position):
        '''draws a single pip in the given location'''
        if self.shading=='solid':
            inside=self.color
        else:
            inside=''
        (topx,topy) = (55,10+ (position-1)*50)      
        if self.shape == 'diamond':
            self.create_polygon(topx, topy, topx+15, topy+20, topx, topy+40, topx-15, topy+20,\
                                outline=self.color,fill=inside,width=3)
            if self.shading=='stripe':
                incrementxy=[(5,30),(10,25), (15,20), (10,15), (5,10)]
                for xy in incrementxy:
                    self.create_line(topx-xy[0],topy+xy[1],topx+xy[0],topy+xy[1],fill=self.color)
        if self.shape == 'circle':
            self.create_oval(topx-20,topy,topx+20,topy+40,fill=inside,outline=self.color,width=3)
            if self.shading=='stripe':
                incrementxy=[(10,3),(14,7),(17,10),(19,14),(20,20),(18,24),(17,30),(14,33),(10,37)]
                for xy in incrementxy:
                    self.create_line(topx-xy[0],topy+xy[1],topx+xy[0],topy+xy[1], fill= self.color)
        if self.shape == 'square':
            self.create_polygon(topx-20,topy,topx+20,topy,topx+20,topy+40,topx-20,topy+40,fill=inside,outline=self.color,width=3)
            if self.shading=='stripe':
                for increment in range(5,40,5):
                    self.create_line(topx-20, topy+increment,topx+20,topy+increment, fill = self.color)


    def erase(self):
        '''erases all the pips'''
        pipList = self.find_all()
        for pip in pipList:
            self.delete(pip)

class SetGameFrame(Frame):
    '''frame for a game of Set'''

    def __init__(self,master):
        '''creates a new Set frame'''
        # set up Frame object
        Frame.__init__(self,master)
        self.grid()
        colorList=['red','green','magenta']
        shadingList=['solid','stripe','open']
        shapeList=['circle','diamond','square']
        self.dealt_cards=[]
        self.deck=[]
        for number in range(3):
            for color in colorList:
                for shading in shadingList:
                    for shape in shapeList:
                        self.deck.append(SetCard(self,number+1,color,shape,shading))
        random.shuffle(self.deck)
        for position in range(9):
            self.deck[0].deal_card(position)
            self.dealt_cards.append(self.deck[0])
        self.setButton=Button(self,text="SET!",command=self.pick_set)
        self.setButton.grid(row=6,column=1,rowspan=2)

    def pick_set(self):
        pass

def play_Set():
    root = Tk()
    root.title('Set Game')
    game = SetGameFrame(root)
    root.mainloop()

play_Set()

你的错误在于让选择按钮成为卡片的奴隶而不是 canvas。
将定义更改为

self.pickButton=Button(master,text="Pick me!", command=self.toggle_card)

您的代码将起作用。你所拥有的代码发生了什么,卡片在 canvas 中被网格化,但是按钮在卡片中被网格化,你所看到的只是按钮。

第一个参数 (master) 应该是 self 似乎很自然(至少对我而言),因为按钮是卡片的一个属性。但是,Tk(tkinter 下的 GUI 工具包)中的 widget 层次结构与此无关。这里的第一个参数并不意味着 self.PickButton 是 objected-oriented 意义上的 child master,而是那个 master(canvas 小部件)正在管理 self-pickButton的"geometry"。

顺便说一下,您的代码中存在语法错误。在第 30 行,单词 "sunken."

应该有引号