使用Kivy在Python中传递事件

0 投票
2 回答
998 浏览
提问于 2025-04-18 11:18

我刚开始学习Python和Kivy,想在按下任何按钮时清除一个容器里的所有小部件,我的代码如下:

from kivy.uix.button import Button
from kivy.uix.gridlayout import GridLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.popup import Popup
from kivy.uix.label import Label

spots={}

class spot(Button):
    '''
    classdocs
    '''
    def __init__(self, **kwargs):
        '''
        Constructor
        '''
        super(spot,self).__init__(**kwargs)
        self.ismine=False
        if 'text' in kwargs:
            self.text=kwargs['text']
        else:
            self.text="X"

    def on_press(self, *args, **kwargs):
        #return Button.on_press(self, *args, **kwargs)
        game.spottouched(self, self.text)

class game(BoxLayout):
    def __init__(self,**kwargs):
        super(game,self).__init__(**kwargs)
        self.m=minesholder(rows=25, cols=25)
        self.add_widget(self.m)
        self.attachtogrid()

    def attachtogrid(self):
        self.m.clear_widgets()
        spots.clear()
        for r in range(0,25):
            for c in range(0,25):
                idd=str(r)+","+str(c)
                spots[idd]=idd
                self.m.add_widget(spot(text=idd))

    def spottouched(self,spotid):
        #popup=Popup(title=spotid)
        #popup.open()
        self.clear_widgets()

最后一行是用来清除小部件的,spot类有一个on_press事件。我想把按钮的on_press事件传递给一个包含的boxlayout(游戏类),你能告诉我或者指引我一下,怎么把这些事件传递过去吗?

谢谢你。

2 个回答

1

game.spottouched(self, self.text)

你可能对Python的类有些误解。你需要清除的是你实际使用的那个游戏实例中的小部件,也就是你通过写game()创建的那个实例。你需要用这个实例的引用,调用instance.spottouched(spotid)来执行那个实例的方法。

而你现在做的是通过类的定义来调用这个方法,这样做其实没有意义,你也不应该这样做。实际上,你基本上永远不应该这样做。

无论如何,修复这个问题的方法取决于你是如何构建你的应用的,但归根结底,你需要在某个地方保留对游戏实例的引用,这样点位实例才能看到它。最佳的方法取决于你代码的其他部分,但你总是可以通过应用类来实现,比如:

App.get_running_app().game = game()

然后在后面

App.get_running_app().game.spottouched(self.text)

这只是一个例子,有时候这样做可能并不好。

另外,记得用大写字母开头命名你的部件!kv语言用这个来识别它们,如果你不这样命名,会遇到问题。这也是Python中的一个重要约定,值得遵循。

1

我觉得根据你对@inclement回答的评论,这正是你想要的:把按钮上的on_press方法去掉。你应该绑定到事件上,这样做会更像WPF。

for r in range(0,25):
    for c in range(0,25):
        idd=str(r)+","+str(c)
        spots[idd]=idd
        s = spot(text=idd)
        self.m.add_widget(s)

        s.bind(on_press=self.spottouched)

所以self.spottouched就像是处理spoton_press事件的一个事件处理器。

s.bind(on_press=self.spottouched)

大概是这样的:

AddHandler s.Click, AddressOf spottouched

注意,以这种方式添加处理器时,处理器会接收到一个参数,就是spot的实例。你可以从这个实例中获取spot.text

撰写回答