首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Tkinter Spinbox范围验证

Tkinter Spinbox范围验证
EN

Stack Overflow用户
提问于 2015-07-01 10:22:02
回答 3查看 6.1K关注 0票数 2

我试图利用布赖恩奥克利的这个极好的答案,但没有结果(https://stackoverflow.com/a/4140988/5060127).

我想使用相同的方法来验证Spinbox值。我已经定义了from_和spinboxes的值,但是用户仍然可以在其中键入大部分内容.应该验证的是,只有在from_-范围内的值才能由用户输入,并且只能输入整数。

下面的代码显示了我有多远.

代码语言:javascript
复制
try:
    from Tkinter import *
except ImportError:
    from tkinter import *

class GUI:
    def __init__(self):
        # root window of the whole program
        self.root = Tk()
        self.root.title('ImageSound')

        # registering validation command
        vldt_ifnum_cmd = (self.root.register(self.ValidateIfNum),'%s', '%S')

        # creating a spinbox
        harm_count = Spinbox(self.root, from_=1, to=128, width=5, justify='right', validate='all', validatecommand=vldt_ifnum_cmd)
        harm_count.delete(0,'end')
        harm_count.insert(0,8)
        harm_count.pack(padx=10, pady=10)

    def ValidateIfNum(self, s, S):
        # disallow anything but numbers
        valid = S.isdigit()
        if not valid:
            self.root.bell()
        return valid

if __name__ == '__main__':
    mainwindow = GUI()
    mainloop()
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-07-01 11:10:29

我想我找到问题了。验证器函数最初是用S=''调用的,条件是S.isdigit()返回False,函数不再调用。但是在我将条件更新为valid = S == '' or S.isdigit()之后,它就开始像预期的那样工作了。

当然,您可能需要一些更复杂的条件(例如,检查值是否在范围内),但看起来空字符串必须通过(至少是初始的)验证。

票数 2
EN

Stack Overflow用户

发布于 2015-07-01 12:36:05

我做到了!考虑到小部件的from_和值的整数输入和范围检查都是有效的!也许它看起来有点烦人,但它起作用了!以下是任何感兴趣的人的代码:

代码语言:javascript
复制
try:
    from Tkinter import *
except ImportError:
    from tkinter import *

class GUI:
    def __init__(self):
        # root window of the whole program
        self.root = Tk()
        self.root.title('ImageSound')

        # registering validation command
        vldt_ifnum_cmd = (self.root.register(self.ValidateIfNum),'%P', '%S', '%W')

        # creating a spinbox
        harm_count = Spinbox(self.root, from_=1, to=128, width=5, justify='right', validate='all', validatecommand=vldt_ifnum_cmd)
        harm_count.insert(0,8)
        harm_count.delete(1,'end')
        harm_count.pack(padx=10, pady=10)

    def ValidateIfNum(self, user_input, new_value, widget_name):
        # disallow anything but numbers in the input
        valid = new_value == '' or new_value.isdigit()
        # now that we've ensured the input is only integers, range checking!
        if valid:
            # get minimum and maximum values of the widget to be validated
            minval = int(self.root.nametowidget(widget_name).config('from')[4])
            maxval = int(self.root.nametowidget(widget_name).config('to')[4])
            # check if it's in range
            if int(user_input) not in range (minval, maxval):
                valid = False
        if not valid:
            self.root.bell()
        return valid

if __name__ == '__main__':
    mainwindow = GUI()
    mainloop()

我注意到的一件事是,如果你选择了整个文本,然后粘贴一些错误的东西,比如文本,那就不太管用了。这完全破坏了验证。呃。

票数 1
EN

Stack Overflow用户

发布于 2018-08-19 03:36:32

我已经想出了一个解决方案,它适用于任何入口小部件,因此也适用于SpinBox。它使用validatecommand来确保只输入正确的值。一个空白条目被暂时验证,但是在FocusOut上它会更改回最后一个有效值。

intvalidate.py

代码语言:javascript
复制
import tkinter as tk


def int_validate(entry_widget, limits=(None, None)):
    """
    Validates an entry_widget so that only integers within a specified range may be entered

    :param entry_widget: The tkinter.Entry widget to validate
    :param limits: The limits of the integer. It is given as a (min, max) tuple

    :return:       None
    """
    num_str = entry_widget.get()
    current = None if (not _is_int(num_str)) else int(num_str)
    check = _NumberCheck(entry_widget, limits[0], limits[1], current=current)
    entry_widget.config(validate='all')
    entry_widget.config(validatecommand=check.vcmd)
    entry_widget.bind('<FocusOut>', lambda event: _validate(entry_widget, check))
    _validate(entry_widget, check)


def _is_int(num_str):
    """
    Returns whether or not a given string is an integer

    :param num_str: The string to test

    :return: Whether or not the string is an integer
    """
    try:
        int(num_str)
        return True
    except ValueError:
        return False


def _validate(entry, num_check):
    """
    Validates an entry so if there is invalid text in it it will be replaced by the last valid text

    :param entry: The entry widget
    :param num_check: The _NumberCheck instance that keeps track of the last valid number

    :return:    None
    """
    if not _is_int(entry.get()):
        entry.delete(0, tk.END)
        entry.insert(0, str(num_check.last_valid))


class _NumberCheck:
    """
    Class used for validating entry widgets, self.vcmd is provided as the validatecommand
    """

    def __init__(self, parent, min_, max_, current):
        self.parent = parent
        self.low = min_
        self.high = max_
        self.vcmd = parent.register(self.in_integer_range), '%d', '%P'

        if _NumberCheck.in_range(0, min_, max_):
            self.last_valid = 0
        else:
            self.last_valid = min_
        if current is not None:
            self.last_valid = current

    def in_integer_range(self, type_, after_text):
        """
        Validates an entry to make sure the correct text is being inputted
        :param type_:        0 for deletion, 1 for insertion, -1 for focus in
        :param after_text:   The text that the entry will display if validated
        :return:
        """

        if type_ == '-1':
            if _is_int(after_text):
                self.last_valid = int(after_text)

        # Delete Action, always okay, if valid number save it
        elif type_ == '0':
            try:
                num = int(after_text)
                self.last_valid = num
            except ValueError:
                pass
            return True

        # Insert Action, okay based on ranges, if valid save num
        elif type_ == '1':
            try:
                num = int(after_text)
            except ValueError:
                if self.can_be_negative() and after_text == '-':
                    return True
                return False
            if self.is_valid_range(num):
                self.last_valid = num
                return True
            return False
        return False

    def can_be_negative(self):
        """
        Tests whether this given entry widget can have a negative number

        :return: Whether or not the entry can have a negative number
        """
        return (self.low is None) or (self.low < 0)

    def is_valid_range(self, num):
        """
        Tests whether the given number is valid for this entry widgets range

        :param num: The number to range test

        :return: Whether or not the number is in range
        """
        return _NumberCheck.in_range(num, self.low, self.high)

    @staticmethod
    def in_range(num, low, high):
        """
        Tests whether or not a number is within a specified range inclusive

        :param num: The number to test if its in the range
        :param low: The minimum of the range
        :param high: The maximum of the range

        :return: Whether or not the number is in the range
        """
        if (low is not None) and (num < low):
            return False
        if (high is not None) and (num > high):
            return False
        return True

它被用作

代码语言:javascript
复制
import tkinter as tk
from tkinter import ttk

from intvalidate import int_validate

if __name__ == '__main__':
    root = tk.Tk()
    var = tk.DoubleVar()
    widget = ttk.Spinbox(root, textvariable=var, justify=tk.CENTER, from_=0, to_=10)
    widget.pack(padx=10, pady=10)
    int_validate(widget, limits=(0, 10))
    root.mainloop()
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/31158668

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档