2

Python で簡単な「プログラム ランチャー」を作成しました。現時点では、タブ区切りのテキスト ファイルがあります。

メモ帳 c:\windows\notepad.exe
書き込み c:\windows\write.exe

プログラムはテキストファイルを読み取り、オブジェクトの配列を作成します。各オブジェクトには、name プロパティ (メモ帳など) とルート プロパティ (C:\windows\notepad.exe など) があります。次に、オブジェクトごとに、ボタンに正しい名前でボタンを作成し、ボタンをクリックすると、ルートを使用して正しいプログラムを実行する必要があります。

プログラムはほとんど動作します。実際、オブジェクトの配列は正しく形成されています。これは、for ループが 2 つの異なるプログラム名と 2 つの異なるルートを正しく出力するためです。問題は、両方のボタンが正しくラベル付けされていても、書き込みプログラムを起動することです! 問題はコールバックのどこかで発生していると思いますが、私の Python の知識はこれを解決するのに十分ではありません! 以下のコードからわかるように、「インライン」コールバックを試し、「runprog」関数を定義しました。どちらも同じ結果になります。

あなたの助けをいただければ幸いです。

import Tkinter as tk
import subprocess

class MyClass:
    def __init__(self, thename,theroute):
        self.thename=thename
        self.theroute=theroute

myprogs = []

myfile = open('progs.txt', 'r')
for line in myfile:
    segmentedLine = line.split("\t")
    myprogs.append(MyClass(segmentedLine[0],segmentedLine[1]))
myfile.close()

def runprog(progroute):
    print(progroute)
    subprocess.call([progroute])

root = tk.Tk()
button_list=[]

for prog in myprogs:
    print(prog.thename)
    print(prog.theroute)

    button_list.append(tk.Button(root, text=prog.thename, bg='red', command=lambda: runprog(prog.theroute)))
#    button_list.append(tk.Button(root, text=prog.thename, bg='red', command= lambda: subprocess.call(prog.theroute)))

# show buttons
for button in button_list:
    button.pack(side='left', padx=10)
root.mainloop()
4

2 に答える 2

4

コマンドを次のように変更します。

tk.Button(..., command=lambda route=prog.theroute: runprog(route))

ラムダに、このボタンに関連付けるルートにデフォルト値を設定するキーワード引数があることに注意してください。キーワード arg にデフォルト値を与えることで、この値をこの特定のラムダに「バインド」します。

もう 1 つのオプションは、functools.partialを使用することです。これは、多くの人がラムダよりも威圧感が少ないと感じています。これにより、ボタンは次のようになります。

import functools 
...
tk.Button(..., command=functools.partial(runprog,route)

3 番目のオプションは、「ru​​nprog」関数をプログラムの主要部分ではなくクラスに移動することです。その場合、各ボタンは固有のオブジェクトに関連付けられているため、問題ははるかに単純になります。

tk.Button(..., command=prog.runprog)
于 2013-04-13T12:34:03.673 に答える
-1

この行を変更するだけです:

button_list.append(tk.Button(root, text=prog.thename, bg='red', command=lambda: runprog(prog.theroute)))

に:

button_list.append(tk.Button(root, text=prog.thename, bg='red',
          command= (lambda route:(lambda: runprog(route))) (prog.theroute)))

理由: ラムダ関数 (または関数内の他の関数) を作成すると、外側の関数スコープ内の変数にアクセスできます (Python 2 では読み取り専用アクセス)。ただし、そのスコープ内の「ライブ」変数にアクセスします-ラムダが呼び出されると、「prog」から取得される値は、その時点で「prog」が意味するものになります。この場合、最後の「prog」になりますあなたのリスト(インターフェース全体が構築された後、ユーザーはボタンをクリックするだけなので)

この変更により、中間スコープ (現在の "prog" 値が渡される別の関数本体) が導入され、式が実行される瞬間に prog.theroute が "route" 変数に割り当てられます。これは、リスト内のプログラムごとに 1 回行われます。実際のコールバックである内部ラムダは、中間スコープで「ルート」変数を使用します。これは、ループのパスごとに異なる値を保持します。

于 2013-04-13T10:27:15.703 に答える