Форум сайта python.su
Прошу помощи: я не знаю, как повесить событие на несколько одновременно нажатых клавиш. window.bind('<Клавиша1><Клавиша2>', Функция) не подходит, поскольку срабатывает только при нажатий клавиш порядке и один раз, даже если прицепить модификатор KeyPress. Можно поставить на сочетание с такими клавишами как shift, ctrl. alt, end …(их много) , но мне необходимы две стрелочки.
Уже есть бинды на все стрелочки(1клавиша - 1вызов). Я думал, что нажму две стрелочки и будет меня 2 вызова ф-ий, но нет: при нажатие двух клавиш срабатывает лишь событие одной, а соответственно один обработчик. У меня было 2 мысли, почему такое поведение:
1)однопоточность приложения в целом
2)невозможность осуществлять запись, одновременно с разных потоков в один участок памяти.
Поэтому я разбил каждый бинд(всего 4 бинда, все стрелки) в отдельный поток и сделал очередь. Получилось модель(или как это называется?) производитель\потребитель. Но одновременно два события работать серавно не могли, что в целом предположительно. Ведь bind не вешает весь процесс, а работает как бэ уже работает в фоне, а значит в другом потоке?(я вложил поток в поток?)
Помогите решить мою задачу, надо при событии на двух кнопках одновременно вызывать их обработчики или создать еще одно условие, где необходимо будет нажимать две кнопки одновременно.
Можно вешать в обработчик кнопки еще один бинд и получится некая матрёшка, но это же не верный подход.
Можно проверять клавиши самостоятельно с помощью винапи, но это ведь тоже не правильный вариант.
И очень важно есть ли в моих раздумьях хоть зерно здравого смысла или это все фантазированный бред? Если найдется альтруистически настроенный форумчанин просьба объяснить мои логические ошибки и маразмы.
-
Очевидно, что у меня мало знаний. Может мне что полистать? лутц(которого я полностью не осилил, а лишь заглядываю в некоторые главы) и бизли есть.
Отредактировано moron (Май 14, 2013 15:02:18)
Офлайн
Пример кода. Тогда поговорим… Вы задали сразу несколько вопросов. Часть из них противоречит друг другу. Когда должно происходить действие? Когда нажаты эти две кнопки или когда отпущены? Короче. Код, дружище Битнер, код…
Офлайн
Хорошо, сейчас скину, только такого ужаса вы наверное нигде не видели(индусы отдыхают). Мне стыдно, я не хотел такое вываливать.
#класс окна class GameWin(t.Tk): def __init__(self): print('in __init__') t.Tk.__init__(self) self.title('tank') self.geometry('800x800+150+150') self.resizable(False, False) self.canv = t.Canvas(self, width=800, height=800, bg='white') self.canv.pack() def addTexture(self, fileName): self.texture = ImageTk.PhotoImage(file=fileName) #Посколько минимальное кол-во текстуры 1, то +1 XTexture = int(self.canv.cget('height'))//self.texture.height() +1 YTexture = int(self.canv.cget('width'))//self.texture.width() + 1 for y in range(0, YTexture): for x in range(0, XTexture): self.canv.create_image(x*int(self.texture.width()), y*int(self.texture.width()), image=self.texture, anchor='nw') def addImg(self, fileName): self.imgTank = ImageTk.PhotoImage(file=fileName) self.canv.create_image(50, 50, image=self.imgTank, tag='PLAYER') win = GameWin() win.addTexture('grass_4.jpg') ########################### ######Тут уйма вариантов####### ####################### #1вариант. При нажатии двух клавиш лишь одно событие #функции движения def moveDown(event): x, y = win.canv.coords('PLAYER') win.canv.move('PLAYER', 0, 3) def moveRight(event): x, y = win.canv.coords('PLAYER') win.canv.move('PLAYER', 3, 0) #бинды win.bind('<Down>', moveDown) win.bind('<Right>', moveRight) ######################### #2вариант. При нажатии двух клавиш одно событие. Потоки+очередь #функции движения def threadDown(event): q.put([0, 3]) def threadRight(event): q.put([3, 0]) def moveTank(): coords = q.get() win.canv.move('PLAYER', coords[0], coords[1]) moveTank()#рекурсия-потенциальная утечка памяти? q = Queue() #cами бинды. threading.Thread(target=win.bind, args=('<Down>', threadDown)).start() threading.Thread(target=win.bind, args=('<Right>', threadRight)).start() threading.Thread(target=moveTank).start()
Когда должно происходить действие? Когда нажаты эти две кнопки или когда отпущены?Когда нажата(зажата) хотя бы одна, в случае, если нажаты обе, то одновременно два евента-два обработчика(или же, если это возможно дополнительный бинд на две сразу на две кнопки(bind('<Down><Right>') не подойдет, поскольку событие должно сработать несколько раз и не просто на одноразовом нажатии этих кнопок, а при их удержании)
Офлайн
Вас понял. Мой вариант следующий (так оно и должно быть реализовано):
Необходимо написать метод для перехвата нажатие любой клавиши и в нем самостоятельно собирать нажатие отдельных клавиш в кластер ориентируясь на время межну нажатиями. Выходом клавиши из кластера является событие Release для одной из клавиш… Нужен пример - пишите :)
P.S. Рекомендую еще почитать это http://ru.wikiversity.org/wiki/Курс_по_библиотеке_Tkinter_языка_Python
Раздел “Класс Tk”…
Отредактировано 4kpt (Май 15, 2013 12:00:21)
Офлайн
Как-то так.
class BindCombination(object): _instance = None _combinations = list() _pressed_buttons = dict() def __new__(cls, *args, **kw): if cls._instance is None: cls._instance = super(BindCombination, cls).__new__(cls, *args, **kw) return cls._instance # def __init__(self, tk_widget, combination, func): """ combination - tuple("Right", "Left", "any_button") """ for button in combination: tk_widget.bind("<KeyPress-%s>" % button, self._remember(button)) tk_widget.bind("<KeyRelease-%s>" % button, self._forget(button)) self._pressed_buttons[button] = False self._combinations.append({"buttons": combination, "callback": func}) # def _remember(self, button): def func(*args): self._pressed_buttons[button] = True self._check_combinations() return func # def _forget(self, button): def func(*args): self._pressed_buttons[button] = False return func # def _check_combinations(self): for combination in self._combinations: is_ok = True for button in combination["buttons"]: if not self._pressed_buttons[button]: is_ok = False break if is_ok: combination["callback"]() # # теперь в коде # # arrow left + arrow right BindCombination(root, ("Left", "Right"), my_callback_function) # f + d BindCombination(my_widget, ("f", "d"), my_callback_function) # shift + A + B BindCombination(my_widget, ("A", "B"), my_callback_function)
Отредактировано Griffon (Май 16, 2013 09:53:28)
Офлайн
Прикольно. Но зачем
def __new__(cls, *args, **kw): if cls._instance is None: cls._instance = super(BindCombination, cls).__new__(cls, *args, **kw) return cls._instance
Отредактировано 4kpt (Май 16, 2013 21:28:14)
Офлайн
Изначально я думал над тем чтобы можно было добавлять и удалять бинды, и идея была держать все в одном инстансе. Боялся что при отсутствии ссылок на объекты они могут быть удалены сборщиком мусора. Возможно недопонимание.
upd: видимо лишнее : )
Отредактировано Griffon (Май 16, 2013 22:05:26)
Офлайн
Просмотрел код. Класс. Стащил к себе в архив. Все хорошо, но нужно еще пилить и пилить. Я над похожей идеей думал. Я вешал обработчики Press на одни события и собирал кластер за счет разности во времени между событиями (анализ разницы проводился в атрибуте класса). Если разница маленькая - выполнялся один кластер. Но здесь есть бок. Если один из элементов кластера выключался (держал лево, зажал верх и отпустил верх, то функция, повешенная на лево уже не выполнялась и приходилось самостоятельно генерировать ее поведение, пока для нее не будет вызван Release). Именно с этой генерацией иногда и возникал бок :)
P.S. Ваше решение получше, но нужно еще подпилить одинарные события и разобраться с переопределение метода .bind. Если припечет, допилю Ваш вариант. Пока надобности нет, посему…
Офлайн
def __new__(cls, *args, **kw): if cls._instance is None: cls._instance = super(BindCombination, cls).__new__(cls, *args, **kw) return cls._instance
P.S. Рекомендую еще почитать это http://ru.wikiversity.org/wiki/Курс_по_библиотеке_Tkinter_языка_PythonИ это, блин, мне ни о чем не сказало. Лучше создавать главное окно с помощью Toplevel()? Что я должен был понять?
Раздел “Класс Tk”…
Отредактировано moron (Май 17, 2013 18:18:19)
Офлайн
Однопоточность Tkinter и метод создания параллельного потока…
Офлайн