Tkinter генерирует новые строки полей ввода, не отвечающие на вызов кнопки

#python #tkinter

#python #tkinter

Вопрос:

Я пытаюсь создать интерфейс базы данных SQLite, используя python и Tkinter для хранения результатов тестов. По сути, пользователь сначала выбирает опцию из выпадающего меню (панель меню Tkinter), которая генерирует форму с 6 предопределенными тестами для сбора входных данных. Входные данные из этих полей ввода затем сохраняются в SQLite, где каждая строка / тест хранится в отдельной таблице. Будут протестированы разные материалы, но тесты одинаковы для каждого. Я хочу сравнить одни и те же результаты тестирования для нескольких материалов на более позднем этапе для моделирования тенденций и т.д.

Итак, моя идея заключается в том, что строка меню вызывает функцию (которая определяет категорию теста, например, board_strength) для создания формы с датой и номером проекта и которая выполняет макет. Класс используется для генерации полей ввода, получения входных данных, вычисления среднего значения и сохранения значений в SQLite после заполнения каждой строки. Если пользователю требуется дополнительная строка для того же теста, кнопка должна добавить ее по мере необходимости. Затем, если пользователь переходит к следующему тесту (возможно, с помощью кнопки ..), у них снова есть возможность добавить еще одну строку для этого теста и так далее. Здесь я показал только 1 тест, и т.д., но есть еще 5.

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

 from tkinter import *
import tkinter as tk

date = datetime.date.today()

class create_widgets:
    '''create widgets for input data, collect input, determine average, and store'''
    def __init__(self, window, test_name, units, row):
        self.window = root
        self.test_name = ''
        self.units = ''
        self.row = 0
        self.add_entry(window, test_name, units, row)
      
    def add_entry(self, window, test_name, units, row):
        self.entries = []

        lbl_of_test = Label(window, text = f'{test_name} ({units}):', font = ('Arial', 10))
        lbl_of_test.grid(row = row, column = 0)

        for i in range(3):
            self.entry = Entry(window, width=8)
            self.entry.grid(row=row, column=i 1)
            self.entries.append(self.entry)

def board_strength():
    ''' Add project details and date and generate test labels'''
    lbl1 = Label(top_frame, text = 'Board Strength Properties', font = ('Arial Bold', 12))
    lbl1.pack(side = 'top')
    display_date = Label(top_frame, text = f'Date: {date}', font = ('Arial', 10))
    display_date.pack(anchor = 'w')
    sample_lable = Label(top_frame, text = 'Project Number:', font = ('Arial Bold', 10))
    sample_lable.pack(anchor = 'sw', side = 'left')
    sample_entry = Entry(top_frame, width = 15)
    sample_entry.pack(anchor = 'sw', side = 'left')
    
    for i in range(3):
        lbl = Label(btm_frame2, text = f'Test: {i 1}', font = ('Arial', 10))
        lbl.grid(row=0, column=i 1)
    
    #First test
    ect_widgets = create_widgets(btm_frame2, test_name = 'ECT', units = 'kN/m', row = 1)
    ect_button = Button(btm_frame2,text='Add ECT', command = ect_widgets.add_entry)
    ect_button.grid(row=12,column= 1, pady = 20)

   # Next test
   # fct_widgets = create_widgets(btm_frame2, test_name = 'FCT', units = 'kPa', row = 1)
   # fct_button = Button(btm_frame2,text="FCT", command = fct_widgets.add_entry)
   # fct_button.grid(row=12,column= 2, pady = 20)

   # Next: Add FCT 

menubar = Menu(root)
filemenu = Menu(menubar, tearoff=0)
menubar.add_cascade(label="File", menu=filemenu)
filemenu.add_separator()
filemenu.add_command(label="Exit", command=root.quit)

papermenu = Menu(menubar, tearoff=0)
menubar.add_cascade(label="Paper", menu=papermenu)

boardmenu = Menu(menubar, tearoff=0)
menubar.add_cascade(label="Board", menu=boardmenu)
boardmenu.add_command(label="Strength Properties", command = board_strength)
boardmenu.add_command(label="Structural Properties", command= 'board_structure')
root.config(menu=menubar)

root.mainloop()
  

Когда я запускаю этот код, я получаю следующую ошибку:

 TypeError: add_entry() missing 4 required positional arguments: 'window', 'test_name', 'units', and 'row'
  

Почему ему все еще нужны эти аргументы, если я уже передал их при создании экземпляра ect_widget? И как мне соответственно увеличить номер строки при добавлении новых строк? Номера строк будут головной болью.

Любая помощь или ввод будут высоко оценены. Спасибо!

Комментарии:

1. Опубликуйте полную обратную трассировку

2. Вот полная трассировка: исключение в трассировке обратного вызова Tkinter (последний последний вызов): File «C:UsersAnaconda3libtkinter_ init_ .py», строка 1883, при вызове возвращает self.func(* аргументы) Ошибка типа: add_entry() отсутствуют 4 обязательных позиционных аргумента: ‘window’, ‘test_name’, ‘units’ и ‘row’

3. Может ли ошибка быть в ect_widgets.add_entry том, что вы не передаете никаких аргументов?

Ответ №1:

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

Вероятно, вы хотите, чтобы метод add_entry не содержал всех этих требуемых аргументов. Хотя это необходимо для выполнения того, что он делает; вы можете сохранить эти данные в экземпляре класса при его создании.

 def __init__(self, window, test_name, units, row):
    self.window = window
    self.test_name = test_name
    self.units = units
    self.row = row
    self.add_entry()
  
def add_entry(self):
    self.entries = []

    lbl_of_test = Label(self.window,
        text = f'{self.test_name} ({self.units}):',
        font = ('Arial', 10))
    lbl_of_test.grid(row = self.row, column = 0)

    for i in range(3):
        self.entry = Entry(self.window, width=8)
        self.entry.grid(row=self.row, column=i 1)
        self.entries.append(self.entry)
  

Что-то вроде этого, вероятно, более уместно. Мы храним атрибуты экземпляра, используя этот синтаксис «self.». «Self.window = window» и т.д. Сохраняет эти вещи, поэтому вы можете использовать их в любое время, не передавая их. Затем в методе add_entry он может использовать сохраненные значения этих объектов, вызывая их версию ‘self.’.

(С технической точки зрения, нет ничего волшебного в использовании слова ‘self’ перед этими переменными; это работает таким образом, потому что ‘self’ является первым аргументом, передаваемым в нестатические методы — включая __init__ — в классе. Все, что первым относится к экземпляру этого класса, следовательно, типичное имя ‘self’. Если вам когда-нибудь понадобится обратиться к экземпляру класса в его собственных методах, вы бы просто использовали ‘self’.)

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

PS Я разделил эту действительно длинную строку на несколько … как правило, вам не нужны строки длиной более 80 символов, а Python позволяет свободно вырезать строки между элементами внутри круглых скобок.

Комментарии:

1. Спасибо вам обоим за всю вашу помощь! Я решил свою проблему