ইন্টারেক্টিভভাবে টিকিনটারে এন্ট্রি উইজেট সামগ্রী বৈধকরণ


85

টিকিনটার Entryউইজেটে ইন্টারেক্টিভভাবে সামগ্রী বৈধকরণের জন্য প্রস্তাবিত কৌশলটি কী ?

আমি ব্যবহার সম্পর্কে পোস্টগুলি পড়েছি validate=Trueএবং validatecommand=command, এবং এটি মনে হচ্ছে যে এই বৈশিষ্ট্যগুলি সত্য যদি তারা সাফ করুন দ্বারা সীমাবদ্ধ validatecommandকমান্ড আপডেট Entryউইজেট এর মান।

এই আচরণ দেওয়া, আমরা বাঁধে উচিত KeyPress, Cutএবং Pasteঘটনা এবং মনিটর / আপডেট আমাদের Entryউইজেট মান এই ঘটনা মাধ্যমে? (এবং অন্যান্য সম্পর্কিত ইভেন্টগুলি যা আমি সম্ভবত মিস করেছি?)

বা আমাদের কী ইন্টারেক্টিভ বৈধতা পুরোপুরি ভুলে যাওয়া উচিত এবং কেবল FocusOutইভেন্টগুলিতে বৈধতা দেওয়া উচিত ?

উত্তর:


222

সঠিক উত্তরটি হ'ল, validatecommandউইজেটের বৈশিষ্ট্যটি ব্যবহার করুন । দুর্ভাগ্যক্রমে এই বৈশিষ্ট্যটি টিন্টেটার বিশ্বে মারাত্মকভাবে নীচে নথিভুক্ত করা হয়েছে, যদিও এটি যথেষ্ট পরিমাণে টক দুনিয়ায় ডকুমেন্টেড। যদিও এটি যথাযথভাবে নথিভুক্ত করা হয়নি, তবে আপনার কাছে বাইন্ডিংগুলি বা ভেরিয়েবলগুলি সন্ধান না করা বা বৈধতা প্রক্রিয়াটির মধ্যে থেকে উইজেটটি সংশোধন না করে যাচাইকরণের যা কিছু দরকার তা রয়েছে।

কৌশলটি হ'ল এটি আপনার জালিয়াতি কমান্ডের বিশেষ মানগুলিতে টিন্টার পাস থাকতে পারে তা জানতে। এই মানগুলি আপনাকে ডেটা বৈধ কিনা তা সিদ্ধান্ত নেওয়ার জন্য আপনার প্রয়োজনীয় সমস্ত তথ্য দেয়: সম্পাদনার পূর্বে মান, সম্পাদনাটি বৈধ হলে সম্পাদনার পরে মান এবং অন্যান্য বেশ কয়েকটি তথ্যের বিট। এগুলি ব্যবহার করার জন্য, আপনার বৈধতা আদেশের কাছে এই তথ্যটি পাস করার জন্য আপনাকে কিছুটা ভুডু করতে হবে।

দ্রষ্টব্য: বৈধতা কমান্ডটি ফেরত দেয় 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পদ্ধতিটি কল করেন তখন ফণাটির নীচে কী ঘটে যায় সে সম্পর্কে আরও তথ্যের জন্য , ইনপুট বৈধতা টিকিন্টার দেখুন


16
এটি করার সঠিক উপায় এটি। এটি jmeyer10 এর উত্তর কাজ করার চেষ্টা করার সময় আমি যে সমস্যাগুলি পেয়েছিলাম তা সরিয়ে দেয়। আমি অন্য কোথাও দেখতে পাচ্ছি তার তুলনায় এই উদাহরণটি বৈধতা দেওয়ার জন্য উচ্চতর ডকুমেন্টেশন সরবরাহ করে। আমি ইচ্ছুক এই 5 ভোট দিতে পারে।
স্টিভেন রাম্বালস্কি

4
কি দারুন! আমি স্টিভেনের সাথে একমত - এটি এই ধরণের জবাব যা একাধিক ভোটের জন্য প্রাপ্য। টিন্টেটারে আপনার একটি বই লিখতে হবে (এবং এটি ইতিমধ্যে একটি বহু-ভলিউম সিরিজ করার জন্য যথেষ্ট সমাধান পোস্ট করেছেন)। ধন্যবাদ!!!
ম্যালকম

4
উদাহরণের জন্য ধন্যবাদ। এটি লক্ষণীয় যে বৈধতা কম্যান্ডের একটি বুলিয়ান প্রদান করতে হবে (কেবল সত্য এবং মিথ্যা)। যদি তা না হয় তবে বৈধতা সরানো হবে।
ডেভ বাচার

4
আমি মনে করি এই পৃষ্ঠাটি সামনে আনা উচিত।
ডান পায়ে

4
"টিনকিটার বিশ্বে মারাত্মকভাবে নথিভুক্ত"। এলওএল - টিকিইন্টার বিশ্বের প্রায় সমস্ত জায়গার মতো।
মার্টিনো

21

ব্রায়ানের কোড নিয়ে অধ্যয়ন এবং পরীক্ষার পরে, আমি ইনপুট বৈধতার ন্যূনতম সংস্করণ উত্পাদন করেছি। নিম্নলিখিত কোডটি একটি এন্ট্রি বাক্স রাখবে এবং কেবল সংখ্যাগুলি গ্রহণ করবে।

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()

সম্ভবত আমার যুক্ত করা উচিত যে আমি এখনও পাইথন শিখছি এবং আমি যে কোনও এবং সমস্ত মন্তব্য / পরামর্শ সানন্দে গ্রহণ করব।


4
সাধারণত লোকেরা পরিবর্তে ব্যবহার করে entry.configure(validatecommand=...)এবং লেখেন তবে এটি একটি ভাল, সাধারণ উদাহরণ। test_valtestVal
wizzwizz4

10

Tkinter.StringVarএন্ট্রি উইজেটের মান ট্র্যাক করতে একটি ব্যবহার করুন । এটিতে StringVarএকটি সেট করে আপনি এর মানটি যাচাই করতে পারেন trace

এখানে একটি সংক্ষিপ্ত কার্যকারী প্রোগ্রাম যা এন্ট্রি উইজেটে কেবল বৈধ ফ্লোট গ্রহণ করে।

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()

4
আপনার পোস্টের জন্য ধন্যবাদ। টিনেটার স্ট্রিংওভার .ট্রেস () পদ্ধতি ব্যবহারে দেখে আমি উপভোগ করেছি।
ম্যালকম

কোন ধারণা কেন আমি সম্ভবত এই ত্রুটি পেতে পারি? "NameError: নাম 'বৈধতা নির্ধারণ করা হয় না"
আর্মেন ​​সানোয়ান

4

ব্রায়ান ওকলির উত্তর অধ্যয়ন করার সময় , আমাকে কিছু বলেছিল যে আরও সাধারণ সমাধান বিকাশ করা যেতে পারে। নিম্নলিখিত উদাহরণটি একটি মোড গণনা, একটি টাইপ অভিধান এবং বৈধতার উদ্দেশ্যে একটি সেটআপ ফাংশন উপস্থাপন করে। উদাহরণস্বরূপ ব্যবহারের জন্য 48 লাইনটি দেখুন এবং এর সরলতার জন্য একটি প্রদর্শন করুন।

#! /usr/bin/env python3
# /programming/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()

4

ব্রায়ানের উত্তর সঠিক, তবে কেউ টিন্টার উইজেটের 'অবৈধ কম্যান্ড' বৈশিষ্ট্যটি উল্লেখ করেনি।

একটি ভাল ব্যাখ্যা এখানে: http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/entry-validation.html

ভাঙা লিঙ্কের ক্ষেত্রে পাঠ্য অনুলিপি / আটকানো

এন্ট্রি উইজেটটি একটি অবৈধ কম্যান্ড বিকল্পকে সমর্থন করে যা একটি কলব্যাক ফাংশন নির্দিষ্ট করে যা যখনই বৈধতা কম্যান্ড মিথ্যা প্রত্যাবর্তন করে তখনই ডাকা হয়। এই কমান্ডটি উইজেটের সম্পর্কিত পাঠ্য পরিবর্তনযোগ্যটিতে .set () পদ্ধতিটি ব্যবহার করে উইজেটের পাঠ্যকে সংশোধন করতে পারে। এই বিকল্পটি সেট আপ করা বৈধতা কম্যান্ড সেট আপ করার মতোই কাজ করে। আপনার পাইথন ফাংশনটি মোড়ানোর জন্য আপনাকে অবশ্যই .register () পদ্ধতিটি ব্যবহার করতে হবে; এই পদ্ধতিটি মোড়ানো ফাংশনের নামটিকে স্ট্রিং হিসাবে ফিরিয়ে দেয়। তারপরে আপনি সেই স্ট্রিংটিই অবৈধ কম্যান্ড বিকল্পের মান হিসাবে বা পাসওয়ার্ড কোডযুক্ত একটি টুপলের প্রথম উপাদান হিসাবে পাস করবেন।

দ্রষ্টব্য: কেবলমাত্র একটি জিনিস আমি কীভাবে করব তা অনুধাবন করতে পারছি না: আপনি যদি কোনও এন্ট্রিতে বৈধতা যুক্ত করেন এবং ব্যবহারকারী পাঠ্যের একটি অংশ নির্বাচন করে একটি নতুন মান টাইপ করেন তবে মূল মানটি ক্যাপচার এবং পুনরায় সেট করার কোনও উপায় নেই প্রবেশ. এখানে একটি উদাহরণ

  1. এন্ট্রিটি কেবল 'বৈধতা কম্যান্ড' প্রয়োগ করে পূর্ণসংখ্যা গ্রহণ করার জন্য ডিজাইন করা হয়েছে
  2. ব্যবহারকারী 1234567 প্রবেশ করে
  3. ব্যবহারকারী '345' এবং 'j' টিপুন ses এটি দুটি ক্রিয়া হিসাবে নিবন্ধিত: '345' মুছে ফেলা, এবং 'জে' সন্নিবেশ করানো। টিন্টার মুছে ফেলা উপেক্ষা করে এবং কেবল 'জে' সন্নিবেশ করায় কাজ করে। 'ভ্যালিড কম্যান্ড' মিথ্যা ফিরিয়ে দেয় এবং 'অবৈধ কম্যান্ড' ফাংশনে প্রদত্ত মানগুলি নিম্নরূপ:% d = 1,% i = 2,% P = 12j67,% s = 1267,% S = j
  4. যদি কোডটি একটি 'অবৈধ কম্যান্ড' ফাংশন বাস্তবায়ন করে না, তবে 'ভ্যালিডকম্যান্ড' ফাংশনটি 'জে' প্রত্যাখ্যান করবে এবং ফলাফলটি 1267 হবে an কোডটি যদি 'অবৈধ কম্যান্ড' ফাংশনটি প্রয়োগ করে, মূল 1234567 পুনরুদ্ধার করার কোনও উপায় নেই ।

3

এন্ট্রি মানটি যাচাই করার একটি সহজ উপায়, যা ব্যবহারকারীকে কেবলমাত্র অঙ্কগুলি প্রবেশ করতে দেয়:

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

পিএস: এই উদাহরণটি ক্যালকের মতো একটি অ্যাপ তৈরির জন্য খুব দরকারী useful


2
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

4
হাই, স্ট্যাক ওভারফ্লোতে আপনাকে স্বাগতম "কোড-কেবল" উত্তরগুলি ভ্রান্ত হয়, বিশেষত এমন প্রশ্নের উত্তর দেওয়ার সময় যার ইতিমধ্যে অনেক উত্তর রয়েছে। আপনি যে প্রতিক্রিয়া সরবরাহ করছেন তা কোনওভাবেই মজবুত এবং মূল পোস্টার দ্বারা ইতিমধ্যে যা পরীক্ষা করা হয়েছে তা কেবল প্রতিধ্বনিত করছে না দয়া করে কিছু অতিরিক্ত অন্তর্দৃষ্টি যোগ করার বিষয়ে নিশ্চিত হন।
chb

4
@ ডেমিয়ান ওল্ফ আমি আপনার মূল উত্তরের উন্নত সংস্করণটি পছন্দ করেছি তবে আমাকে এটি আবার ফিরে যেতে হয়েছিল। দয়া করে এটিকে নিজের উত্তর হিসাবে পোস্ট করার বিষয়টি বিবেচনা করুন (আপনি এটি পুনর্বিবেচনার ইতিহাসে খুঁজে পেতে পারেন )।
২৩7777

1

পৃথক মুছে ফেলা বা সন্নিবেশের পরিবর্তে বাছাইয়ের মাধ্যমে পাঠ্যের বিকল্পের উপর সাধারণ বৈধতা নিয়ে কাজ করার ওরিওনবার্টের সমস্যার প্রতিক্রিয়া :

নির্বাচিত পাঠ্যের একটি বিকল্প সন্নিবেশের পরে মুছে ফেলা হিসাবে প্রক্রিয়া করা হয়। এটি সমস্যার সৃষ্টি করতে পারে, উদাহরণস্বরূপ, মুছে ফেলা হলে কার্সারটি বামে সরানো উচিত এবং অন্য কোনও বিকল্পটি কার্সারটিকে ডানে সরিয়ে নিয়ে যেতে পারে। ভাগ্যক্রমে, এই দুটি প্রক্রিয়া একে অপরের সাথে সাথেই কার্যকর করা হয়। অতএব, আমরা নিজেই একটি মুছে ফেলা এবং একটি প্রতিস্থাপনের ফলে সরাসরি একটি সন্নিবেশের পরে সরাসরি একটি মুছে ফেলার মধ্যে পার্থক্য করতে পারি কারণ পরবর্তীকালে মোছা এবং সন্নিবেশের মধ্যে নিষ্ক্রিয় পতাকাটি পরিবর্তন হয় না।

এটি সাবস্টিটিউশনফ্ল্যাগ এবং এ ব্যবহার করে শোষণ করা হয় 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 সমন্বয় একটি নতুন অনন্য এবং চূড়ান্ত ঘটনা।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.