0

何かが起こる直前に、アプリケーションがボタンの on_press コマンドを実行しているという問題があります。レイアウトに .kv を使用すると問題なく動作しますが、単純なリストを使用してボタンを管理できるようにしたいと考えています。

class AppBase(Widget):

    def Launcher(self, launchapp):
        os.system(launchapp)

    def BuildLayout(self):
        layout = GridLayout( rows=4, row_force_default = True, row_default_height = 100, col_force_default = True, col_default_width = 300 )
        with open('config.txt', 'rb') as f:
            reader = csv.reader(f, delimiter="|")
            for row in reader:
                launchbutton = Button( text = row[0], background_normal = 'tile.png', on_press = self.Launcher(row[1]) )
                layout.add_widget(launchbutton)
        return layout


class MyApp(App):

    def build(self):
        Config.set('graphics', 'width', 1920)
        Config.set('graphics', 'height', 400)
        return AppBase().BuildLayout()

if __name__ == '__main__':
    MyApp().run()
4

2 に答える 2

4

コールバックを に渡しているのではなく、Button実際にその時点で関数を実行しています。これを変える:

launchbutton = Button( text = row[0], background_normal = 'tile.png', 
    on_press = self.Launcher(row[1]) 
)

これに:

launchbutton = Button( text = row[0], background_normal = 'tile.png', 
    on_press = lambda: self.Launcher(row[1])
)

が作成されたときの戻り結果に設定するのではなくself.Launcher、イベントが発生したときに呼び出される名前のない関数を渡しています。on_pressself.LauncherButton

更新:何らかの理由でon_presson_releaseイベントは のコールバックに実際に割り当てられていませんButton.__init__。イベント自体は登録されただけで結果はありません。(これは私にはバグのように思えますが、Kivy についてはっきりと言えるほど詳しくはありません。)bind動作させるには、コールバックを明示的に指定する必要があります。

launchbutton = Button( text = row[0], background_normal = 'tile.png' )
launchbutton.bind( on_press = lambda widget: self.Launcher( row[1] ) )

コールバックが実際に引数を受け取ることに注意してください。これwidgetは、ラムダに含めました。

更新 2:申し訳ありませんが、ローカル テスト ケースをボタン 1 つに減らしていました。これをループで行う場合:

funcs = []
for x in xrange(10):
    funcs.append( lambda: x)

funcs[n]()whereを呼び出すたびに が返されますが、期待どおりの値はn in [0..9]返されません。ラムダは、周囲のスコープからインクルードするクロージャーを作成しました。ただし、その値はループの過程で変化し、最後には. 現在、すべてのラムダはへの参照を保持しています。これは、必要な値をラムダのローカル スコープに追加することで回避できます。9nxx9funcs9

    funcs.append( lambda x=x: x)

これは、外側のスコープでxループ変数によって参照されるのと同じオブジェクトで、ラムダ ローカル変数をポイントします。x異なる変数名を使用するとどうなるかは明らかです。

    funcs.append( lambda inner_x=x: inner_x)

しかし、x=xこの場合、フォームは非常に一般的です。したがって、各ボタンが正しい値を使用するようにするには、次のようにする必要があります。

launchbutton.bind( on_press = lambda widget, appname=row[1]: self.Launcher( appname ) )

row[1]ここでは、現在の値をラムダのローカル スコープにバインドするため、呼び出されたときにappnameそれが渡されます。Launcher

于 2012-09-11T16:29:41.877 に答える
1

作業コード。次の構造の CSV ファイルを作成します

1|hello
2|world

test.csv として保存

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Button
from kivy.config import Config
import csv
import os

class AppBase(Widget):
    def Launcher(self, launchapp):
        #os.system(launchapp)
        print(f"Application to be launched is {launchapp}")

    def BuildLayout(self):
        layout = GridLayout( rows = 4, row_force_default = True, row_default_height = 100, col_force_default = True, col_default_width = 300)
        with open('test.csv', 'r') as f:
            reader = csv.reader(f, delimiter='|')
            for row in reader:
                print(row)
                launchbutton = Button(text = row[0])


                launchbutton.bind( on_press = lambda widget, appname=row[1]: self.Launcher( appname ) )
                layout.add_widget(launchbutton)
        return layout

class MyApp(App):
    def build(self):
        Config.set('graphics','width', 1920)
        Config.set('graphics', 'height', 400)
        Config.set('graphics', 'maxfps', 30)
        return AppBase().BuildLayout()
if __name__ == '__main__':
    MyApp().run()
于 2021-08-14T11:39:08.783 に答える