Tkinter에서 대화식으로 항목 위젯 컨텐츠 유효성
tkinter Entry
위젯 에서 대화식으로 컨텐츠를하기 위해 권장되는 기술은 무엇입니까?
validate=True
및 사용에, 대한 게시물을 읽었으며 validatecommand=command
이러한 기능 현관은 validatecommand
명령이 Entry
위젯의 값을 업데이트하면 지워진다는 사실로 인해 제한되는 것으로 보입니다 .
이 동작을 감안할 때, 우리는에 결합한다 KeyPress
, Cut
및 Paste
이벤트 모니터 / Entry
업데이트를 통해 위젯의 가치인가? (그리고 내가 놓쳤을 수도있는 기타 관련 이벤트?)
아니면 대화 형 유효성 검사를 완전히 잊어 버리고 FocusOut
이벤트에 유효성을 검사해야 합니까?
정답은 validatecommand
위젯 의 속성을 사용하는 것입니다. 안타깝게도이 기능은 Tkinter 세계에서는 충분히 문서화되어 있지 않지만 Tk 세계에서는 충분히 문서화되어 있습니다. 잘 문서화되어는 없지만 바인딩 또는 추적 변수에 의존하지 않고 유효성 검사 절차 내에서 위젯을 수정하지 않는 유효성 검사를 수행하는 데 필요한 모든 것이 있습니다.
트릭은 Tkinter가 특정 값을 검증하는 것입니다. 이 값은 데이터가 유효한지 여부를 결정하기 위해 필요한 모든 정보를 제공합니다. 편집 전 값, 편집이 유효한 경우 편집 후 값, 기타 여러 정보가 있습니다. 그러나이를 사용하는 경우 비용이 적게 발생합니다.
참고 : 유효성 검사 명령이 True
또는 반환하는 것이 중요합니다 False
. 그 밖의 사항은 위젯에 대한 유효성 검사를 해제합니다.
다음은 소문자 만 허용하고 모든 펑키 값을 인쇄하는 예입니다.
import tkinter as tk # python 3.x
# import Tkinter as tk # python 2.x
class Example(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
# valid percent substitutions (from the Tk entry man page)
# note: you only have to register the ones you need; this
# example registers them all for illustrative purposes
#
# %d = Type of action (1=insert, 0=delete, -1 for others)
# %i = index of char string to be inserted/deleted, or -1
# %P = value of the entry if the edit is allowed
# %s = value of entry prior to editing
# %S = the text string being inserted or deleted, if any
# %v = the type of validation that is currently set
# %V = the type of validation that triggered the callback
# (key, focusin, focusout, forced)
# %W = the tk name of the widget
vcmd = (self.register(self.onValidate),
'%d', '%i', '%P', '%s', '%S', '%v', '%V', '%W')
self.entry = tk.Entry(self, validate="key", validatecommand=vcmd)
self.text = tk.Text(self, height=10, width=40)
self.entry.pack(side="top", fill="x")
self.text.pack(side="bottom", fill="both", expand=True)
def onValidate(self, d, i, P, s, S, v, V, W):
self.text.delete("1.0", "end")
self.text.insert("end","OnValidate:\n")
self.text.insert("end","d='%s'\n" % d)
self.text.insert("end","i='%s'\n" % i)
self.text.insert("end","P='%s'\n" % P)
self.text.insert("end","s='%s'\n" % s)
self.text.insert("end","S='%s'\n" % S)
self.text.insert("end","v='%s'\n" % v)
self.text.insert("end","V='%s'\n" % V)
self.text.insert("end","W='%s'\n" % W)
# Disallow anything but lowercase letters
if S == S.lower():
return True
else:
self.bell()
return False
if __name__ == "__main__":
root = tk.Tk()
Example(root).pack(fill="both", expand=True)
root.mainloop()
register
메서드 를 호출 할 때 내부에서 발생하는 작업에 대한 자세한 내용 은 입력 유효성 검사 tkinter를 참조하세요.
Bryan의 코드를 연구하고 실험 한 후 최소한의 입력 유효성 검사 버전을 생성했습니다. 다음 코드는 입력 상자를 표시하고 숫자 만 허용합니다.
from tkinter import *
root = Tk()
def testVal(inStr,acttyp):
if acttyp == '1': #insert
if not inStr.isdigit():
return False
return True
entry = Entry(root, validate="key")
entry['validatecommand'] = (entry.register(testVal),'%P','%d')
entry.pack()
root.mainloop()
아마도 나는 아직 제안을 배우고 있고 모든 의견 / 제안을 기꺼이 받아 들일 제안을 할 것입니다.
Tkinter.StringVar
항목 위젯의 값을 추적 시작을 사용하십시오 . 에 StringVar
a trace
를 설정하여 의 값을 확인할 수 있습니다 .
다음은 Entry 위젯에서 유효한 수레 만 허용되는 짧은 작업 프로그램입니다.
from Tkinter import *
root = Tk()
sv = StringVar()
def validate_float(var):
new_value = var.get()
try:
new_value == '' or float(new_value)
validate.old_value = new_value
except:
var.set(validate.old_value)
validate.old_value = ''
# trace wants a callback with nearly useless parameters, fixing with lambda.
sv.trace('w', lambda nm, idx, mode, var=sv: validate_float(var))
ent = Entry(root, textvariable=sv)
ent.pack()
root.mainloop()
Bryan Oakley의 답변을 하는 동안 훨씬 더 일반적인 솔루션을 개발할 수있는 내용이 있습니다. 다음 예제에서는 유효성 검사를위한 모드 소개, 유형 사전 및 설정 함수를 소개합니다. 사용 예와 단순성에 대한 데모는 48 행을 참조하십시오.
#! /usr/bin/env python3
# https://stackoverflow.com/questions/4140437
import enum
import inspect
import tkinter
from tkinter.constants import *
Mode = enum.Enum('Mode', 'none key focus focusin focusout all')
CAST = dict(d=int, i=int, P=str, s=str, S=str,
v=Mode.__getitem__, V=Mode.__getitem__, W=str)
def on_validate(widget, mode, validator):
# http://www.tcl.tk/man/tcl/TkCmd/ttk_entry.htm#M39
if mode not in Mode:
raise ValueError('mode not recognized')
parameters = inspect.signature(validator).parameters
if not set(parameters).issubset(CAST):
raise ValueError('validator arguments not recognized')
casts = tuple(map(CAST.__getitem__, parameters))
widget.configure(validate=mode.name, validatecommand=[widget.register(
lambda *args: bool(validator(*(cast(arg) for cast, arg in zip(
casts, args)))))]+['%' + parameter for parameter in parameters])
class Example(tkinter.Frame):
@classmethod
def main(cls):
tkinter.NoDefaultRoot()
root = tkinter.Tk()
root.title('Validation Example')
cls(root).grid(sticky=NSEW)
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
root.mainloop()
def __init__(self, master, **kw):
super().__init__(master, **kw)
self.entry = tkinter.Entry(self)
self.text = tkinter.Text(self, height=15, width=50,
wrap=WORD, state=DISABLED)
self.entry.grid(row=0, column=0, sticky=NSEW)
self.text.grid(row=1, column=0, sticky=NSEW)
self.grid_rowconfigure(1, weight=1)
self.grid_columnconfigure(0, weight=1)
on_validate(self.entry, Mode.key, self.validator)
def validator(self, d, i, P, s, S, v, V, W):
self.text['state'] = NORMAL
self.text.delete(1.0, END)
self.text.insert(END, 'd = {!r}\ni = {!r}\nP = {!r}\ns = {!r}\n'
'S = {!r}\nv = {!r}\nV = {!r}\nW = {!r}'
.format(d, i, P, s, S, v, V, W))
self.text['state'] = DISABLED
return not S.isupper()
if __name__ == '__main__':
Example.main()
Bryan의 대답은하지만 아무도 tkinter 위젯의 'invalidcommand'속 언급하지 않습니다.
좋은 설명은 다음과 가변합니다. http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/entry-validation.html
링크가 더러워진 경우 텍스트 복사 / 가져 오기
항목 위젯은 validatecommand가 False를 반환 할 때마다 호출되는 호출되는 함수를 지정하는 invalidcommand 옵션도 지원합니다. 이 명령은 위젯의 관련 텍스트 변수에서 .set () 메소드를 사용하여 위젯의 텍스트를 사용할 수 있습니다. 이 옵션을 설정하는 것은 명령을 설정하는 것과 동일하게 작동합니다. Python 함수를 래핑합니다. 이 메서드는 래핑 된 함수의 이름을 반환합니다. 그런 다음 포함하는 SSL 또는 대체 코드를 포함하는 튜플의 첫 번째 요소로 invalidcommand 옵션의 값으로 전달합니다.
참고 : 방법을 알아낼 수없는 한 가지만 있습니다. 항목에 유효성 검사를 추가하고 사용자가 텍스트의 일부를 선택하고 새 값을 입력하면 원래 값을 설치하고 사용할 방법이 없습니다. 항목. 여기에 예가 있습니다.
- 항목은 'validatecommand'를 구현하여 정수만 허용하도록 설계되었습니다.
- 사용자가 1234567을 입력합니다.
- 사용자는 '345'를 선택하고 'j'를 선택합니다. 이것은 '345'삭제와 'j'삽입의 두 가지 동작으로 등록됩니다. Tkinter는 삭제를 무시하고 'j'가 삽입 된 경우에만 작동합니다. 'validatecommand'는 False를 반환하고 'invalidcommand'함수에 전달 된 값은 다음과 같습니다. % d = 1, % i = 2, % P = 12j67, % s = 1267, % S = j
- 코드가 'invalidcommand'함수를 구현하지 않으면 'validatecommand'함수는 'j'를 거부하고 결과는 1267이됩니다. 코드가 'invalidcommand'함수를 구현하면 원래 1234567을 복구 할 방법이 없습니다. .
import tkinter
tk=tkinter.Tk()
def only_numeric_input(e):
#this is allowing all numeric input
if e.isdigit():
return True
#this will allow backspace to work
elif e=="":
return True
else:
return False
#this will make the entry widget on root window
e1=tkinter.Entry(tk)
#arranging entry widget on screen
e1.grid(row=0,column=0)
c=tk.register(only_numeric_input)
e1.configure(validate="key",validatecommand=(c,'%P'))
tk.mainloop()
#very usefull for making app like calci
별도의 삭제 또는 삽입 대신 선택을 통해 텍스트를 대체 할 때 간단한 유효성 검사를 처리 하는 orionrobert의 문제 에 대한 응답 :
선택한 텍스트의 대체는 삭제 후 삽입으로 처리됩니다. 예를 들어 삭제하면 커서가 왼쪽으로 이동하고 대체는 커서를 오른쪽으로 이동해야하는 경우 문제가 발생할 수 있습니다. 다행히도이 두 프로세스는 즉시 실행 됩니다. 따라서 후자는 삭제와 삽입 사이에 유휴 시간이 없기 때문에 자체 삭제와 대체로 인해 삽입이 직접 뒤 따르는 삭제를 구별 할 수 있습니다.
이것은 replacementFlag 및 Widget.after_idle()
. after_idle()
이벤트 큐 끝에서 람다 함수를 실행합니다.
class ValidatedEntry(Entry):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.tclValidate = (self.register(self.validate), '%d', '%i', '%P', '%s', '%S', '%v', '%V', '%W')
# attach the registered validation function to this spinbox
self.config(validate = "all", validatecommand = self.tclValidate)
def validate(self, type, index, result, prior, indelText, currentValidationMode, reason, widgetName):
if typeOfAction == "0":
# set a flag that can be checked by the insertion validation for being part of the substitution
self.substitutionFlag = True
# store desired data
self.priorBeforeDeletion = prior
self.indexBeforeDeletion = index
# reset the flag after idle
self.after_idle(lambda: setattr(self, "substitutionFlag", False))
# normal deletion validation
pass
elif typeOfAction == "1":
# if this is a substitution, everything is shifted left by a deletion, so undo this by using the previous prior
if self.substitutionFlag:
# restore desired data to what it was during validation of the deletion
prior = self.priorBeforeDeletion
index = self.indexBeforeDeletion
# optional (often not required) additional behavior upon substitution
pass
else:
# normal insertion validation
pass
return True
물론 대체 후 삭제 부분을 확인하는 동안 삽입이 뒤따를 지 여부를 알 수 없습니다. 다행히 그러나,로 : .set()
, .icursor()
, .index(SEL_FIRST)
, .index(SEL_LAST)
, .index(INSERT)
, 우리가 대상으로 가장 원하는 동작을 얻을 수 있습니다 (삽입과 우리의 새로운 substitutionFlag의 조합은 새로운 독특하고 최종 이벤트이기 때문이다.
다음은 사용자가 숫자 만 입력 할 수있는 입력 값을 확인하는 간단한 방법입니다.
import tkinter # imports Tkinter module
root = tkinter.Tk() # creates a root window to place an entry with validation there
def only_numeric_input(P):
# checks if entry's value is an integer or empty and returns an appropriate boolean
if P.isdigit() or P == "": # if a digit was entered or nothing was entered
return True
return False
my_entry = tkinter.Entry(root) # creates an entry
my_entry.grid(row=0, column=0) # shows it in the root window using grid geometry manager
callback = root.register(only_numeric_input) # registers a Tcl to Python callback
my_entry.configure(validate="key", validatecommand=(callback, "%P")) # enables validation
root.mainloop() # enters to Tkinter main event loop
추신 :이 예제는 calc와 같은 앱을 만드는 데 매우 유용 할 수 있습니다.
참고 URL : https://stackoverflow.com/questions/4140437/interactively-validating-entry-widget-content-in-tkinter
'ProgramingTip' 카테고리의 다른 글
React Router에서 DefaultRoute를 다른 경로로 설정하는 방법 (0) | 2020.10.25 |
---|---|
주어진 값이 일반 목록인지 어떻게 확인합니까? (0) | 2020.10.25 |
ASP.NET MVC 3 Razor 재귀 함수 (0) | 2020.10.25 |
Mac OS X에서 mongod를 중지하는 방법은 무엇입니까? (0) | 2020.10.25 |
div 클래스의 스타일 속성을 변경하는 jquery (0) | 2020.10.25 |