2017-01-15 17 views
0

これは私が苦労しているプログラムの2番目のバージョンです。私はプログラムの最初のバージョンで以前の質問を掲載しましたが、運はありませんでした。TKinterボタンでいつでもGPIO RPiループを中断する方法

ここでは、私がトラックから外れている場所を見つけるのに役立つ「大きな画像のアイデア」です。私は水にたくさんの植物を持っていますが、ラズベリーパイのタッチスクリーンに表示されるTKinterのGUIを作りたいと思います。 Piは、水ポンプに配線された110Vリレースイッチを制御します。 z#の植物の基本的な「オン/オフ」ループ。

ユーザーには、調整する3つのスライダーバー、X、Y、Zの値があります。 XはウォーターポンプをONにする必要がある時間、Yはウォーターポンプをどれぐらいオフにする必要があるか(したがって、ホースを次のプラントに物理的に移動させる時間がある)、Zは必要なプラントの総数水。私はいつもループを永遠に走らせていました。なぜなら私はいつもCTRL-Cを使ってプログラムを終了させることができたからです。しかし今はキーボードが不要なタッチスクリーン上で全部しようとしています。 Linuxが端末の使い方をどのように意味しているかを知る。 GUIのタッチスクリーンボタン(スマートフォンやタブレットのような)を見るのに慣れているプログラムのように実行する必要もあります。

コードはほとんどの場合うまく機能し、停止してクラッシュすることなく起動します。私はスタートボタンを見つけました。そして、ゼロで値を開始したい場合にスライダーの値をクリアするリセットボタンがあります。しかし、ここにいる多くの人々に影響を与えていると思われる大きな問題は、frigginのEXITボタンです。

ループ中にいつでもTKinter EXITボタンを押して、ボタンが押されたときにプログラムに知らせて、すぐにループを中断することができるようにする必要があります。私は多くのことを試みましたが、何も動作しません。チェックボタンは、ループが終了するまで待ってから、トグル値を更新します。その時点でそれは遅すぎます。私は給水ループ全体でユーザーコントロールが必要です。

EXITを押したときにプログラムを終了させたくないのではなく、GPIOループを "OFF"値で停止して基本的にプログラムを開始状態に戻したいとします。

私はtime.sleep()が非常に粗いことを知っていますが、それ以外の方法はありません。私は人々が「糸を引く」ことについて話しているのを見たことがありますが、私はそれが何を意味しているのかわかりません。私はTKintersの "after()"関数についても人々が話しているのを見てきました。また、私は答えについて非常に明確な例が必要です。ちょうど "使用スレッド"はヘルプを提供していない - 私はノブです!

from tkinter import * 
    import RPi.GPIO as GPIO 
    import time 


    master = Tk() 


    def onoffcycle(): 
     GPIO.setwarnings(False) 
     GPIO.setmode(GPIO.BCM) 
     GPIO.setup(14, GPIO.OUT) 
     GPIO.setup(14, GPIO.LOW) 
     y=off.get() 
     y=float(y) 
     x=on.get() 
     x=float(x) 
     GPIO.output(14, True) 
     print("On")+str(x) 
     time.sleep(x) 
     GPIO.output(14, False) 
     print("Off")+str(y) 
     time.sleep(y) 


    def start(): 
     print("Prepare to water in 10 seconds...") 
     time.sleep(10) 
     z=cycle.get() 
     z=float(z) 
     while z > 0: 
      onoffcycle() 
      z=z-1 
      print("Cycles remaining:")+str(z) 
      ###tog() 
      ###if t==1: 
       ###reset() 
     else: 
      reset() 
     ### this program runs onoffcycle() for z number of cycles as set by the slider. 
     ### It should check for an exit toggle, then run the program for one cycle, 
     ### then check for exit, then another round. countdown from cycle.get variable 


    def reset(): 
     GPIO.cleanup() 
     on.set(0) 
     off.set(0) 
     cycle.set(0) 

    t=IntVar() 

    ###def tog(): 
     ### HELP! This is where I need the program to be looking for the EXIT button being pressed 
     ### in order to stop the program. Everything I have tried so far waits until the z value drops 
     ### to zero, basically until the program stops on its own. I need a button that interrupts 
     ### everything. 


    on = Scale(master, label="Set # Seconds Water ON:", from_=0, to=180, orient=HORIZONTAL, length=400, width=35, 
       troughcolor="red", bg="SteelBlue1", fg="black", bd=6, sliderlength=90, sliderrelief=RIDGE, 
       font = '-weight bold') 
    on.grid(column=1, row=1, columnspan=3) 

    off = Scale(master, label="Set # Seconds Water OFF:", from_=0, to=30, orient=HORIZONTAL, length=400, width=35, 
       troughcolor="yellow", bg="SteelBlue1", fg="black", bd=6, sliderlength=90, sliderrelief=RIDGE, 
       font = '-weight bold') 
    off.grid(column=1, row=2, columnspan=3) 

    cycle = Scale(master, label="Set # of Plants to Water:", from_=0, to=200, orient=HORIZONTAL, length=400, width=35, 
       troughcolor="green", bg="SteelBlue1", fg="black", bd=6, sliderlength=90, sliderrelief=RIDGE, 
       font = '-weight bold') 
    cycle.grid(column=1, row=3, columnspan=3) 


    go = Button(master, text="START", command=start, bg="SteelBlue3", width=10, height=2, font='-weight bold') 
    go.grid(column=1, row=4) 

    adios = Checkbutton(master, text="EXIT", variable=t, indicatoron=0, bd=6, bg="SteelBlue3", width=11, height=2, font='-weight bold') 
    adios.grid(column=3, row=4) 
    ###adios should have a command to run an exit program - with toggle values? or something else? 
    resetbutton = Button(master, text="RESET", command=reset, bg="SteelBlue3", width=10, height=2, font='-weight bold') 
    resetbutton.grid(column=2, row=4) 



    mainloop() 
+0

あなたは 'sleep()'と 'while'の代わりに' root.after(milliseconds、function_name) 'を使う必要があります。 '10s = 10000ms'つまり、' start() 'の最後の' root.after(10000、start) 'は10秒後にこの関数を再度実行しなければならず、' sleep() 'は必要なく、 whileを必要とするが、ifはafterを止める。 – furas

+0

'print(" On ")+ str(x)'は 'None'を返すので意味がありません。' None + str(x) 'を実行します。 print( "On"、x) 'または少なくともprint(" On "+ str(x))'または 'print(" On {} "。最も単純です。 – furas

+0

furas - 非常に多くの情報をありがとう! print()の部分は、ユーザが選択した値をコマンドラインで表示します。 TKinterのウィンドウを全画面にしたいので、実際にはユーザーが見ることを意図していないと思います。私はデバッグ中にそれを使っていましたが、最終的には役に立たないかもしれません。 – Stephen

答えて

0

使用ブール変数True/False

time_to_exit = False 

グローバル変数を作成し、EXITボタン

を押し、で使用する場合、それをTrueを設定し、例えば、ループやその他の要素

を制御します機能

while z > 0 and not time_to_exit: 

ループを停止する必要があります。

ループが停止して終了する場合、他のブール変数を使用してプログラムに通知できます。

# inform function to use global variable 
global loop_is_working 
loop_is_working = True 
while z > 0 and not time_to_exit: 

# ... 

def reset(): 
    # inform function to use global variable 
    global loop_is_working 

    loop_is_working = False 

def on_exit: 

    if loop_is_working: 
     reset() 
     # check again afte 100ms 
     after(100, on_exit) 
    else: 
     # stop `mainloop()` and close tkinter window 
     root.destroy() 

あなたの他の問題がある:あなたがsleep()whileを使用するので、Tkinterは、それが終わるまで待たなければなりません。

master.after(miliseconds, function_name)Tkinter/mainloopを使用すると、この機能が実行され、ボタンを確認できます。

time_to_exit = False 

def start(): 
    print("Prepare to water in 10 seconds...") 

    # mainloop will run `start_loop` after `10s` 
    master.after(10000, start_loop) # 10s = 10 000ms 

def start_loop():  
    z = float(cycle.get()) 
    loop(z) 
    # or 
    #master.after(0, loop, z) 

def loop(z):  
    if z > 0 and not time_to_exit: 
     onoffcycle() 
     z -= 1 
     print("Cycles remaining:", z) 
      ###tog() 
      ###if t==1: 
       ###reset() 
     # mainloop will run `loop` again as soon as possible 
     master.after(0, loop, z) 
    else:  
     reset() 

あるいは

# create global variables 
time_to_exit = False 
loop_is_working = False 

def start(): 
    # inform function to use global variable 
    global loop_is_working 

    loop_is_working = True 

    print("Prepare to water in 10 seconds...") 

    # mainloop will run `start_loop` after `10s` 
    master.after(10000, start_loop) # 10s = 10 000ms 

def start_loop():  
    z = float(cycle.get()) 
    loop(z) 
    # or 
    #master.after(0, loop, z) 

def loop(z):  

    if z > 0 and not time_to_exit and loop_is_working: 
     onoffcycle() 
     z -= 1 
     print("Cycles remaining:", z) 
      ###tog() 
      ###if t==1: 
       ###reset() 
     # mainloop will run `loop` again as soon as possible 
     master.after(0, loop, z) 
    else:  
     reset() 

def reset(): 
    # inform function to use global variable 
    global loop_is_working 

    # ... your code ... 

    loop_is_working = False 
+0

これは素晴らしいです、私はそれを試してみましょう、あなたにお知らせください! – Stephen

+0

うわー!リセットボタンがループを中断します。唯一の問題は、 'z'値が 'loop()'の各反復後に減少しないことです。それを移動するか、グローバル変数として導入するか? – Stephen

+0

私はコードを変更しました - 'start_loop'が' z'(10s後)を取得し、 'loop(z)を実行します) '。そして '後で'新しい 'z'で' loop'を再び実行します – furas

0

だからここfuras'優れた提案を新しいコードがあります。私はまた、反復ごとにz値を減らす方法を見つけました。 RESETボタンは、現在のサイクルが完了した後にプログラムを停止させ、新しいサイクルを開始するのを待ちます。これはまだONとOFFのタイミングを扱っているtime.sleep()があるからです。私はこのためにafter()を使用しようとしましたが、他の大きな問題につながっていました。そして、この時点では、プログラムは技術的に完全に使えるので、私はそれを1つのサイクルでぶら下げても構いません。それは実際の世界のアプリケーションを損なうことはありません!タッチスクリーンを適切に較正し、LDXEを自動起動した後に自動的にプログラムを起動するなど、自分自身の質問に値する他の問題がまだあります。 class()にすべてを適切に配置する予定です。また、if:ステートメントで止まっている間にLabelウィジェットのテキストを変更できるようにしたいと考えています。みんな、ありがとう!

#!/usr/bin/python 
    from Tkinter import * 
    import ttk 
    import RPi.GPIO as GPIO 
    import time 


    master = Tk() 
    master.title("Obligatory Title") 
    master.attributes("-fullscreen", True) 
    time_to_exit = False 
    loop_is_working = False 


    def onoffcycle(): 
     global t 
     GPIO.setwarnings(False) 
     GPIO.setmode(GPIO.BCM) 
     GPIO.setup(18, GPIO.OUT) 
     GPIO.output(18, GPIO.LOW) 
     y=float(off.get()) 
     x=float(on.get()) 
     GPIO.output(18, True) 
     print("On")+str(x) 
     t.set("Water ON") 
     t.get() 
     time.sleep(x) 
     GPIO.output(18, False) 
     print("Off")+str(y) 
     t.set("Water OFF") 
     time.sleep(y)    

    def start(): 
     global loop_is_working 
     global t 
     loop_is_working = True 
     print("Prepare to water in 10 seconds...") 
     t.set("Prepare to water in 10 seconds...") 
     master.after(10000, loop) 

    def loop(): 
     z=float(cycle.get()) 
     global loop_is_working 
     global time_to_exit 
     global t 
     t.set("Now Watering...") 
     if z > 0 and not time_to_exit and loop_is_working: 
      onoffcycle() 
      z=z-1 
      cycle.set(z) 
      print("Cycles remaining: ")+ str(z) 
      master.after(0, loop) 
     else: 
      reset() 


    def reset(): 
     global loop_is_working 

     GPIO.cleanup() 
     on.set(0) 
     off.set(0) 
     cycle.set(0) 
     t.set("Welcome! Drag the sliders to set values. Tap left or right of the sliders to fine tune values.") 
     loop_is_working = False 

    t = StringVar() 
    t.set("Welcome! Drag the sliders to set values. Tap left or right of the sliders to fine tune values.") 

    welcome = Label(master, bg="Steelblue3", bd=6, relief=RAISED, width=92, 
        height=2, textvariable=t) 
    welcome.grid(column=1, row=1, columnspan=3) 


    on = Scale(master, label="Set # Seconds Water ON:", from_=0, to=120, orient=HORIZONTAL, length=735, 
       width=50, troughcolor="steelblue", bg="SteelBlue1", fg="black", bd=6, sliderlength=90, 
       sliderrelief=RIDGE) 
    on.grid(column=1, row=2, columnspan=3) 

    off = Scale(master, label="Set # Seconds Water OFF:", from_=0, to=30, orient=HORIZONTAL, length=735, 
       width=50,troughcolor="steelblue", bg="SteelBlue1", fg="black", bd=6, sliderlength=90, 
       sliderrelief=RIDGE) 
    off.grid(column=1, row=3, columnspan=3) 

    cycle = Scale(master, label="Set # of Plants to Water:", from_=0, to=200, orient=HORIZONTAL, length=735, 
        width=50,troughcolor="steelblue", bg="SteelBlue1", fg="black", bd=6, sliderlength=90, 
        sliderrelief=RIDGE) 
    cycle.grid(column=1, row=4, columnspan=3) 

    go = Button(master, text="START", command=start, bg="green3", width=19, height=3, 
       bd=4, font='-weight bold') 
    go.grid(column=1, row=5) 

    adios = Button(master, text="EXIT", command=exit, bg="red3", width=19, height=3, 
       bd=4, font='-weight bold') 
    adios.grid(column=3, row=5) 

    resetb = Button(master, text="RESET", command=reset, bg="yellow3", width=19, 
       height=3, bd=4, font='-weight bold') 
    resetb.grid(column=2, row=5) 

    mainloop() 
関連する問題