Как сравнить входы двух записей, используя одну функцию tkinter для группы таких пар записей? - PullRequest
0 голосов
/ 02 июня 2019

Я хочу проверить две записи tkinter.Один называется минимумом, а другой называется максимумом.Конечно, я хочу убедиться, что минимум не превышает максимум.И есть третья запись, называемая приращением, которая должна быть меньше максимальной.Существует 15 таких записей, которые я пытаюсь проверить.

Я пытался использовать цикл for и трассировать textvariable каждой записи.Но внутри цикла for я могу проверить только одно поле ввода.Кроме того, когда я пропускаю проверку для этой конкретной записи, называемой txtCab, он выдает следующее исключение: если я делаю это для всех виджетов, он работает, но иногда завершается неудачей.

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Users\beejb\AppData\Local\Programs\Python\Python37-32\lib\tkinter\__init__.py", line 1705, in __call__
    return self.func(*args)
  File "C:\PROSAIL_5B_Fortran\PROSAIL_5B_FORTRAN\PROSAIL.py", line 191, in min_max
    minVar = eval("self.txtVar_"+ str(wid)+ "_min.get()")
  File "<string>", line 1, in <module>
NameError: name 'self' is not defined

Я использовал следующую функцию проверки:

def min_max(*args):
            alltextFields = ["N","Cab","Car","Cw","Cm","Cbrown", "rsoil0","LIDFa","LIDFb","TypeLIDF","LAI","hspot","tts","tto","psi" ]
            for wid in alltextFields:
                if eval("self." + wid + "_variable.get()"):
                    minVar = eval("self.txtVar_"+ str(wid)+ "_min.get()")
                    maxVar = eval("self.txtVar_"+ str(wid) + "_max.get()")
                    rangeVar = eval("self.txtVar_"+ str(wid) + "_range.get()")
##
##            print((minVar))
##            print((maxVar))
##            print((rangeVar))

            if len(minVar) > 0 and len(maxVar):
                if (minVar) > (maxVar):
                    messagebox.showinfo("Input Error", "Minimum should not be greater than maximum")

            if len(rangeVar) > 0 and len(maxVar) > 0:
                if (rangeVar) > (maxVar) :
                    messagebox.showinfo("Input Error", "Increment cannot exceed maximum limit")

##            print(self.txtVar_Cab_min.get()); print(self.txtVar_Cab_max.get());
##            print(self.txtVar_N_min.get()); print(self.txtVar_N_max.get());
            if len(self.txtVar_Cab_min.get()) > 0 and len(self.txtVar_Cab_max.get()) > 0 and len(self.txtVar_Cab_range.get()) > 0:
                if (self.txtVar_Cab_min.get()) > (self.txtVar_Cab_max.get()):
                    messagebox.showinfo("Input Data Error", "Minimum should not be greater than maximum!!")
                if (self.txtVar_Cab_range.get()) > (self.txtVar_Cab_max.get()):
                    messagebox.showinfo("Error", "Increment cannot exceed maximum!!")

Еще одна функция проверки, которую я пробовал:

    def validateMRM(self,value, text,W):
        vMin,vMax,vRange;
        entry = self.controller.nametowidget(W)
        print(entry)
        if entry == self.txt_N_min:
            print(entry.get())
            print(self.txtVar_N_max.get())
            print(self.txtVar_N_range.get())
        alltextFields = ["txt_N","txt_Cab","txt_Car","txt_Cab","txt_Cw","txt_Cw","txt_Cm","txt_Cbrown","txt_Cm", "txt_rsoil0",
                                    "txt_LIDFa","txt_LIDFb","txt_TypeLIDF","txt_LAI","txt_hspot","txt_hspot","txt_tts","txt_tto","txt_psi"
                                ]
        for wid in alltextFields:
            typeOfVar = wid.split("_")

            if entry == eval("self.txt_" + str(typeOfVar[1])+ "_min"):
                vMin = eval("self.txtVar_" + str(typeOfVar[1])+ "_min.get()")
                print(eval("self.txtVar_" + str(typeOfVar[1])+ "_min.get()"))
                vMax = eval("self.txtVar_" + str(typeOfVar[1])+ "_max.get()")
                print(eval("self.txtVar_" + str(typeOfVar[1])+ "_max.get()"))
                vRange = eval("self.txtVar_" + str(typeOfVar[1])+ "_range.get()")
                print(eval("self.txtVar_" + str(typeOfVar[1])+ "_range.get()"))

        print(vMin); print(vMax); print(vRange)

        if len(vMin) > 0 and len(vMax) > 0 and len(vRange) > 0:
            if (vMin) > (vMax):
                messagebox.showinfo("Error", "Minimum cannot be greater than maximum")
            if (vRange) > (vMax) :
                messagebox.showinfo("Error", "Increment cannot exceed the maximum limit")        
        print(len(entry.get()))
        if len(entry.get())>2:

И вот как создаются все записи:

 self.lbl_N = tk.Label(self,text="Structure Coefficient(N)",anchor="w",width=40,bg='white'); self.lbl_N.grid(row=3,column=4,padx=4,pady=4);
        self.N_variable = tk.BooleanVar()
        self.chk_N = tk.Checkbutton(self,variable=self.N_variable, command=lambda:self.show_hide()); self.chk_N.grid(row=3,column=6,padx=4,pady=4);
        self.txt_N = tk.Entry(self,width=10,validate = 'key', validatecommand = vcmd); self.txt_N.grid(row=3,column=7,padx=4,pady=4);

        self.txtVar_N_min = tk.StringVar(); self.txtVar_N_max = tk.StringVar(); self.txtVar_N_range = tk.StringVar();
        self.txtVar_N_min.trace("w", min_max); self.txtVar_N_max.trace("w", min_max); self.txtVar_N_range.trace("w", min_max);

        self.txt_N_min = tk.Entry(self,width=5,validate = 'key',textvariable=self.txtVar_N_min, validatecommand = vcmd_min_max);
        self.txt_N_max = tk.Entry(self,width=5,validate = 'key', textvariable=self.txtVar_N_max,validatecommand = vcmd_min_max);
        self.txt_N_range = tk.Entry(self,width=5,validate = 'key', textvariable=self.txtVar_N_range,validatecommand = vcmd_min_max); 

Есть набор из четырнадцати таких записей, и мне нужно проверить каждую из них.

Но ничего из этого не дает желаемого результата.Это работает некоторое время и терпит неудачу некоторые другие времена.Я не уверен, почему это происходит, и я потратил немало времени на эту проверку.

Ответы [ 2 ]

0 голосов
/ 16 июня 2019

Вот еще одно предложение. Включите метку и запись в функцию row-n. Включите активацию / отключение записи в функцию активации. Функция row_n выполняется в цикле по списку желаемых описаний.

import tkinter as tk

row_names = [ "Structure Coefficient(N)", "Chlorophyll Content(Cab) (µg.cm-2)", 
              "Carotenoid content(Car) (µg.cm-2)", "Brown pigment content(Cbrown)(arbitrary units)"]

def row_n(parent, desc, n, init_show = 0 ):
    """ Create one row of the display. """
    # tk.Variables
    v_show = tk.IntVar()
    v_min = tk.StringVar()
    v_max = tk.StringVar()
    v_incr = tk.StringVar()
    v_fixed = tk.StringVar() # New StringVar
    v_message = tk.StringVar()
    v_show.set(init_show)
    v_message.set("OK")

    def do_trace(*args):
        """ Runs every time any of the three Entries change value. 
            Sets the message to the appropriate text.
        """
        lo = to_float(v_min.get())
        hi = to_float(v_max.get())
        inc = to_float(v_incr.get())
        if lo < hi and inc <=hi:
            v_message.set('OK')
        else:
            txt = ''
            if lo >= hi: 
                txt += 'Min >= Max'
            if inc > hi:
                if len(txt): txt += ' & '
                txt += 'Incr > Max'
            v_message.set(txt)

    # Set trace callback for changes to the three StringVars
    v_min.trace('w', do_trace)
    v_max.trace('w', do_trace)
    v_incr.trace('w', do_trace)

    def activation(*args):
        """ Runs when the tickbox changes state """
        if v_show.get():
            e_min.grid(row = n, column = 8)
            e_max.grid(row = n, column = 9)
            e_inc.grid(row = n, column = 10)
            message.grid(row = n, column = 11)
            e_fixed.config(state = 'disabled') # Disable the base Entry

        else:
            e_min.grid_remove()
            e_max.grid_remove()
            e_inc.grid_remove()
            message.grid_remove()
            e_fixed.config(state = 'normal') # Enable the base Entry Widget

    tk.Label(parent, text = desc ).grid(row = r+1, column = 4 ) # Add the desc. Label
    e_fixed = tk.Entry(parent, textvariable = v_fixed) # Add the new Entry widget
    e_fixed.grid(row = r+1, column = 5)
    tk.Checkbutton(parent, 
        text = ' '.format(n), 
        variable = v_show, command = activation ).grid(row = n, column = 6)
    e_min = tk.Entry(parent, width=5, textvariable = v_min)
    e_min.config(font=('Candara', 15))
    e_max =tk.Entry(parent, width=5, textvariable = v_max)
    e_max.config(font=('Candara', 15))
    e_inc = tk.Entry(parent, width=5, textvariable = v_incr)
    e_inc.config(font=('Candara', 15))
    message = tk.Label(parent, width=-15, textvariable = v_message)
    message.config(font=('Candara', 15))
    activation()

    return { 'Min': v_min, 'Max': v_max, 'Inc': v_incr, 'Fixed': v_fixed }
    #  The 'Fixed' field added to the dictionary to return

def print_row(row):
    fmt = 'Min: {}, Max: {}, Inc: {}, Fixed: {}'
    print(fmt.format(
        row['Min'].get(), row['Max'].get(), row['Inc'].get(), row['Fixed'].get() 
    ))

def to_float(txt):

    """ Safely convert any string to a float.  Invalid strings return 0.0 """ 
    try:
        return float(txt)
    except ValueError: 
        return 0.0

# GUI Start
root = tk.Tk()
root.title('Validation wth Trace')

# Header Labels
tk.Label(root,text="Min").grid(row=0,column=8,padx=4,pady=4)
tk.Label(root,text="Max").grid(row=0,column=9,padx=4,pady=4)
tk.Label(root,text="Inc").grid(row=0,column=10,padx=4,pady=4)

# Body of rows
rows = []
for r, r_text in enumerate(row_names):
    rows.append(row_n( root, r_text, r+1))

root.mainloop()

print("Strings in the Entry fields")
for r, row in enumerate(rows):
    print('Row: ', r, 'Data:', end=' ')
    print_row(row)

НТН. Увидев свой код в подписанном вопросе, вы можете предпочесть сделать row_n классом.

0 голосов
/ 02 июня 2019

Я не уверен, отвечает ли это на ваш вопрос, но оно должно указывать вам правильное направление.

Я не мог разобраться в вашем коде.Я создал 15 столбцов х 4 сетки столбца.4-й столбец - это сообщение о том, что 3 поля рядом с ним «ОК» или, если нет, указывают на проблему.Проверка выполняется по всей сетке для каждого нажатия клавиши.Если это слишком медленно, кнопка проверки может запустить проверку вместо этого.

import tkinter as tk
from tkinter import ttk

def rec(): return {'lo': 0, 'hi': 0, 'step': 0, 'ok': '' }

root = tk.Tk()
root.title('SO Question')

def entry(id, ent_dict, var_dict, v=0):
    """ Add an Entry Widget to the root, with associated StringVar."""
    var_dict[id] = tk.StringVar()
    var_dict[id].set(str(v))
    ent_dict[id] = ttk.Entry(root, textvariable= var_dict[id], width = 10 )
    return ent_dict[id]

def do_validate(lo, hi, step):
    """ Return OK if lo, hi and step are consistent else an error string. """
    if lo < hi and step < hi: return 'OK'
    txt = ''
    if lo >= hi: 
        txt = 'lo >= hi. ' 
    if step >= hi:
        txt += 'step >= hi.'
    return txt 

def conv(txt):
    """ Convert text to float.  Return 0.0 if not valid float e.g "" or 'a' """
    try: 
        return float(txt)
    except ValueError:
        return 0.0 

def oklabel(ent_dict, var_dict):
    """ Add an OK Label to a row. """
    lo = conv(var_dict['lo'].get())
    hi = conv(var_dict['hi'].get())
    step = conv(var_dict['step'].get())
    var_dict['ok'] = tk.StringVar()
    var_dict['ok'].set(do_validate(lo, hi, step))
    ent_dict['ok'] = ttk.Label(root, textvariable = var_dict['ok'], width = -17)
    return ent_dict['ok']  # Return the Label object for gridding. 

def do_check(*args):
    """ Loop through the rows setting the validation string in each one. """ 
    for var_dict in stringvars:
        lo = conv(var_dict['lo'].get())
        hi = conv(var_dict['hi'].get())
        step = conv(var_dict['step'].get())
        var_dict['ok'].set(do_validate(lo, hi, step))

# Add column labels
ttk.Label(root, text='Minimums').grid(row=0, column=0)
ttk.Label(root, text =' Maximums').grid(row=0, column=1)
ttk.Label(root, text='Increment').grid(row=0, column=2)
ttk.Label(root, text='Valid').grid(row=0, column=3)

# Create containers for he Entries and Stringvars
entries =[]
stringvars = []

# Add 15 rows of Entries / Validation Labels to the UI. 
for row in range(1, 16):
    tempe=rec()
    tempv=rec()       
    entry('lo', tempe, tempv, 0).grid(row = row, column=0)
    entry('hi', tempe, tempv, 0).grid(row = row, column=1)
    entry('step', tempe, tempv, 0).grid(row = row, column=2)
    oklabel(tempe, tempv).grid(row = row, column = 3)
    entries.append(tempe)
    stringvars.append(tempv)

# Bind do_check to all Entry widgets.
root.bind_class('TEntry', '<KeyPress>', do_check, add='+')
root.bind_class('TEntry', '<BackSpace>', do_check, add='+')
root.bind_class('TEntry', '<Delete>', do_check, add='+')

root.mainloop()

В прошлом я застревал, пытаясь проверить несколько полей, не допуская несогласованные записи.Пользователям трудно следить за тем, что требуется для исправления полей.Они должны работать в правильном порядке.например, lo = 100, hi = 9 и step = 1. Должен ли пользовательский интерфейс разрешать удаление последнего нуля в 100, оставляя 10, что составляет gt 9?

Это может быть расширено, чтобы активировать 'Next'Кнопка, только если все строки в порядке.

Редактировать 1 - Ответ на комментарий

Имеется функция для создания и активации каждой строки дисплея.Каждая строка имеет свои переменные и функцию проверки.Они запускаются трассировкой на трех Entry StringVars, нет необходимости использовать validate.

import tkinter as tk
from tkinter import ttk

def to_float(txt):
    """ Safely convert any string to a float.  Invalid strings return 0.0 """ 
    try:
        return float(txt)
    except ValueError: 
        return 0.0

def row_n( parent, n, init_show = 0 ):
    """ Create one row of the display. """
    # tk.Variables
    v_show = tk.IntVar()
    v_min = tk.StringVar()
    v_max = tk.StringVar()
    v_incr = tk.StringVar()
    v_message = tk.StringVar()

    # Initialise variables
    v_min.set('0')
    v_max.set('1')
    v_incr.set('1')  # Can the increment be zero?
    v_show.set(init_show)
    v_message.set("OK")

    def do_trace(*args):
        """ Runs every time any of the three Entries change value. 
            Sets the message to the appropriate text.
        """
        lo = to_float(v_min.get())
        hi = to_float(v_max.get())
        inc = to_float(v_incr.get())
        if lo < hi and inc <=hi:
            v_message.set('OK')
        else:
            txt = ''
            if lo >= hi: 
                txt += 'Min >= Max'
            if inc > hi:
                if len(txt): txt += ' & '
                txt += 'Incr > Max'
            v_message.set(txt)

    # Set trace callback for changes to the three StringVars
    v_min.trace('w', do_trace)
    v_max.trace('w', do_trace)
    v_incr.trace('w', do_trace)

    def activation(*args):
        """ Runs when the tickbox changes state """
        if v_show.get():
            e_min.grid(row = n, column = 1)
            e_max.grid(row = n, column = 2)
            e_inc.grid(row = n, column = 3)
            message.grid(row = n, column = 4)
        else:
            e_min.grid_remove()
            e_max.grid_remove()
            e_inc.grid_remove()
            message.grid_remove()

    tk.Checkbutton(parent, 
        text = 'Structure Coefficient {} :'.format(n), 
        variable = v_show, command = activation ).grid(row = n, column = 0)
    e_min = tk.Entry(parent, width=5, textvariable = v_min)
    e_max =tk.Entry(parent, width=5, textvariable = v_max)
    e_inc = tk.Entry(parent, width=5, textvariable = v_incr)
    message = tk.Label(parent, width=-15, textvariable = v_message)
    activation()

    return { 'Min': v_min, 'Max': v_max, 'Inc': v_incr }

def show_results():
    print('Min   Max  Inc')
    for row in rows:
        res = '{}   {}  {}'.format(row['Min'].get(), row['Max'].get(), row['Inc'].get())
        print( res )

root = tk.Tk()
root.title('SO Question')

ttk.Label(root, text='Minimums').grid(row=0, column=1)
ttk.Label(root, text =' Maximums').grid(row=0, column=2)
ttk.Label(root, text='Step', width = 5 ).grid(row=0, column=3)
ttk.Label(root, text='Valid', width = 15 ).grid(row=0, column=4)

rows = []
for r in range(1,16):
    rows.append(row_n(root, r, init_show=r%3 == 0 ))

tk.Button(root, command=show_results, text = '  Show Results  ').grid(column=1, pady = 5)

root.mainloop()

Это другой подход.Помогает ли это.

...