from tkinter import * class Interface_graphique(Frame): def __init__(self, root, **kwargs): Frame.__init__(self, root, width=768, height=576, **kwargs) self.pack(fill=BOTH) self.message_1 = Label(self, text="value1") self.message_1.grid(row=0, sticky='w') self.entry_1 = Entry(self) self.entry_1.grid(row=0, column=1) self.message_2 = Label(self, text="value2") self.message_2.grid(row=1, sticky='w') self.entry_2 = Entry(self) self.entry_2.grid(row=1, column=1) root = Tk() interface = Interface_graphique(root) interface.mainloop() I want to type in the Entry widget 'value1' and press the down arrow button to put the cursor in the Entry widget 'value2. Is it possible?
3 Réponses :
Une solution serait d'utiliser une liste pour stocker vos champs de saisie, puis de lier chaque champ avec une référence au champ précédent et suivant de la liste en fonction de l'index. avantage supplémentaire de ne travailler que dans les champs de saisie. Vous n'aurez pas à vous soucier de l'utilisation des touches fléchées lorsqu'un champ de saisie n'a pas du tout le focus sur votre interface graphique.
import tkinter as tk import ctypes from ctypes import wintypes import time user32 = ctypes.WinDLL('user32', use_last_error=True) INPUT_MOUSE = 0 INPUT_KEYBOARD = 1 INPUT_HARDWARE = 2 KEYEVENTF_EXTENDEDKEY = 0x0001 KEYEVENTF_KEYUP = 0x0002 KEYEVENTF_UNICODE = 0x0004 KEYEVENTF_SCANCODE = 0x0008 MAPVK_VK_TO_VSC = 0 # msdn.microsoft.com/en-us/library/dd375731 VK_TAB = 0x09 VK_SHIFT = 0x10 # C struct definitions wintypes.ULONG_PTR = wintypes.WPARAM class MOUSEINPUT(ctypes.Structure): _fields_ = (("dx", wintypes.LONG), ("dy", wintypes.LONG), ("mouseData", wintypes.DWORD), ("dwFlags", wintypes.DWORD), ("time", wintypes.DWORD), ("dwExtraInfo", wintypes.ULONG_PTR)) class KEYBDINPUT(ctypes.Structure): _fields_ = (("wVk", wintypes.WORD), ("wScan", wintypes.WORD), ("dwFlags", wintypes.DWORD), ("time", wintypes.DWORD), ("dwExtraInfo", wintypes.ULONG_PTR)) def __init__(self, *args, **kwds): super(KEYBDINPUT, self).__init__(*args, **kwds) # some programs use the scan code even if KEYEVENTF_SCANCODE # isn't set in dwFflags, so attempt to map the correct code. if not self.dwFlags & KEYEVENTF_UNICODE: self.wScan = user32.MapVirtualKeyExW(self.wVk, MAPVK_VK_TO_VSC, 0) class HARDWAREINPUT(ctypes.Structure): _fields_ = (("uMsg", wintypes.DWORD), ("wParamL", wintypes.WORD), ("wParamH", wintypes.WORD)) class INPUT(ctypes.Structure): class _INPUT(ctypes.Union): _fields_ = (("ki", KEYBDINPUT), ("mi", MOUSEINPUT), ("hi", HARDWAREINPUT)) _anonymous_ = ("_input",) _fields_ = (("type", wintypes.DWORD), ("_input", _INPUT)) LPINPUT = ctypes.POINTER(INPUT) def _check_count(result, func, args): if result == 0: raise ctypes.WinError(ctypes.get_last_error()) return args user32.SendInput.errcheck = _check_count user32.SendInput.argtypes = (wintypes.UINT, # nInputs LPINPUT, # pInputs ctypes.c_int) # cbSize # Functions def PressKey(hexKeyCode): x = INPUT(type=INPUT_KEYBOARD, ki=KEYBDINPUT(wVk=hexKeyCode)) user32.SendInput(1, ctypes.byref(x), ctypes.sizeof(x)) def ReleaseKey(hexKeyCode): x = INPUT(type=INPUT_KEYBOARD, ki=KEYBDINPUT(wVk=hexKeyCode, dwFlags=KEYEVENTF_KEYUP)) user32.SendInput(1, ctypes.byref(x), ctypes.sizeof(x)) root = tk.Tk() def up_key(event): PressKey(VK_SHIFT) PressKey(VK_TAB) ReleaseKey(VK_TAB) ReleaseKey(VK_SHIFT) def down_key(event): PressKey(VK_TAB) ReleaseKey(VK_TAB) tk.Entry(root).pack() tk.Entry(root).pack() tk.Entry(root).pack() tk.Entry(root).pack() tk.Entry(root).pack() root.bind('<Up>', up_key) root.bind('<Down>', down_key) root.mainloop()
Comme Bryan l'a souligné ctypes code> est un peu exagéré, mais je voulais laisser cela à tous les curieux de
ctypes
tout de même.
Vous pouvez utiliser ctypes
pour utiliser le clavier et j'ai copié une structure ctypes
bien connue et créé une interface graphique tkinter simple pour illustrer comment vous pouvez lier les touches fléchées haut et bas pour fonctionner comme des onglets.
Faites-moi savoir si vous avez des questions.
import tkinter as tk root = tk.Tk() entry_list = [] def move_entry(x): entry_list[x].focus() for i in range(5): entry_list.append(tk.Entry(root)) entry_list[-1].pack() if i == 0: entry_list[-1].bind('<Down>', lambda e, x=i: move_entry(x + 1)) elif i == 4: entry_list[-1].bind('<Up>', lambda e, x=i: move_entry(x - 1)) else: entry_list[-1].bind('<Up>', lambda e, x=i: move_entry(x - 1)) entry_list[-1].bind('<Down>', lambda e, x=i: move_entry(x + 1)) root.mainloop()
Ce serait bien de savoir quel est le vote défavorable. Cela fonctionne avec les ctypes.
ctypes est exagéré et ne fonctionne que sur Windows. Ce n'est pas une bonne solution à usage général.
J'étais également à la recherche d'une solution plus simple utilisant une liste pour héberger les champs de saisie. Je mettrai à jour ma réponse avec des options supplémentaires.
@BryanOakley J'ai ajouté une solution plus simple qui n'implique pas de ctypes
à ma réponse. J'ai laissé l'autre exemple à tous ceux qui voulaient tout de même y jeter un œil.
Vous pouvez utiliser bind
et focus
:
Tkinter fournit un mécanisme puissant pour vous permettre de gérer les événements toi même. Pour chaque widget, vous pouvez lier des fonctions et des méthodes Python aux événements.
from tkinter import * class Interface_graphique(Frame): def __init__(self, root, **kwargs): Frame.__init__(self, root, width=768, height=576, **kwargs) self.pack(fill=BOTH) self.message_1 = Label(self, text="value1") self.message_1.grid(row=0, sticky='w') self.entry_1 = Entry(self) self.entry_1.grid(row=0, column=1) self.message_2 = Label(self, text="value2") self.message_2.grid(row=1, sticky='w') self.entry_2 = Entry(self) self.entry_2.grid(row=1, column=1) root.bind('<Down>', self.downKey) root.bind('<Up>', self.upKey) def downKey(self, event): self.entry_2.focus() def upKey(self, event): self.entry_1.focus() root = Tk() interface = Interface_graphique(root) interface.mainloop()Si un événement correspondant à la description de l'événement se produit dans le widget, le le gestionnaire donné est appelé avec un objet décrivant l'événement.
.
Dirigez le focus d'entrée vers ce widget.
widget.focus()Si l'application n'a actuellement pas le focus, ce widget obtenir le focus si l'application obtient le focus via la fenêtre gestionnaire.
widget.bind(event, handler)
En bref, créez une reliure qui déplace le focus où vous le souhaitez. Il existe de nombreuses façons de procéder. Si vous n'avez que deux widgets, vous pouvez coder en dur les widgets. Cependant, tkinter permet de fournir assez facilement une solution générale qui fonctionnera toujours dans chaque widget d'entrée.
Lorsque vous créez une liaison, la fonction liée recevra un objet représentant l'événement. L'un des attributs de cet objet est le widget qui a capturé l'événement. Ce widget a une méthode nommée tk_focusNext
qui renverra le widget suivant dans l'ordre de focus standard.
Vous pouvez ajouter une liaison à tous les widgets d'entrée qui utilisent cette fonction pour changer le focus . Dans l'exemple suivant, nous lions la flèche vers le bas à la classe de widget Entry
pour appeler une fonction qui déplace le focus
Commencez par créer une méthode qui peut être liée à l'événement :
self.entry_1.bind("<Down>", self.next_widget) self.entry_2.bind("<Down>", self.next_widget)
Ensuite, utilisez ceci pour vous lier à chaque widget d'entrée:
root.bind_class("Entry", "<Down>", self.next_widget)
ou , liez à chaque widget d'entrée individuel:
def next_widget(self, event): event.widget.tk_focusNext().focus() return "break"
J'essaye de faire la même chose avec un cadre défilé mais ça ne marche pas. def int (racine): sf = ScrolledFrame (racine, True, True); sf.pack (fill = 'both', expand = True); Label (sf.inner, text = "value1"). Grid (row = 0, sticky = 'w'); entry_1 = Entrée (sf.inner) .grid (ligne = 0, colonne = 1); root.bind_class ("Entrée", "
Je suis désolé, j'ai essayé de créer un bloc de pré-code avec ctrl + K, mais je n'ai pas réussi
Pour le cadre défilé, j'ai remplacé d'abord self par sf, puis par sf.inner mais les deux solutions ne fonctionnent pas
@Ing:: "ne fonctionne pas" est une phrase inutile, et la section des commentaires n'est pas l'endroit approprié pour poser une nouvelle question ou publier un nouveau code.
J'imagine que c'est possible. Vous devez
.bind ()
la touche fléchée pour exécuter les fonctions TAB et Shift + TAB. Probablement avec ctypes