2015-12-30 6 views
0

Я пытаюсь сделать GUI на python, чтобы управлять своим роботизированным автомобилем. Мой вопрос заключается в том, как я выполняю функцию, определяющую кнопку удержания. Я хочу переместить автомобиль, когда кнопка нажата, удерживается и останавливает автомобиль, когда кнопка отпускается.GUI Button hold down - tkinter

from Tkinter import * 

hold_down = False 
root = Tk() 

def button_hold(event): 
     hold_down=true 
     while hold_down== True: 
       print('test statement') 
       hold_down = root.bind('<ButtonRelease-1>',stop_motor) 

def stop_motor(event): 
     hold_down= False 
     print('button released') 

button = Button(root, text ="forward") 
button.pack(side=LEFT) 
root.bind('<Button-1>',button_forward) 
root.mainloop() 

Я пытаюсь моделировать то, что я нашел в этом answer

я пытаюсь сделать это в while цикле с булевым. Когда пользователь нажимает кнопку, логическое значение изменяется на True, а код вводит цикл while. Когда пользователь отпускает кнопку, логическое значение изменяется на False, а код выходит из цикла, но в этом коде логическое пребывание всегда истинно независимо от того, я отпустил кнопку или нет.

Редактирование: Я хочу, чтобы функция вызывалась до тех пор, пока не произойдет условие. Функция, которая будет вызываться, - hold_down(), и условие для проверки - это кнопка отпускается.

Обновление: Я нашел способ заставить его работать.

+0

Вы можете поделиться своим решением здесь? У меня такая же проблема. –

ответ

0

Попробуйте это ...

from Tkinter import * 
root = Tk() 
global hold_down 

def button_hold(event): 
    hold_down = True 
    while hold_down: 
     print('test statement') 

def stop_motor(event): 
    hold_down = False 
    print('button released') 

button = Button(root, text ="forward") 
button.pack(side=LEFT) 
root.bind('<Button-1>',button_hold) 
root.bind('<ButtonRelease-1>',stop_motor) 
root.mainloop() 
+0

его на бесконечный цикл. Это похоже на то, что он всегда остается верным (оставаться в петлях), и независимо от того, что, если отпущенная кнопка программа не перескакивает на другую команду, всегда остается в цикле. Я пытаюсь использовать root.bind для ButtonReleased внутри цикла while и не работает. –

+0

Это не сработает. Вы не позволяете циклу событий когда-либо обрабатывать выпуск кнопки. –

1

Вы можете попробовать вариант repeatinterval. Способ, которым он работает, - это кнопка, которая будет постоянно срабатывать, пока пользователь удерживает ее. Параметр repeatinterval по существу позволяет программе знать, как часто он должен запускать кнопку, если это так. Вот ссылка на объяснение:

http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/button.html

Поиск в странице для «repeatinterval».

Другим именем для этого параметра является repeatdelay.

3

Установите флажок, когда кнопка нажата, установите флажок, когда кнопка отпущена. Там нет необходимости в цикле, так как вы уже используете цикл (mainloop)

from Tkinter import * 
running = False 
root = Tk() 
def start_motor(event): 
    global running 
    running = True 
    print("starting motor...") 

def stop_motor(event): 
    global running 
    print("stopping motor...") 
    running = False 

button = Button(root, text ="forward") 
button.pack(side=LEFT) 
button.bind('<ButtonPress-1>',start_motor) 
button.bind('<ButtonRelease-1>',stop_motor) 
root.mainloop() 

Если предположить, что вы на самом деле хотите сделать что-то в то время как клавиша нажата, вы можете настроить цикл анимации с использованием after. Например, чтобы вызвать оператор печати один раз в секунду при нажатии кнопки, вы можете добавить функцию, которая выполняет оператор печати, а затем устраивает для себя вызов через секунду. Кнопка остановки просто должна отменить любое незавершенное задание.

Вот пример. Основное отличие от исходного кода заключается в добавлении функции move. Я также добавил вторую кнопку, чтобы показать, как можно использовать одну и ту же функцию для перехода вперед или назад.

from Tkinter import * 
running = False 
root = Tk() 
jobid = None 

def start_motor(direction): 
    print("starting motor...(%s)" % direction) 
    move(direction) 

def stop_motor(): 
    global jobid 
    root.after_cancel(jobid) 
    print("stopping motor...") 

def move(direction): 
    global jobid 
    print("Moving (%s)" % direction) 
    jobid = root.after(1000, move, direction) 

for direction in ("forward", "backward"): 
    button = Button(root, text=direction) 
    button.pack(side=LEFT) 
    button.bind('<ButtonPress-1>', lambda event, direction=direction: start_motor(direction)) 
    button.bind('<ButtonRelease-1>', lambda event: stop_motor()) 

root.mainloop() 
+0

Нельзя ли привязать кнопку, а не главное окно? –

+0

@StevenSummers: Может быть. Неясно, чего хочет OP. Исходный код привязывается к главному окну. Это зависит от того, хотите ли они, чтобы кнопка мыши нажата в любом месте графического интерфейса пользователя, или только при использовании виджета кнопки. Теперь, когда я перечитаю вопрос, возможно, вы правы. Я изменю свой ответ. –

+0

Я хочу, когда пользователь нажимает кнопку (нигде в графическом интерфейсе) и не повторяет эту функцию, пользователь освобождает кнопку. –

-1

@ Дэнни Попробуйте следующий код:

четкость stop_motor (событие): печати (кнопку 'выпустил') возвращает False

Этого ответ тиражи «испытательное заявление ' один раз. Цикл while запускается один раз при нажатии кнопки.

@ Bryan Oakley Установить флаг при нажатии кнопки, снять флаг при отпускании кнопки. Там нет необходимости в цикле, так как вы уже используете петлю (MainLoop)

from Tkinter import * 
running = False 

root = Tk() 
def start_motor(event): 
    global running 
    running = True 
    print("starting motor...") 

def stop_motor(event): 
    global running 
    print("stopping motor...") 
    running = False 

button = Button(root, text ="forward") 
button.pack(side=LEFT) 
root.bind('<ButtonPress-1>',start_motor) 
root.bind('<ButtonRelease-1>',stop_motor) 
root.mainloop() 

Этот ответ выше остается в бесконечном цикле при нажатии кнопки.

@ Joseph FarahВы можете попробовать вариант repeatinterval. Способ, которым он работает, - это кнопка, которая будет постоянно срабатывать, пока пользователь удерживает ее. Параметр repeatinterval по существу позволяет программе знать, как часто он должен запускать кнопку, если это так. Вот ссылка на объяснение:

http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/button.html

Поиск в странице для «repeatinterval».

Другое имя для этого параметра - repeatdelay.

Я установил интервал повторения в параметре для виджета кнопки, но он не повторяет команду.

Спасибо за весь ответ. Все еще ищут решение этой проблемы.

+0

Могу ли я увидеть код для функции button_forward? – Danny

+0

Код для функции button_forward совпадает с кодом для кнопки button_hold. Я меняю имена, но делаю то же самое. –

+0

Что я хочу сделать, так это. Я хочу сделать это, когда пользователь (я) удерживает кнопку «foward», программа продолжает выполнять код, который заставляет машину работать в фойе, и когда я отпускаю кнопку, остановите машину - прекратите выполнение кода. –

0

Основываясь на ответе Брайана Оукли об использовании флагов для имитации нажатия и удержания кнопки. Проблема в том, что вы не можете иметь какие-либо петель в своем приложении tkinter, чтобы сказать во время движения движением вперед вперед.

Именно поэтому я предлагаю использовать потоки. Таким образом, вы можете запустить цикл while в фоновом режиме, проверяя, должен ли автомобиль двигаться вперед.

from threading import Thread 
from Tkinter import *  

running = False 
root = Tk() 

def start_motor(event): 
    global running 
    print("starting motor...") 
    running = True 

def stop_motor(event): 
    global running 
    running = False 
    print("stopping motor...") 

def move_forward(): 
    while True: # Thread will run infinitely in the background 
     if running: 
      print("Car is moving forward...\n") 

button = Button(root, text ="forward") 
button.pack(side=LEFT) 
button.bind('<ButtonPress-1>',start_motor) 
button.bind('<ButtonRelease-1>',stop_motor) 

# Create and start the new thread 
t = Thread(target = move_forward, args =()) 
t.start() 

root.mainloop() 
+0

Фоновая нить всегда занимает 100% процессорного времени - не очень хорошо. – Olexa

+0

Чтобы избежать использования процессорного времени по фоновому потоку, когда это не необходимо, создайте и запустите поток в 'start_motor' после' running = True', вместо того, чтобы создавать и запускать его при запуске, а также менять 'move_forward' для запуска' while running' вместо от 'while True'. – Olexa