Tkinter как скрыть окно
Перейти к содержимому

Tkinter как скрыть окно

  • автор:

Tkinter как скрыть окно

На этом шаге мы рассмотрим процесс создания таких окон .

Модальное вторичное окно , в отличие от обычного, при открытии блокирует все остальные окна приложения, в результате чего пользователь теряет доступ к ним. Остальные окна становятся доступными только после закрытия модального окна. Такие окна обычно применяются в качестве диалоговых окон для запроса каких-либо данных, необходимых для дальнейшей работы приложения.

К сожалению, библиотека Tkinter не предоставляет никаких инструментов для вывода модальных окон. Однако мы можем превратить обычное вторичное окно в модальное, вызвав у его контейнера или у него самого метод grab_set() (см. 11 шаг). Этот метод задает для контейнера или окна режим перехвата событий, в результате чего остальные окна перестают реагировать на действия пользователя. Как только окно, для которого был установлен перехват событий, закрывается и удаляется из памяти, перехват событий перестает работать, и остальные окна приложения становятся доступными для пользователя.

Есть еще один неприятный момент, связанный с реализацией модальных окон. Если после запуска приложения и вывода модального вторичного окна мы посмотрим на панель задач Windows , то увидим, что там присутствуют оба окна: и главное, и вторичное. Но присутствие модального окна на панели задач говорит о плохом стиле программирования. Чтобы скрыть вторичное окно, следует вызвать у него метод transient() (см. 21 шаг), передав ему ссылку на главное окно. Этот метод, в частности, отменит представление вторичного окна на панели задач.

Вот фрагмент кода контейнера, который превратит окно, в котором выведен, в модальное:

class Secondary(tkinter.ttk.Frame): def __init__(self, master=None): . . . . . self.master.transient(parent) self.grab_set()

В качестве примера давайте модифицируем приложение из предыдущего шага таким образом, чтобы выводимое им вторичное окно стало модальным. Текст ниже показывает исправленный код класса контейнера вторичного окна.

import tkinter import tkinter.ttk # Объявляем класс контейнера для вторичного окна class Secondary(tkinter.ttk.Frame): # Конструктор этого класса поддерживает дополнительный параметр # parent, с которым передается ссылка на главное окно. Она # понадобится нам, чтобы вывести занесенное значение в главном окне def __init__(self, master=None, parent=None): super().__init__(master) # Сохраним ссылку на главное окно в атрибуте self.parent = parent self.pack() self.create_widgets() self.master.title("Вторичное окно") self.master.transient(parent) self.grab_set() def create_widgets(self): self.varValue = tkinter.StringVar() self.varValue.set("Значение") entValue = tkinter.ttk.Entry(self, textvariable=self.varValue) entValue.pack() btnOK = tkinter.ttk.Button(self, text="OK", command=self.ok) btnOK.pack(side="left") btnCancel = tkinter.ttk.Button(self, text="Отмена", command=self.master.destroy) btnCancel.pack(side="right") def ok(self): self.parent.lblValue["text"] = self.varValue.get() self.master.destroy() def show_value(self): self.parent.lblValue["text"] = self.varValue.get() class Application(tkinter.ttk.Frame): def __init__(self, master=None): super().__init__(master) self.pack() self.create_widgets() self.master.title("Модальное вторичное окно") self.master.resizable(False, False) def create_widgets(self): btnShowWindow = tkinter.ttk.Button(self, text="Вывести окно", command=self.show_window) btnShowWindow.pack() # Опция width компонента Label задает ширину надписи # в символах текста self.lblValue = tkinter.ttk.Label(self, text="", width=50) self.lblValue.pack() def show_window(self): # Выводим вторичное окно, не забыв указать в параметре parent # конструктора ссыпку на главное окно Secondary(master=tkinter.Toplevel(), parent=self) root = tkinter.Tk() app = Application(master=root) root.mainloop()

Архив с файлом можно взять здесь.

Результат работы приложения приведен на рисунке 1.

Рис.1. Результат работы приложения

На следующем шаге мы рассмотрим управление жизненным циклом приложения .

Как скрыть виджеты после их нажатия и выполнения действия?

На главном окне у меня будут: кнопка, поля ввода и несколько label. Как сделать так, чтобы после нажатия кнопки она исчезала(скрывалась), а затем появлялись остальные объекты.
То есть как авторизация: вводим логин, пароль, нажимаем «войти», всё скрывается и появляются другие компоненты, то есть будто вход выполнен.

Искал в интернете, но нашел только скрыть кнопку по нажатию или скрыть/показать label по нажатию на кнопку.
Можно ли, когда нажму на кнопку, сначала выполниться действие(показ всех остальных элементов), а потом все компоненты авторизации исчезнут?(или наоборот, сначала все исчезает, а потом появляются компоненты). То есть можно ли как-то скрыть все компоненты по 1 нажатию кнопки и как это реализовать или есть какой-то другой способ?

Функция hide_me скрывает кнопку через bind(), если кнопка не привязана к координатам, а так ничего не происходит.
Попробовал через lambda сделать, чтобы выполнить 2 функции сразу, но появляется ошибка.

btn=Button(text=»Авторизация», command=lambda:(AUTO(),hide_me()))
TypeError: hide_me() missing 1 required positional argument: ‘event’

from tkinter import * def hide_me(event): event.widget.pack_forget() root = Tk() root.title("Авторизация") root.geometry("500x250") root.resizable(False, False) l = "admin" p = "password" LOGIN = "Введите логин:" LOGIN = Label(text=LOGIN, justify=LEFT) LOGIN.place(x=0, y=0) lineLOGIN = Entry() lineLOGIN.pack() lineLOGIN.place(x=80, y=30, anchor="c") PASS = "Введите пароль:" PASS = Label(text=PASS, justify=LEFT) PASS.place(x=0, y=60) linePASS = Entry() linePASS.pack() linePASS.place(x=80, y=90, anchor="c") def AUTO(): if lineLOGIN.get() == l and linePASS.get() == p: linePA = Entry() linePA.pack() linePA.place(x=200, y=70, anchor="c") else: print("Неверный логин/пароль") btn=Button(text="Авторизация", command=lambda:(AUTO(),hide_me())) #btn.bind('', hide_me) btn.pack() btn.place(x=60, y=120, anchor="c") root.mainloop()
  • Вопрос задан более двух лет назад
  • 811 просмотров

Спрятать окно tkinter

Проблема следующая. Пользуюсь модулем messagebox, который, помимо окна диалога, создает пустое окно root. Чтобы спрятать это окно, на форумах советуют использовать root.withdraw(). Однако мой скрипт создает много разнообразных окон tkinter, и после того, как я что-нибудь нажал в диалоге messagebox, tkinter не может создать новое окно (терминал просто висит) — видимо, ждет, когда я закрою пустое окно root (оно, напомню, спрятано, т.е. мне остается только Ctrl+C). root_destroy() в конце таких процедур как ниже не помогает. Если же withdraw убрать, tkinter начинает плодить сущности: 1, 2 — некрасиво. Как можно решить этот вопрос?

from tkinter import * from tkinter import filedialog from tkinter import messagebox # Диалог "Вы уверены. " def ok_cancel(message): root=Tk() # Иначе будет показываться лишнее пустое окно #root.withdraw() if messagebox.askokcancel('Подтвердите:',message): return True; else: return False #root.destroy()

Deleted
01.04.13 06:05:21 MSK

Никак. В Tk обязательно есть root-окно. Цикл wm (основной цикл для Windows Manager’a Tk) обязательно должен содержать рутовое окно (иначе просто не к чему привязать цикл). Ну, и для Tk использование диалоговых окон вне цикла — просто не возможно. Дело в том, что исходя из архитектуры Tk, элемент message box — это просто дочернее окно (следовательно, оно должно быть привязано к root’овому), у которого заранее заданы определенные параметры.

Я такую проблему обходил просто — сделал класс, который описывал нужный мне диалог и создавал/убивал окно по мере надобности (каждый раз это было просто заново создаваемое root’овое окно). Для Tk это более правильный подход, нежели скрывать корневое окно, а потом плодить мессадж-боксы.

silver-bullet-bfg ★★
( 01.04.13 08:05:07 MSK )

Второй путь: забить на Tk и юзать Gtk 🙂

Novator ★★★★★
( 01.04.13 10:34:18 MSK )
Ответ на: комментарий от Novator 01.04.13 10:34:18 MSK

А смысл? Для маленьких скриптов — tk самое оно. Тем более, что Tkinter — гвидоугодный.

silver-bullet-bfg ★★
( 01.04.13 13:03:24 MSK )
Ответ на: комментарий от silver-bullet-bfg 01.04.13 08:05:07 MSK

Пример класса можете привести?

Deleted
( 01.04.13 13:28:31 MSK )
Ответ на: комментарий от silver-bullet-bfg 01.04.13 08:05:07 MSK

Для Tk это более правильный подход, нежели скрывать корневое окно, а потом плодить мессадж-боксы.

Т.е. предлагаете написать свой messagebox?

Deleted
( 01.04.13 13:30:22 MSK )

не знаю как оно на питоне, но в tcl так:

wm withdraw .
Bad_ptr ★★★★★
( 01.04.13 13:32:36 MSK )

Bad_ptr ★★★★★
( 01.04.13 13:34:29 MSK )
Ответ на: комментарий от silver-bullet-bfg 01.04.13 13:03:24 MSK

А смысл? Для маленьких скриптов — tk самое оно.

Gtk в любом линуксе есть всегда. А вот tk не всегда.
В виндовс Gtk (без туфты) занимает 14Мб в распакованном виде. В архиве того меньше. Сколько tk в винде занимает — не знаю.

А смысл в том, что Gtk выглядит поприятнее, более популярно и лучше документировано. Еще в том, что описанной проблемы можно избежать без выкрутасов.

Ни в коем случае не уговариваю. Решать топикстартеру.

Novator ★★★★★
( 01.04.13 13:59:36 MSK )
Ответ на: комментарий от Novator 01.04.13 13:59:36 MSK

Согласен, что GTK-диалоги приятнее, но очень обломно изучать Tkinter ради простого скрипта, и в итоге из-за маленькой проблемы разучивать что-то другое.

Deleted
( 01.04.13 14:38:04 MSK )
Ответ на: комментарий от Deleted 01.04.13 13:30:22 MSK

Ну да, что тут сложного? Сделаете за 3 минуты. Python очень плохо помню, но что-то вроде:

class WmDialog def __init__(self): self.root=Tk() self.bntOk=ttk.Button (root, text="Hello, world", ).grid() def cmdOk(self): return "ok" def liveWnd (self,isLive): self.root.mainloop() def deadWnd (self): self.root.destroy() 

silver-bullet-bfg ★★
( 01.04.13 14:53:51 MSK )
Ответ на: комментарий от silver-bullet-bfg 01.04.13 14:53:51 MSK

* self.bntOk=ttk.Button (root, text=«Hello, world», command=self.cmdOk).grid()

silver-bullet-bfg ★★
( 01.04.13 14:55:04 MSK )
Ответ на: комментарий от Deleted 01.04.13 14:38:04 MSK

Tkinter гвидоугоден зато ^_^. На нем можно не только для скриптов гуй рисовать.

silver-bullet-bfg ★★
( 01.04.13 14:55:51 MSK )
Ответ на: комментарий от silver-bullet-bfg 01.04.13 14:55:04 MSK

Я Питон недавно начал изучать. Можете объяснить, как применить этот класс, чтобы не было пустых окон?

Deleted
( 02.04.13 00:40:42 MSK )
Ответ на: комментарий от Novator 01.04.13 10:34:18 MSK

А есть какой-нибудь простой конструктор типа zenity, вместо того, чтобы кучу непонятных функций писать?

Deleted
( 02.04.13 00:53:31 MSK )
Ответ на: комментарий от Deleted 02.04.13 00:40:42 MSK

Там все просто, вот смотри какая идея:

from Tkinter import * class WmDialog: def __init__(self): self.root=Tk() self.bntOk=Button (self.root, text="Kill Dialog",command=self.root.destroy).grid() self.bntCancel=Button (self.root, text="Exit from Script", command=exit).grid() def liveWnd (self): self.root.mainloop() dlg=WmDialog() dlg.liveWnd() print "I am destroy 1-st window" dlg=WmDialog() dlg.liveWnd() print "I am destroy 2-st window" print "Exit" 

Что тут происходит: ты создаешь класс с именем WmDialog (как раз аналог диалог-бокса, я его настраивать не стал — сам сделаешь, тут не сложно), который позволяет либо продолжить выполнение скрипта дальше (если нажмешь bntOk), либо вырубит скрипт (если нажмешь btnCancel). Когда ты нажимаешь bntOk вызывается метод destroy для окна dlg.root, которое и является корневым для цикла Tk(). После вывода первой надписи («I am destroy 1-st window»), мы снова создаем объект-окно. Ну и так далее :). Дальше сам придумаешь, я думаю.

silver-bullet-bfg ★★
( 02.04.13 09:26:40 MSK )
Ответ на: комментарий от silver-bullet-bfg 01.04.13 14:53:51 MSK

Какими местом для опроса диалога Вы хотите присобачить класс О_О?

from Tkinter import * from tkMessageBox import * def dialog(f, *L, **D): root=Tk(); root.withdraw() try: return f(*L, **D) finally: root.destroy() print dialog( askokcancel, '111', '222') print dialog( askokcancel, '333', '444') 

dialog подходит для вызова любого dialog-а. Для питона3 ТС думаю сможет адаптировать сам.

ЗЫ: ТС destroy вызывал ПОСЛЕ return, ясно что рут не закрывался;-) Ну и конструкции вида

if True: return True else: return False 

доставляют;-)
AIv ★★★★★
( 02.04.13 09:27:11 MSK )
Ответ на: комментарий от Novator 01.04.13 13:59:36 MSK

В винде Tk будет ставится вместе в Python (а вот Gtk придется отдельно доставлять), да и лучше документации чем по Tk в принципе не видел. Просто надо смотреть не только Tkinter доки, но и Tk чистого доки.

silver-bullet-bfg ★★
( 02.04.13 09:30:47 MSK )
Ответ на: комментарий от AIv 02.04.13 09:27:11 MSK

Ваше решение красивее:) Эх. Привык я уже все делать через ООП-извращения 🙁

silver-bullet-bfg ★★
( 02.04.13 09:33:26 MSK )
Ответ на: комментарий от silver-bullet-bfg 02.04.13 09:26:40 MSK

И даже если делать диалог ручками — накой там класс то? По дизайну это ф-я, вызвал — она все нарисовала — висит ждет решения юзера — закрылась и вернула результат. Классы тут актуальны либо когда есть несколько вызовов для работы с одними и теми же данными, либо когда нужно сделать какой то полуфабрикат (сложный виджет) для повторного испольщования.

AIv ★★★★★
( 02.04.13 09:34:09 MSK )
Ответ на: комментарий от silver-bullet-bfg 02.04.13 09:33:26 MSK

Дык переходите на ФП! Даже для гуйни оно иногда бывает весьма полезно;-)

AIv ★★★★★
( 02.04.13 09:35:02 MSK )
Ответ на: комментарий от AIv 02.04.13 09:35:02 MSK

Вот и хочу на ФП перейти, только пока не получается. А вы случайно не подскажите, какой ФП язык наиболее хорошо работает с гуйней? Сейчас как раз пишу «домашний» проект на C#+Gtk, но честно — уже воротит от этой дряни (C#/ООП).

silver-bullet-bfg ★★
( 02.04.13 10:11:52 MSK )
Ответ на: комментарий от AIv 02.04.13 09:34:09 MSK

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

silver-bullet-bfg ★★
( 02.04.13 10:13:17 MSK )
Ответ на: комментарий от silver-bullet-bfg 02.04.13 10:11:52 MSK

Ну я пишу на питоне, ФП там есть, и в гуйне оно вполне актуально

Дизайн окна с помощью python tkinter

Есть ли способы создать дизайн окна (рамку, форму) и убрать кнопки Свернуть, Развернуть и Закрыть? Хочу их заменить на свои, пока костыляю, но это не красиво.

Лучший ответ

помоему кнопки можно только заблокировать, но не убрать
если ты хочешь замутить дизайн в стиле окон антивируса, то тут уже наверное нужен Python Qt или pygame. Кстати именно под такую тему есть специализированный фрейм Electron, но он уже для JavaScript

Clarke GriffinУченик (97) 3 года назад
Я имела ввиду tkinter только, в вопросе написано. Попробую пока с ним работать. Но спасибо все равно
Остальные ответы

можно с помощью метода Tk.overrideredirect(1) убрать заголовок вообще и тогда сделать свои кнопки. Однако двигать окно по экрану будет невозможно

Ученик (145) 8 месяцев назад

аноним аноним Мыслитель (8111) -, Неужели это наконец-то пофиксили? Это какая версия Python? Я помню, что когда-то пробовал на 3.6.5 и у меня тогда еще не работало

Ученик (145) 8 месяцев назад

Это можно зделать с помощью небольшого костыля
Вот код если надо

class move(Tk):
def __init__(self,master=None):
Tk.__init__(self,master)
self.overrideredirect(True)
self._offsetx = 0
self._offsety = 0
self.bind(»,self.clickwin)
self.bind(»,self.dragwin)

def dragwin(self,event):
x = self.winfo_pointerx() — self._offsetx
y = self.winfo_pointery() — self._offsety
self.geometry(‘++’.format(x=x,y=y))

def clickwin(self,event):
self._offsetx = event.x
self._offsety = event.y

аноним аноним Мыслитель (8111) -, а, ну так-то да +bind сделать не на Tk (иначе полетит в дочерних), а на frame самодельной верхней строки

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *