"Улетают" виджеты после 10 минутной работы tkinter
Разрабатываю приложение для вывода информации с плк на пк. После 10 минутной работы программы, все читаемые переменные улетают в один левый верхний угол (показано на скриншоте).Что может повлиять на поведение программы? Немного пояснения: пошагово до появление этой проблемы разбирался с методом расположения grid(). Все отображалось и находилось в заданных местах. Но примерно через 10 минут работы они "улетают". 2. Программа разрабатывается под конкретное железо для вывода информации, поэтому было сделано так (добавил скрин с расположением как только запускаю программу, все на своих местах находится). Первый раз занимаюсь разработкой приложений на python.
import tkinter as tk
from tkinter import ttk
from tkinter import *
from threading import Timer
from pymodbus.client import ModbusTcpClient as ModbusClient
import multiprocessing
class App(tk.Tk): # Главное окно
def __init__(self): # Инициализация главного окна
super().__init__()
self.title('Тандем 3') # Заголовок окна
self.geometry('1920x1000') # Размер в пикселях окна
self.resizable(False, False) # Запрет на растягивания окна
self['background'] = 'lightskyblue1'
self.Connect_to_PLC()
self.create_widgets() # Отображение фреймов
def Connect_to_PLC(self): # Подключение к ПЛК в качестве клиета
print('Start Modbus Client') # Вывод надписи в консоль для проверки работы функции
global client # Присваивание глобального типа к переменной для доступа других функций
global reg # Присваивание глобального типа к переменной для доступа других функций
global address # Присваивание глобального типа к переменной для доступа других функций
client = ModbusClient(host='192.168.100.50', port=502, auto_open=TRUE) # ПЛК выступает в роли сервера
reg = 0
address = 0
def create_widgets(self): # Отображение фреймов
for i in range(4): # Создание в цикле фреймов экструдеров
FrameExtr(self, i + 1).grid(row=0, column=0 + i, columnspan=1, padx=50, pady=10, ipadx=20, ipady=10,
sticky=tk.N) # Вызов класса экструдера и привязки их по сетке
class FrameExtr(ttk.Frame): # Отображение фреймов
def __init__(self, container, i):
super().__init__(container)
style = ttk.Style()
style.configure('My.TFrame', relief='solid', background='gray94')
self.configure(style='My.TFrame')
self.choice_extr(i)
self.create_widgets_static()
self.process_temp = multiprocessing.Process(target=self.repeater(5, self.update_temp_fields))
self.process_extr = multiprocessing.Process(target=self.repeater(2, self.update_extr_fields))
def choice_extr(self, i):
if i == 1:
self.numberExtr = 1
self.nameExtr = '120/1'
self.quantity_zone = 11
self.offset = 0
if i == 2:
self.numberExtr = 2
self.nameExtr = '120/2'
self.quantity_zone = 10
self.offset = 26
if i == 3:
self.numberExtr = 3
self.nameExtr = '90/1'
self.quantity_zone = 11
self.offset = 52
if i == 4:
self.numberExtr = 4
self.nameExtr = '45'
self.quantity_zone = 10
self.offset = 78
def create_widgets_static(self):
ttk.Label(self, text=f'Экструдер {self.nameExtr}', font=("Times", 32), anchor='center').grid(row=0, column=0,
columnspan=4)
ttk.Label(self, text='Текущие обороты', font=("Times", 18)).grid(row=1, column=0, columnspan=2)
ttk.Label(self, text='Текущий ток', font=("Times", 18)).grid(row=2, column=0, columnspan=2)
ttk.Label(self, text='Текущая', font=("Times", 18)).grid(row=3, column=1)
ttk.Label(self, text='Заданная', font=("Times", 18)).grid(row=3, column=2)
for i in range(self.quantity_zone):
ttk.Label(self, text=f'Зона {i + 1}', font=("Times", 24)).grid(row=4 + 2 * i, column=0, padx=5, pady=10)
def repeater(self, interval, function):
Timer(interval, self.repeater, [interval, function]).start()
function()
def update_extr_fields(self):
self.text_extr_vars = [StringVar() for _ in range(2)]
for i in range(2):
if i == 0:
ttk.Label(self, textvariable=self.text_extr_vars[i], font=("Times", 30), background='green', width=5,
anchor='center', relief='ridge', padding=3).grid(row=1, column=2)
else:
ttk.Label(self, textvariable=self.text_extr_vars[i], font=("Times", 30), background='blue', width=5,
anchor='center', relief='ridge', padding=3).grid(row=2, column=2)
for i in range(2):
self.text_extr_vars[i].set(client.read_holding_registers(reg + self.offset + 22 + i, 1).registers)
def update_temp_fields(self):
# Создаем список для хранения объектов StringVar
self.text_vars = [StringVar() for _ in range(self.quantity_zone * 2)]
# Создаем текстовые поля с привязкой к соответствующим StringVar
for i in range(self.quantity_zone * 2):
# self.text_vars[i].set(client.read_holding_registers(reg + i, 1).registers)
if i % 2 == 0:
ttk.Label(self, textvariable=self.text_vars[i], font=("Times", 30), background='yellow', width=5,
anchor='center', relief='ridge', padding=3).grid(row=4 + i, column=1)
else:
ttk.Label(self, textvariable=self.text_vars[i], font=("Times", 30), background='red', width=5,
borderwidth=8, anchor='center').grid(row=3 + i, column=2)
# Обновляем текст в текстовых полях
for i in range(self.quantity_zone * 2):
self.text_vars[i].set(client.read_holding_registers(reg + self.offset + i, 1).registers)
if __name__ == "__main__":
app = App()
app.mainloop()
Ответы (1 шт):
Функция update_temp_fields вызывается по таймеру каждые пять секунд. На каждый вызов она создаёт пару десятков объектов StringVar и пару десятков полей ttk.Label. Предыдущие переменные и поля не удаляются. Новые поля рисуются поверх старых. Число полей во окне растёт неограниченно, а tkinter использует шестнадцатибитные переменные для индексов полей. В конце концов счётчик переполняется, портятся внутренние структуры и программа падает.
Поправить можно так:
- код создания переменных и полей перенести в
create_widgets_static:
def create_widgets_static(self):
...
self.text_vars = [StringVar() for _ in range(self.quantity_zone * 2)]
for i in range(self.quantity_zone * 2):
if i % 2 == 0:
ttk.Label(self, ...).grid(row=4 + i, column=1)
else:
ttk.Label(self, ...).grid(row=3 + i, column=2)
...
- в
update_temp_fieldsоставить только обновление переменных:
def update_temp_fields(self):
for i in range(self.quantity_zone * 2):
self.text_vars[i].set(...)
Аналогичная проблема есть в функции update_extr_fields, её тоже надо исправить.
P.S. Код реально ужасен: неправильно использованы библиотеки, неправильно использованы средства языка. Наплачетесь вы с этой программой, её надо переписать полностью.

