【问题标题】:Tkinter: gridding canvas objects and buttons togetherTkinter:将画布对象和按钮网格化在一起
【发布时间】:2015-11-09 08:42:24
【问题描述】:

我想在一个框架中显示 9 张套牌。每张卡片下面都有自己的按钮。我正在使用 SetCard.deal_card(position) 方法将卡片放置在 Frame 中的 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()

【问题讨论】:

    标签: python button tkinter grid frame


    【解决方案1】:

    您的错误在于使选择按钮成为卡片而非画布的奴隶。
    将定义更改为

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

    你的代码就可以工作了。你所拥有的代码发生了什么,卡片在画布中被网格化,但按钮在卡片中被网格化,你看到的只是按钮。

    第一个参数(master)是 self 似乎很自然(至少对我来说),因为按钮是卡片的一个属性。但是,Tk(tkinter 底层的 GUI 工具包)中的小部件层次结构与此无关。这里的第一个参数并不意味着 self.PickButton 是面向对象意义上的 master 的子级,而是那个 master(画布小部件)正在管理 self-pickButton 的“几何”。

    顺便说一句,您的代码中存在语法错误。在第 30 行,“sunken”这个词应该有引号。

    【讨论】:

    • 我认为你的陈述“tkinter 不是面向对象的”是不正确的。 Tkinter 小部件确实是对象:您通过类定义它们,它们从超类继承属性,并且它们具有属性和方法。这使其高度面向对象。
    • 我没有说 tkinter,我说的是 Tk。 tkinter 是一个围绕 Tk 的面向对象的包装器,它本身不是面向对象的。
    • 啊,我明白了。我看不出这有什么关系,因为 tkinter 是面向对象的。父/子层次结构与它是否面向对象无关。我认为与此相关的 cmets 会让尝试学习如何使用 tkinter 的人感到困惑。
    • 嗯,这似乎让你感到困惑,但是当我学习 tkinter 时,我很困惑,因为对象层次结构与 OO 层次结构无关。在我看来,OP 也遇到了同样的问题,我正试图向他指出这一点。我会尝试将我的解释编辑得更明确,谢谢。
    猜你喜欢
    • 2017-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-11
    • 1970-01-01
    • 2014-04-28
    • 2018-11-05
    • 1970-01-01
    相关资源
    最近更新 更多