Есть ли какое-либо событие для Gtk.Button, которое будет многократно выполнять код, пока кнопка нажата?

Есть ли какое-либо событие для Gtk.Button, которое будет многократно выполнять код, пока кнопка нажата?

Предположим, у меня есть следующий код, написанный на Python 3 и использующий PyGObject. Я хотел бы, чтобы сообщение «Привет» повторно печаталось на экране, пока пользователь удерживал левую кнопку мыши над кнопкой (нажимая и удерживая).

Есть ли какое-либо другое событие, которое я могу использовать вместо щелчка или любого другого решения? Спасибо.

from gi.repository import Gtk

class Window(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self)
        self.button = Gtk.Button("Hi Printer")
        self.button.connect("clicked", self.on_button_clicked)
        self.add(self.button)
        self.connect("delete-event", Gtk.main_quit)
    def on_button_clicked(self, widget):
        print("Hi")

window = Window()
window.show_all()
Gtk.main()

person Zignd    schedule 17.10.2013    source источник


Ответы (2)


Адаптировано из отредактированного ответа tcaswell, но без дополнительного вызова print_hi() после отпускания кнопки:

from gi.repository import Gtk, GObject

class Window(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self)
        self.button = Gtk.Button("Hi Printer")
        self.button.connect("pressed", self.on_button_clicked)
        self.button.connect("released", self.on_button_released)
        self.add(self.button)
        self.connect("delete-event", Gtk.main_quit)

    def on_button_clicked(self, widget):
        # kick off time out
        timeout = 50
        self._timeout_id = GObject.timeout_add(timeout, self.print_hi)

    def on_button_released(self, widget):
        # remove timeout
        GObject.source_remove(self._timeout_id)
        self._timeout_id = 0 # better safe than sorry

    def print_hi(self):
        print 'hi'
        # repeat until the source is removed
        return True

window = Window()
window.show_all()
Gtk.main()
person Tristan Brindle    schedule 18.10.2013
comment
Спасибо Tristan Brindle за ответ и решение проблемы с тайм-аутом. - person Zignd; 19.10.2013

from gi.repository import Gtk, GObject

class Window(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self)
        self.button = Gtk.Button("Hi Printer")
        self.button.connect("pressed", self.on_button_clicked)
        self.button.connect("released", self.on_button_released)
        self.add(self.button)
        self.connect("delete-event", Gtk.main_quit)

    def on_button_clicked(self, widget):
        # arm repeater
        self._repeat = True
        # trigger printing
        self.print_hi()

    def on_button_released(self, widget):
        # disarm repeater
        self._repeat = False

    def print_hi(self):
        print 'hi'
        # tune timeout for repeat rate
        timeout = 50
        # if should still be repeating
        if self._repeat:
            # arm timer, with call back to this function
            GObject.timeout_add(timeout, self.print_hi)

window = Window()
window.show_all()
Gtk.main()

Проблема до того, как «нажата» кнопка вверх-вниз, «нажата» вниз, а «отпущена» вверх.

Также обновлено, чтобы использовать правильный таймер.

Оказывается функция таймаута в gtk может автоматически переустанавливаться, так что это можно сделать еще проще:

from gi.repository import Gtk, GObject


class Window(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self)
        self.button = Gtk.Button("Hi Printer")
        self.button.connect("pressed", self.on_button_clicked)
        self.button.connect("released", self.on_button_released)
        self.add(self.button)
        self.connect("delete-event", Gtk.main_quit)

    def on_button_clicked(self, widget):
        # arm repeater
        self._repeat = True
        # kick off time out
        timeout = 50
        GObject.timeout_add(timeout, self.print_hi)

    def on_button_released(self, widget):
        # disarm repeater
        self._repeat = False

    def print_hi(self):
        print 'hi'
        # if should still be repeating
        return self._repeat

window = Window()
window.show_all()
Gtk.main()

пример

person tacaswell    schedule 17.10.2013
comment
Вы не можете вызвать timeout_add_seconds с плавающей запятой. Или, в зависимости от вашей версии, возможно, вы можете, но он все равно будет запускаться каждую секунду, а не каждые 0,5 секунды. Если вы хотите запускать более одного раза в секунду (или просто хотите большей точности), вы должны использовать timeout_add. - person abarnert; 18.10.2013
comment
tcaswell, ваше решение работает не очень хорошо, но похоже, что решение будет запускать поток при нажатии кнопки и останавливать его при ее отпускании, верно? Я также исправил ваш код, и он работает на Python 3 и PyGObject, а не на PyGTK. - person Zignd; 18.10.2013
comment
@abarnert, не могли бы вы подтвердить мою логику, если она верна? решение будет запускать поток при нажатии кнопки и останавливать его при отпускании - person Zignd; 18.10.2013
comment
@Zignd: нет необходимости использовать поток только для периодического запуска кода; вы делаете вещи более сложными и менее эффективными без причины. Основная идея в этом ответе выглядит правильной, даже если детали могут быть неверными. Между тем, если вы объясните, что вы имеете в виду под не очень хорошей работой, возможно, будет легче ее улучшить. - person abarnert; 18.10.2013
comment
@abarnert Да, я испортил детали. Я думаю, что теперь они верны (работает на py2.7) - person tacaswell; 18.10.2013
comment
Вышеупомянутое (отредактированное) решение в порядке, но у него есть недостаток, заключающийся в том, что функция тайм-аута (print_hi()) по-прежнему будет запускаться после того, как кнопка будет отпущена. Это, вероятно, незаметно с интервалом повторения 50 мс, но определенно будет раздражать, скажем, с задержкой в ​​1 секунду. Лучшим решением было бы сохранить возвращаемое значение из GObject.timeout_add(), а затем вызвать GObject.source_remove() с этим сохраненным значением в вашей функции on_button_released(), чтобы удалить время ожидания до следующего срабатывания. - person Tristan Brindle; 18.10.2013