Как вернуть изменённую переменную?
пишу школьный проект и опыта в программировании у меня мало и вот создал я приложение на tkinter теперь мне нужно чтобы из функции btn1_click выходило pos1 = 0, для того чтобы это окно нельзя было вывести два раза, но пишет ошибку. Помогите пожалуйста или может быть есть другой способ легко ограничить количество открываемых окон одной и той же функции? ``
from tkinter import *
class Main:
main = Tk()
main.title("Решатель задач 2999")
main.geometry('600x400')
main.resizable(0, 0)
canvas = Canvas(main, height=600, width=400)
canvas.pack()
frame = Frame(main, bg='white')
frame.place(relx=0, rely=0, relwidth=1, relheight=1)
pos = 1
def btn1_click():
global pos
if pos==1:
wnd1 = Toplevel()
wnd1.protocol("WM_DELETE_WINDOW",)
wnd1.title("Первый вариант")
wnd1.geometry('600x400')
wnd1.resizable(0, 0)
canvas = Canvas(wnd1, height=600, width=400)
canvas.pack()
return (pos - 1)
def btn2_click():
wnd2 = Toplevel()
wnd2.title("Первый вариант")
wnd2.geometry('600x400')
wnd2.resizable(0, 0)
canvas = Canvas(wnd2, height=600, width=400)
canvas.pack()
return(0)
title = Label(frame, text='Выберите вариант', bg='white')
title.pack()
btn1 = Button(frame, text='Встречное движение', bg='gray', font=50, command=btn1_click)
btn1.pack(side=LEFT, padx=50)
btn2 = Button(frame, text='Попутное движение', bg='gray', font=50, command=btn2_click)
btn2.pack(side=RIGHT, padx=50)
main.mainloop()``
Ответы (2 шт):
А почему не объявить это перменную на уровне класса, со значением 1, после вызова функции значение бы менялось на ноль и соответвенно больше бы функция не отрабатывала? Только не return а просто присвоением нового значения.
Здраствуйте,
1. Ошибка состоит в том, что вы объявили переменную pos непосредственно в классе, вместо этого вынесите переменную из класса и объявите её сразу после from tkinter import *.
Вместо return (pos - 1) используйте pos = 1, поскольку return используется для присваивания (например: var_1 = func()), получим:
from tkinter import *
pos = 1
def btn1_click():
global pos
if pos == 0: return # Если pos = 0 завершаем выполнение функции, ничего не вернув
wnd1 = Toplevel()
wnd1.title("Первый вариант")
wnd1.geometry('600x400')
wnd1.resizable(0, 0)
canvas = Canvas(wnd1, height=600, width=400)
canvas.pack()
pos = 0
""" Продолжение вашего кода """
2. Так или иначе выбранное вами решение проблемы не рационально, также не рекомендуется использовать глобальные переменные. Вот как вы можете улучшить код:
2.1. Не стоит оборачивать код в class Main без необходимости.
2.2. Лучше обернём выполнение самого кода в функцию main(). Также необходимо переименовать экземпляр основного окна main в window, дабы избежать ошибок.
2.3. Вместо проверки значения переменной просто будем выключать кнопку: заменим command=btn1_click на command=lambda: [ btn1_click(), btn1.config(state=DISABLED) ], тоже самое сделаем со второй кнопкой. Здесь мы используем лямбда-функцию для того, чтобы выполнить сразу несколько команд. Заметьте, что здесь обязательно нужно вызвать функцию с помощью круглых скобок, поскольку мы обернули её в лямбда-функцию.
2.4. Начнём выполнение кода с помощью следующей конструкции. Запомните, что ваш файл должен быть назван main.py.
if __name__ == '__main__':
main()
Вот улучшенная версия кода: надеюсь, что я вам помог.
from tkinter import *
def btn1_click():
wnd1 = Toplevel()
wnd1.protocol("WM_DELETE_WINDOW",)
wnd1.title("Первый вариант")
wnd1.geometry('600x400')
wnd1.resizable(0, 0)
canvas = Canvas(wnd1, height=600, width=400)
canvas.pack()
def btn2_click():
wnd2 = Toplevel()
wnd2.title("Первый вариант")
wnd2.geometry('600x400')
wnd2.resizable(0, 0)
canvas = Canvas(wnd2, height=600, width=400)
canvas.pack()
def main():
window = Tk()
window.title("Решатель задач 2999")
window.geometry('600x400')
window.resizable(0, 0)
canvas = Canvas(window, height=600, width=400)
canvas.pack()
frame = Frame(window, bg='white')
frame.place(relx=0, rely=0, relwidth=1, relheight=1)
title = Label(frame, text='Выберите вариант', bg='white')
title.pack()
btn1 = Button(frame, text='Встречное движение', bg='gray', font=50, command=lambda:[ btn1_click(), btn1.config(state=DISABLED)])
btn1.pack(side=LEFT, padx=50)
btn2 = Button(frame, text='Попутное движение', bg='gray', font=50, command=lambda: [ btn2_click(), btn2.config(state=DISABLED)])
btn2.pack(side=RIGHT, padx=50)
window.mainloop()
if __name__ == '__main__':
main()
3. Есть наилучшее решение с использованием ООП, оно достаточно сложное с вашей точки зрения, но очень и очень удобное, рекомендую сразу перейти на ООП. Возможно, мой ответ не точен, но сухое объяснение теории вам ничего не даст: дам подсказку, аргумент self означает, что этот параметр получит объект app, так же все объекты и переменные с префиксом self можно изменять из любой точки класса (не забудьте в аргументы функции записать self).
Здесь же вы можете оптимально ограничить максимальное количество нажатий, создав переменную self.btn1_count = 0 и self.btn2_count = 0, получим:
from tkinter import *
class App(Tk):
def __init__(self):
super(App, self).__init__()
self.title("Решатель задач 2999")
self.geometry('600x400')
self.resizable(0, 0)
self.canvas = Canvas(self, height=600, width=400)
self.canvas.pack()
self.frame = Frame(self, bg='white')
self.frame.place(relx=0, rely=0, relwidth=1, relheight=1)
self.btn1_count = 0
self.btn2_count = 0
title = Label(self.frame, text='Выберите вариант', bg='white')
title.pack()
self.btn1 = Button(self.frame, text='Встречное движение', bg='gray', font=50, command=self.btn1_click)
self.btn1.pack(side=LEFT, padx=50)
self.btn2 = Button(self.frame, text='Попутное движение', bg='gray', font=50, command=self.btn2_click)
self.btn2.pack(side=RIGHT, padx=50)
def btn1_click(self):
if self.btn1_count > 0: return # Завершаем выполнение функции, если мы уже нажимали на кнопку
wnd1 = Toplevel()
wnd1.title("Первый вариант")
wnd1.geometry('600x400')
wnd1.resizable(0, 0)
self.canvas = Canvas(wnd1, height=600, width=400)
self.canvas.pack()
self.btn1_count += 1 # self.btn_count = self.btn_count + 1
# Если хотите, чтобы можно было нажать на кнопку только один раз, и
# чтобы после этого она выключалась, можно просто использовать
# в конце этой функции self.btn1_config(state=DISABLED),
# тогда удалите self.btn1_count = 0 и условие if self.btn1_count > 0: return,
# то же самое можете сделать со второй кнопкой.
def btn2_click(self):
if self.btn2_count > 0: return
wnd2 = Toplevel()
wnd2.title("Второй вариант")
wnd2.geometry('600x400')
wnd2.resizable(0, 0)
self.canvas = Canvas(wnd2, height=600, width=400)
self.canvas.pack()
self.btn2_count += 1
def main():
app = App()
app.mainloop()
if __name__ == '__main__':
main()