Форум программистов, компьютерный форум, киберфорум
Python: GUI, графика
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.60/25: Рейтинг темы: голосов - 25, средняя оценка - 4.60
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30

Модальный диалог

09.01.2020, 19:28. Показов 4864. Ответов 12

Студворк — интернет-сервис помощи студентам
Есть код:
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import tkinter as tk
import tkinter.ttk as ttk
  
class ButtonsFrame(tk.Frame):
  def __init__(self,master=None):
    super().__init__(master) 
    self.cancel_button = tk.Button(self, text="Отмена",width=10)    
    self.cancel_button.pack(side=tk.RIGHT,padx=5,pady=5)
 
    self.apply_button = tk.Button(self, text="Применить",width=10)
    self.apply_button.pack(side=tk.RIGHT,padx=5,pady=5)  
  
class Dialog(tk.Toplevel):
  Accepted = True
  Rejected = False
  def __init__(self,master=None):
     super().__init__(master)
     self.__result = Dialog.Rejected
 
     self.content_frame = tk.Frame(self)
     self.content_frame.pack(side=tk.TOP,fill=tk.BOTH,expand=True)
 
     self.__buttons_frame = ButtonsFrame(self)
     self.__buttons_frame.pack(side=tk.BOTTOM,fill=tk.X) 
     self.__buttons_frame.apply_button.bind("<Button-1>",self.__apply_button_pressed)
     self.__buttons_frame.cancel_button.bind("<Button-1>",self.__cancel_button_pressed)     
 
  def __apply_button_pressed(self,event):
     self.__result = Dialog.Accepted
     self.__close()
 
  def __cancel_button_pressed(self,event):
     self.__result = Dialog.Rejected
     self.__close()
 
  def __close(self): # close window without destroing
     self.grab_release()
     self.withdraw()
     self.quit()     
 
  def exec(self):
     self.to_master_center()
     self.focus_set()  # modal
     self.grab_set()
     self.mainloop()
     #self.master.wait_window(self)
     return  self.__result    
     
  def to_master_center(self):   
       if self.master:
          x0 = self.master.winfo_x()+self.winfo_reqwidth()//2
          y0 = self.master.winfo_y()+self.winfo_reqheight()//2
          x = x0 - self.winfo_reqwidth()//2
          y = y0 - self.winfo_reqheight()//2
          self.geometry('+{x}+{y}'.format(x=x, y=y))  
  
  
class PasswordDialog(Dialog):  
  def __init__(self,master=None):
     super().__init__(master)
     
     self.login_label = tk.Label(self.content_frame,text="Логин")
     self.login_label.grid(row=0,column=0)
     
     self.login = tk.StringVar()
     self.login_entry = tk.Entry(self.content_frame,textvar=self.login)
     self.login_entry.grid(row=0,column=1)
     
     self.password_label = tk.Label(self.content_frame,text="Пароль")
     self.password_label.grid(row=1,column=0)
     
     self.password = tk.StringVar()
     self.password_entry = tk.Entry(self.content_frame,textvar=self.password)     
     self.password_entry.grid(row=1,column=1)
     
     
class MainWindow(tk.Tk):
  def __init__(self,master=None):   
    super().__init__(master)
    self.button = tk.Button(self,text="Edit",command=self.button_pressed)
    self.button.pack(fill=tk.X)
    self.to_screen_center()
    
  def button_pressed(self):
    dialog = PasswordDialog(self)    
    if dialog.exec()==Dialog.Accepted:
       print(dialog.login.get())
       print(dialog.password.get())
    dialog.destroy()
    
  def to_screen_center(self):
     x = self.winfo_screenwidth()  // 2 - self.winfo_reqwidth() // 2
     y = self.winfo_screenheight() // 2 - self.winfo_reqheight() // 2
     self.geometry('+{x}+{y}'.format(x=x, y=y))
 
if __name__ == "__main__":
  window = MainWindow()
  window.mainloop()
Это код создает диалоговое окно.
Проблема его в том что периодически по завершению программы возникает исключение:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\fujitsu\AppData\Local\Programs \Python\Python37-32\lib\tkinter\__init__.py", line 1702, in __call__
return self.func(*args)
File "C:\Users\fujitsu\Desktop\testTk.py" , line 89, in button_pressed
dialog.destroy()
File "C:\Users\fujitsu\AppData\Local\Programs \Python\Python37-32\lib\tkinter\__init__.py", line 2302, in destroy
self.tk.call('destroy', self._w)
_tkinter.TclError: can't invoke "destroy" command: application has been destroyed
Можно ли вообще как то корректно прятать диалог не уничтожая его что бы использовать его содержимое/данные после закрытия?
0
Лучшие ответы (1)
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
09.01.2020, 19:28
Ответы с готовыми решениями:

Диалог в Qt Designer
Добрый день! Помогите, пожалуйста! Создала в Qt Designer диалог. Назвала файл Ui_My_dialog_ui.ui. В коде создала для него класс My_dialog....

Диалог на PyQt5
Как на PyQt сделать вывод текста как в диалоге Например как в сообщениях вк, телеграм, ватсапп и тд Очень долго бьюсь с этим вопросом ...

Диалог выбора даты
Добрый вечер. Подскажите, как в wxPython отобразить на панели элемент выбора даты? Какой элемент нужно использовать?

12
1293 / 677 / 367
Регистрация: 07.01.2019
Сообщений: 2,301
09.01.2020, 19:37
Цитата Сообщение от Avazart Посмотреть сообщение
как то корректно прятать диалог
есть команда именно скрытия dialog.withdraw()
0
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
09.01.2020, 19:38  [ТС]
Цитата Сообщение от tooru Посмотреть сообщение
есть команда именно скрытия dialog.withdraw()
Посмотрите мой код, я ее и использую. Вопрос в том как это делать корректно.

В интернете почему то примеры или с destroy() или с предварительным объявлением ф-ций обработчиков до диалога и передачей их в диалог.
0
1293 / 677 / 367
Регистрация: 07.01.2019
Сообщений: 2,301
09.01.2020, 19:54
Цитата Сообщение от Avazart Посмотреть сообщение
мой код, я ее и использую
В строке 38, но в строке 89 вы это окно уничтожаете
0
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
09.01.2020, 20:04  [ТС]
Цитата Сообщение от tooru Посмотреть сообщение
В строке 38, но в строке 89 вы это окно уничтожаете
Да конечно. Оно ведь мне больше не нужно. Проблема в то что походу оно уничтожено еще до этого. Вопрос в том как это получатся.
0
1293 / 677 / 367
Регистрация: 07.01.2019
Сообщений: 2,301
09.01.2020, 20:19
Цитата Сообщение от Avazart Посмотреть сообщение
Проблема в то что походу оно уничтожено еще до этого
Нет, оно уничтожается в момент закрытия, а вашу ошибку можно легко воспроизвести, запустите программу откройте диалог, не закрывая диалог закройте главное окно и будет эта ошибка
0
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
09.01.2020, 20:31  [ТС]
А как тогда принудительно уничтожить окно? Если закрывать и открывать окно - очевидно что это утечка ресурсов.
Кстати del dialog тоже не помогает, окно не уничтожается.
Добавлено через 55 секунд
Цитата Сообщение от tooru Посмотреть сообщение
запустите программу откройте диалог, не закрывая диалог закройте главное окно и будет эта ошибка
Модальность окна(фокус) не даст это сделать.
0
1293 / 677 / 367
Регистрация: 07.01.2019
Сообщений: 2,301
09.01.2020, 20:48
Цитата Сообщение от Avazart Посмотреть сообщение
Модальность окна(фокус) не даст это сделать.
Это я на Ubuntu запускал, там модальности нет, теперь перезагрузился в винду

Цитата Сообщение от Avazart Посмотреть сообщение
А как тогда принудительно уничтожить окно? Если закрывать и открывать окно - очевидно что это утечка ресурсов.
Окно диалога уничтожается сразу после закрытия

попробуйте два варианта

так

Python
1
2
3
4
5
6
7
def button_pressed(self):
    dialog = PasswordDialog(self)    
    if dialog.exec()==Dialog.Accepted:
       print(dialog.login.get())
       print(dialog.password.get())
    # dialog.destroy()
    dialog.deiconify()
и так

Python
1
2
3
4
5
6
7
def button_pressed(self):
    dialog = PasswordDialog(self)    
    if dialog.exec()==Dialog.Accepted:
       print(dialog.login.get())
       print(dialog.password.get())
    dialog.destroy()
    dialog.deiconify()
0
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
09.01.2020, 20:51  [ТС]
Цитата Сообщение от tooru Посмотреть сообщение
Это я на Ubuntu запускал, там модальности нет, теперь перезагрузился в винду
Мм как нет?

Добавлено через 51 секунду
Цитата Сообщение от tooru Посмотреть сообщение
Окно диалога уничтожается сразу после закрытия
После закрытия чего? Диалога или главного окна?
0
1293 / 677 / 367
Регистрация: 07.01.2019
Сообщений: 2,301
09.01.2020, 20:52
Цитата Сообщение от Avazart Посмотреть сообщение
После закрытия чего?
После закрытия диалога

Цитата Сообщение от Avazart Посмотреть сообщение
Мм как нет?
Вот нет, спокойно закрывал главное окно при открытом окне диалога
0
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
09.01.2020, 21:10  [ТС]
Цитата Сообщение от tooru Посмотреть сообщение
После закрытия диалога
Это и не понятно почему оно уничтожается само, а тогда когда я указываю в коде.

Цитата Сообщение от tooru Посмотреть сообщение
Вот нет, спокойно закрывал главное окно при открытом окне диалога
Блин оно еще не кроссплатформенно...

Добавлено через 10 минут
В обще как не печально признавать, но видимо единственный способ работать с диалогом это передавать ф-цию обработчик (что хорошо работает, но выглядит не очень в плане кода)

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
import tkinter as tk
  
class ButtonsFrame(tk.Frame):
  def __init__(self,master=None):
    super().__init__(master) 
    
    self.cancel_button = tk.Button(self, text="Отмена",width=10)    
    self.cancel_button.pack(side=tk.RIGHT,padx=5,pady=5)
 
    self.apply_button = tk.Button(self, text="Применить",width=10)
    self.apply_button.pack(side=tk.RIGHT,padx=5,pady=5)  
  
class Dialog(tk.Toplevel):
  def __init__(self,master=None,command=None):
     super().__init__(master)     
     self.__command = command
     #self.withdraw() # hide window
 
     self.content_frame = tk.Frame(self)
     self.content_frame.pack(side=tk.TOP,fill=tk.BOTH,expand=True)
 
     self.__buttons_frame = ButtonsFrame(self)
     self.__buttons_frame.pack(side=tk.BOTTOM,fill=tk.X) 
     self.__buttons_frame.apply_button.bind("<Button-1>",self.__apply_button_pressed)
     self.__buttons_frame.cancel_button.bind("<Button-1>",self.__cancel_button_pressed)     
 
  def __apply_button_pressed(self,event):
     if self.__command:
       self.__command(self,True)
     self.destroy()
 
  def __cancel_button_pressed(self,event):
     if self.__command:
       self.__command(self,False)
     self.destroy()     
 
  def exec(self):
     self.to_master_center()
     #self.deiconify()  # show window
     self.focus_set()  # modal
     self.grab_set()
     #self.master.wait_window(self)
     self.mainloop()
 
  def to_master_center(self):   
       if self.master:
          x0 = self.master.winfo_x()+self.winfo_reqwidth()//2
          y0 = self.master.winfo_y()+self.winfo_reqheight()//2
          x = x0 - self.winfo_reqwidth()//2
          y = y0 - self.winfo_reqheight()//2
          self.geometry('+{x}+{y}'.format(x=x, y=y))  
  
  
class PasswordDialog(Dialog):  
  def __init__(self,master=None,command=None):
     super().__init__(master,command)
     
     self.login_label = tk.Label(self.content_frame,text="Логин")
     self.login_label.grid(row=0,column=0)
     
     self.login = tk.StringVar()
     self.login_entry = tk.Entry(self.content_frame,textvar=self.login)
     self.login_entry.grid(row=0,column=1)
     
     self.password_label = tk.Label(self.content_frame,text="Пароль")
     self.password_label.grid(row=1,column=0)
     
     self.password = tk.StringVar()
     self.password_entry = tk.Entry(self.content_frame,textvar=self.password)     
     self.password_entry.grid(row=1,column=1)
     
     
class MainWindow(tk.Tk):
  def __init__(self,master=None):   
    super().__init__(master)
    self.button = tk.Button(self,text="Edit",command=self.button_pressed)
    self.button.pack(fill=tk.X)
    self.to_screen_center()
      
  def button_pressed(self):
  
    def dialog_closed(dialog,accepted):
      if accepted:
        print(dialog.login.get())
        print(dialog.password.get())         
        
    dialog = PasswordDialog(self,dialog_closed)    
    dialog.exec()
    
  def to_screen_center(self):
     x = self.winfo_screenwidth()  // 2 - self.winfo_reqwidth() // 2
     y = self.winfo_screenheight() // 2 - self.winfo_reqheight() // 2
     self.geometry('+{x}+{y}'.format(x=x, y=y))
 
if __name__ == "__main__":
  window = MainWindow()
  window.mainloop()
1
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
12.01.2020, 21:48  [ТС]
Есть еще такой вопрос: можно ли что бы под виндой не создавалась отдельная иконка на панели задач при создании диалога?
0
1293 / 677 / 367
Регистрация: 07.01.2019
Сообщений: 2,301
12.01.2020, 22:56
Лучший ответ Сообщение было отмечено Avazart как решение

Решение

Цитата Сообщение от Avazart Посмотреть сообщение
можно ли что бы под виндой не создавалась отдельная иконка на панели задач при создании диалога?
Что-то такое

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
import tkinter as tk
root = tk.Tk()
root.title('main')
root.geometry('300x300')
 
def dialog():
    t = tk.Toplevel()
    t.title('Второе окно') 
    t.geometry('100x100')
    t.transient(root) 
 
tk.Button(root, text='click', command=dialog).pack()
root.mainloop()
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
12.01.2020, 22:56
Помогаю со студенческими работами здесь

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

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

Многошаговый диалог с пользователем
Здравствуйте, уважаемые коллеги! С недавних пор самостоятельно изучаю Django и пытаюсь писать с его помощью скромный проектик. В...

Модальный диалог да/нет
Как вызвать ShowMessage (или как еще) что бы появилось модальное окно с вопросом и кнопками да/нет? и после вызова в продолжении функции...

MFC модальный диалог
Здравствуйте. Собственно, такая проблема возникла - MFC приложение, диалоговое, есть главный диалог, есть второй диалог, их классы,...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
13
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Основы отладки веб-приложений на SDL3 по USB и Wi-Fi, запущенных в браузере мобильных устройств
8Observer8 07.02.2026
Содержание блога Браузер Chrome имеет средства для отладки мобильных веб-приложений по USB. В этой пошаговой инструкции ограничимся работой с консолью. Вывод в консоль - это часть процесса. . .
SDL3 для Web (WebAssembly): Обработчик клика мыши в браузере ПК и касания экрана в браузере на мобильном устройстве
8Observer8 02.02.2026
Содержание блога Для начала пошагово создадим рабочий пример для подготовки к экспериментам в браузере ПК и в браузере мобильного устройства. Потом напишем обработчик клика мыши и обработчик. . .
Философия технологии
iceja 01.02.2026
На мой взгляд у человека в технических проектах остается роль генерального директора. Все остальное нейронки делают уже лучше человека. Они не могут нести предпринимательские риски, не могут. . .
SDL3 для Web (WebAssembly): Вывод текста со шрифтом TTF с помощью SDL3_ttf
8Observer8 01.02.2026
Содержание блога В этой пошаговой инструкции создадим с нуля веб-приложение, которое выводит текст в окне браузера. Запустим на Android на локальном сервере. Загрузим Release на бесплатный. . .
SDL3 для Web (WebAssembly): Сборка C/C++ проекта из консоли
8Observer8 30.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
SDL3 для Web (WebAssembly): Установка Emscripten SDK (emsdk) и CMake для сборки C и C++ приложений в Wasm
8Observer8 30.01.2026
Содержание блога Для того чтобы скачать Emscripten SDK (emsdk) необходимо сначало скачать и уставить Git: Install for Windows. Следуйте стандартной процедуре установки Git через установщик. . . .
SDL3 для Android: Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 29.01.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами. Версия v3 была полностью переписана на Си, в. . .
Инструменты COM: Сохранение данный из VARIANT в файл и загрузка из файла в VARIANT
bedvit 28.01.2026
Сохранение базовых типов COM и массивов (одномерных или двухмерных) любой вложенности (деревья) в файл, с возможностью выбора алгоритмов сжатия и шифрования. Часть библиотеки BedvitCOM Использованы. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru