Ошибка "cannot pickle '_tkinter.tkapp' object", с которой вы столкнулись, происходит из-за того, что объекты tkinter не могут быть сериализованы (преобразованы в байтовый поток) для передачи между процессами при использовании модуля `multiprocessing`. Каждый процесс в `multiprocessing` имеет свое собственное пространство памяти, и объекты tkinter (например, окна, виджеты) существуют в единственном процессе, где они были созданы.
Когда вы хотите передать виджет (например, `window`), в другую функцию, выполняемую в другом процессе, это вызывает ошибку, потому что `multiprocessing` не может сериализовать объект tkinter.
В отличие от `threading`, где потоки работают в одном и том же пространстве памяти и могут напрямую работать с объектами tkinter, `multiprocessing` создаёт новые процессы с их собственным пространством памяти и требует сериализации для передачи данных между ними.
Для решения проблемы вы можете рассмотреть следующие варианты:
1. **Использовать `Queue` или другие механизмы передачи данных:** Вместо передачи виджетов, используйте `Queue` для передачи сообщений между процессом и главным потоком, чтобы управлять состоянием приложения.
2. **Обработка задач в главном потоке:** Можно избежать использования `multiprocessing` и использовать `threading` для продолжительной работы, в том числе, добавляя логику для завершения потоков по сигналу от виджета.
Вот пример, как вы можете использовать `Queue` для взаимодействия между процессами:
```python
import time
import multiprocessing
from tkinter import *
from tkinter import ttk
def s4et(k, q):
"""Функция счета."""
i = 0
while i < 10 ** 6:
i += 1
d = i * k
q.put(d) # Отправляем результат в очередь
def check_for_results(q, window):
"""Проверка результатов выполнения."""
while True:
try:
while not q.empty():
result = q.get()
print(result)
except Exception as e:
print(f"Error: {e}")
time.sleep(0.2)
if not window.winfo_exists():
break # Закрываем цикл, если окно уже закрыто
def pusk():
def denide():
t1.terminate() # Завершение процесса
window.destroy() # Закрытие окна
window = Toplevel()
window.geometry("400x200")
btn1 = Button(master=window, text="Stop", command=denide)
btn1.pack(pady=20)
q = multiprocessing.Queue() # Создаем очередь для передачи данных
t1 = multiprocessing.Process(target=s4et, args=(2, q), daemon=True)
t1.start() # Стартуем процесс
t2 = Thread(target=check_for_results, args=(q, window), daemon=True)
t2.start() # Запускаем поток для проверки результатов
# Запуск главного окна
root = Tk()
root.geometry("200x100")
start_button = Button(root, text="Start", command=pusk)
start_button.pack(pady=20)
root.mainloop()
```
В этом примере используется очередь `multiprocessing.Queue` для хранения результатов функции `s4et`, а другой поток проверяет очередь на наличие данных. Это позволяет избежать передачи объектов tkinter между процессами и сохраняет возможность обработки данных асинхронно.