#python #python-3.x #user-interface #tkinter #raspberry-pi
#python #python-3.x #пользовательский интерфейс #tkinter #raspberry-pi
Вопрос:
У меня есть сложная программа, в которой я запускаю несколько задач в своем основном цикле tkinter. Моя программа работает, однако у меня возникла одна досадная проблема, у меня нет возможности остановить задачу, если она не завершена. Я разработал простую программу tkinter, чтобы показать эту проблему:
Полный код :
import tkinter as tk
from tkinter import Button,Entry,Canvas,Label,ttk
class Application(tk.Frame):
def __init__(self,master=None):
super().__init__(master)
self.master = master
def Create_canvas(self,canvas_width,canvas_height):
global canvas#described as global because used outside class
canvas = tk.Canvas(self.master,bg='papaya whip',width=canvas_width,height=canvas_height)
def Application_Intro(self):
print("starting new app")
restart_program_button = tk.Button(canvas, text="Restart_program",font='Helvetica 12 bold', width=20, height=2, command =self.Restart)
start_program_button = tk.Button(canvas, text="Start_program",font='Helvetica 12 bold', width=20, height=2, command =self.Start_program)
canvas.create_text(960,20,text="MY PROGRAM",font='Helvetica 16 bold')
canvas.create_window(710,300,window = restart_program_button)
canvas.create_window(710,500,window = start_program_button)
canvas.pack()
self.master.mainloop()
def Start_program(self):
print("Program start")
self.master.after(1000,self.Start_program)
def Restart(self):
#self.master.destroy()
#self.master.quit()
print("HERE I WANT TO INTERRUPT START PROGRAM AND RETURN TO IDLE STATE")
#WHAT TO DO IN THIS FUNCTION TO GO BACK TO INITIAL MAINLOOP STATE??
return
master = tk.Tk()
app = Application(master=master)
app.Create_canvas(1920,1080)
app.Application_Intro()
Приведенная выше программа создаст простой графический интерфейс с 2 кнопками. Первоначально программа будет простаивать и ждать, пока пользователь запустит приложение. При запуске приложения оно будет вызывать себя рекурсивно (проверяя различные состояния и выполняя другие сложные операции в моей реальной программе), однако я хочу иметь возможность прервать эту операцию и остановить ее в любое время. Вот почему я создал кнопку «ПЕРЕЗАПУСК», которая должна перезапустить программу обратно в исходное состояние, где я жду, когда пользователь снова запустит приложение. Как я могу вернуться из функции Start_program после нажатия кнопки?
Я действительно не могу найти соответствующую информацию в Интернете, кроме master.destroy() или master.quit().
master.destroy() полностью уничтожает мой mainloop, чего я не хочу, и вызов master.quit(), похоже, даже ничего не делает.
Добавление URL-адреса изображения, чтобы вам было легче его понять:https://ibb.co/djMd5TW
Комментарии:
1. Если «Программа работает нормально», то в чем ваша проблема? Похоже, вы уже получаете то, что хотите, но хотите получить общий совет, чтобы сделать это лучше. Вы должны быть конкретными, чтобы действительно получить помощь.
2. Точно так, как вы сказали. Я надеюсь получить совет от кого-то, у кого больше опыта работы с tkinter, и мог бы дать мне общий совет, является ли это эффективным способом обработки окон, поскольку я не чувствую, что это очень эффективно уничтожать и переделывать новое окно каждый раз, когда я запускаю новую операцию (новая операция может инициироваться каждые 30 секунд или что-то в этом роде)
3. Будет очень мало проблем с регулярным уничтожением Windows при запуске приложения на рабочем столе. Более тревожным будет то, что, похоже, вы используете более одного экземпляра
Tk()
(login_screen
иwindow
).4. Спасибо за ответ. Я использую единственный экземпляр Tk() экран входа в систему является верхним уровнем окна. Он создается во время окна входа в систему следующим образом:
global login_screen login_screen = TopLevel(window)
5. Вы должны быть готовы к работе. После того, как приложение заработает, вы можете перейти к нему и провести рефакторинг. Но сначала заставьте его работать, что, похоже, у вас уже есть.
Ответ №1:
Это зависит от того, какую часть программы вы готовы переписать. ИМО, «наилучшим сценарием» было бы не удалять главное окно и использовать как можно меньше TopLevel
секунд. Я бы рекомендовал вместо этого просто создать серию фреймов, чтобы вы могли очень легко добавлять и удалять все содержимое окна. Эти фреймы будут вашими собственными классами с их родительским существом tkinter.Frame
и содержать всю логику для этого экрана.
Причина, по которой я предлагаю это, заключается в том, что, похоже, у вас есть ~ 700 строк методов, которые (я знаю по опыту 😉 очень сложно поддерживать (больше, чем несколько сотен строк, и я начну использовать метод выше). Если вам нужен пример этого метода, пожалуйста, посмотрите код внизу этого ответа.
Немного меньшее изменение, я бы рекомендовал вам заменить ваше from tkinter import *
на import tkinter as tk
, поскольку первое создает очень загроможденное пространство имен:
from tkinter import *
: Это импортирует библиотеку Tkinter в глобальное пространство имен. Это не лучшая практика, потому что она заполняет ваше пространство имен множеством классов, которые вы можете случайно перезаписать, но это нормально для очень маленьких скриптов. [Создание Tkinter Hello World — Программирование графического интерфейса Python с помощью Tkinter]
Еще одно небольшое изменение, которое я бы рекомендовал, — прекратить создавать собственные окна сообщений (например, объявляющие «Успех входа») и вместо этого посмотреть на tkinter.messagebox
модуль (в этой ситуации вы могли бы использовать showinfo
).).
Если у вас много свободного времени, взгляните на незанятый исходный код, поскольку это программа tkinter, которая (вообще говоря) очень хорошо написана (я полагаю, что Тонни также использует tkinter).
#/usr/bin/python3
import tkinter as tk
class Login(tk.Frame):
def __init__(self, *args, **kw):
super().__init__(*args, **kw)
self.create_widgets()
self.pack(expand=True, fill="both")
def create_widgets(self):
# your login screen widgets ...
# I use this method to stop __init__ becoming too big and also to
# give me the option to seperate widget creating from
# instantiation if I wish
tk.Button(self, text="Login", command=self.check_creds).pack()
def check_creds(self):
# mysql and other logic
# assuming everything is good to go:
self.destroy()
Welcome(self.master)
class Welcome(tk.Frame):
def __init__(self, *args, **kw):
super().__init__(*args, **kw)
self.create_widgets()
self.pack(expand=True, fill="both")
def create_widgets(self):
# again, your widgets are created here...
tk.Button(self, text="Log out", command=self.log_out).pack()
def log_out(self):
self.destroy()
Login(self.master)
root = tk.Tk()
Login(root)
root.mainloop()
Комментарии:
1. Спасибо, сэр, я обязательно посмотрю на такую реализацию GUI и посмотрю, как далеко я могу зайти.