PySimpleGUI / PySimpleGUI

Python GUIs for Humans! PySimpleGUI is the top-rated Python application development environment. Launched in 2018 and actively developed, maintained, and supported in 2024. Transforms tkinter, Qt, WxPython, and Remi into a simple, intuitive, and fun experience for both hobbyists and expert users.
https://www.PySimpleGUI.com
Other
13.47k stars 1.83k forks source link

[Question] My question is how to make an InputText to only accept integers #3268

Closed thothloki closed 4 years ago

thothloki commented 4 years ago

Type of Issues (Question)

Operating System (all)

Python version (3.8)

PySimpleGUI Port and Version (4.19.0)

I am wondering if/how I can set an InputText to only accept numbers/integers. I am relatively new to PySimpleGUI but am coming over from other GUI modules like PyQt, appJar, remi and the like.

jason990420 commented 4 years ago

Here for your reference, not sure is it good for you.

import PySimpleGUI as sg

def valid(text):
    if len(text)==1 and text in '+-':
        return True
    else:
        try:
            number = float(text)
            return True
        except:
            return False

font = ('Helvetica', 20)
layout = [[sg.InputText('', size=(40, 1), font=font, key='-INPUT-', enable_events=True)],
          [sg.Button('Exit', font=font)]]

window = sg.Window('Test', layout)

while True:

    event, values = window.read()
    print(event, values)
    if event in (sg.WINDOW_CLOSED, 'Exit'):
        break
    elif event == '-INPUT-':
        text = values['-INPUT-']
        if not valid(text):
            window['-INPUT-'].update(value=text[:-1])

window.close()
PySimpleGUI commented 4 years ago

Jason's got it right. This is how input validation is done in PySimpleGUI. There is a Cookbook Recipe that shows you one way of doing this that you'll find here: https://pysimplegui.readthedocs.io/en/latest/cookbook/#recipe-input-validation

PySimpleGUI commented 4 years ago

Generally speaking, the quick and dirty way is to use a simple try/except block. Let Python tell you if it's an int.

import PySimpleGUI as sg

layout = [  [sg.Text('Input only int point numbers')],
            [sg.Input(key='-IN-', enable_events=True)],
            [sg.Button('Exit')]  ]

window = sg.Window('Int input validation', layout)

while True:
    event, values = window.read()
    if event in (sg.WIN_CLOSED, 'Exit'):
        break
    # if last character in input element is invalid, remove it
    if event == '-IN-' and values['-IN-']:
        try:
            in_as_int = int(values['-IN-'])
        except:
            if not (len(values['-IN-']) == 1 and values['-IN-'][0] == '-'):
                window['-IN-'].update(values['-IN-'][:-1])
window.close()
thothloki commented 4 years ago

Thank you both!!! I am trying out PySimpleGUI with an app I already wrote with appJar and was just trying to find an equivalent to its NumericEntry()

I will give that a try and see how well it works.

thothloki commented 4 years ago

both of your ways work very well!!! Thank you very very much. Now to just add that to about 100 inputs (for loop, here i come!)

thothloki commented 4 years ago

I know this is probably python 101, using this implementation to validate an input text box. How would/could I make this more generic to handl over 100 boxes?

jason990420 commented 4 years ago

It depend on how you get input for 100 boxes !

For example, you have 100 boxes in window at the same time, you can set key of each box start with 'INT_', like 'INT_01', 'INT_02', ...

layout = [[sg.Input(key=f'INT_{j}{i}', enable_events=True) for i in range(10)] for j in range(10)]

then the loop event handler can be

elif event.startswith('INT_'):
    ...

Difference case maybe with different way to go !

PySimpleGUI commented 4 years ago

You can also use tuples as keys.... key=(i,j).

Or if you don't need a row, col kind of thing and it's just 100 inputs in a row, but you want to know it's an input.... it could be

layout = [[sg.Input(key=('INT', i), enable_events=True) for i in range(100)]]

# event loop...
if hasattr(event, tuple):     # if you will have both strings and tuples as keys, check for tuple first
   if event[0] == 'INT':         # You'll know this is one of the inputs to check for int only
      # do the int check / fixup here

It's the exact same kind of mechanism Jason has shown, but with tuples instead of strings. I do like the string version as it requires only 1 check.

Oh, actually, you can safely use a [ ] index into both a string and a tuple, so you maybe don't check for the tuple, but instead check for the first position being "INT". If it's a string, event[0] will be a single character.

if event[0] == 'INT':         # You'll know this is one of the inputs to check for int only
   # do the int check / fixup here
MCilento93 commented 4 years ago

I know this is probably python 101, using this implementation to validate an input text box. How would/could I make this more generic to handl over 100 boxes?

If useful, I have empowered the code above reported to check from a list of keys if the input is a float or int:

import PySimpleGUI as sg

def valid_float(text):
    if len(text)==1 and text in '+-':
        return True
    else:
        try:
            number = float(text)
            return True
        except:
            return False

def valid_int(text):
    if len(text)==1 and text in '+-':
        return True
    else:
        try:
            number = int(text)
            return True
        except:
            return False

font = ('Helvetica', 20)
layout = [[sg.InputText('', size=(40, 1), font=font, key='-INPUT-', enable_events=True)],
          [sg.InputText('', size=(40, 1), font=font, key='-INPUT2-', enable_events=True)],
          [sg.InputText('', size=(40, 1), font=font, key='-INPUT3-', enable_events=True)],
          [sg.Button('Exit', font=font)]]

window = sg.Window('Test', layout)

while True:

    event, values = window.read()
    if event in (sg.WINDOW_CLOSED, 'Exit'):
        break

    # check input(s): float
    check_float=['-INPUT-','-INPUT2-'] # a list with key(s) to check
    for key in check_float:
        if event == key:
            text = values[key]
            if not valid_float(text):
                window[key].update(value=text[:-1])

    # check input(s): int
    check_int=['-INPUT3-'] # a list with key(s) to check
    for key in check_int:
        if event == key:
            text = values[key]
            if not valid_int(text):
                window[key].update(value=text[:-1])

window.close()