Просмотрите мои изменения внизу, теперь эта проблема связана с ОС.
GIF-изображение проблемы в действии
Итак, у меня проблема с экземпляром ttk.OptionMenu . Я успешно реализовал этот виджет раньше, однако я пытаюсь использовать его здесь как раскрывающийся список для доступных файлов во всплывающем окне, и мне кажется, что он не работает правильно.
Проблема
- Виден только первый вариант в меню, другие варианты недоступны
- Он не реагирует на мышь, кроме того, что он затемняется при нажатии
- Когда по нему щелкают, в терминале не отображаются ошибки или выходные данные, что затрудняет отслеживание
Код
Фактический вызов выполняется из другого файла, скажем myproject/main.py
from classes.load_window import *
start_load_menu()
Класс для этого хранится в файле по адресу myproject/classes/load_window.py
, и он обращается к файлам сохранения, хранящимся в myproject/saved/
import tkinter
import tkinter.ttk as ttk
from os import listdir
from os.path import join, isfile
class LoadMenu(object):
def __init__(self):
root = self.root = tkinter.Tk()
root.title("Save Manager")
root.overrideredirect(True)
""" MAIN FRAME """
frm_1 = ttk.Frame(root)
frm_1.pack(ipadx=2, ipady=2)
""" MESSAGE LABEL """
self.msg = str("Would you like to load from a save file?")
message = ttk.Label(frm_1, text=self.msg)
message.pack(padx=8, pady=8)
""" INNER FRAME """
frm_2 = ttk.Frame(frm_1)
frm_2.pack(padx=4, pady=4)
""" TEST IMPLEMENTAITON [DOES NOT WORK] """
mylist = ['1', '2', '3', '4', '5', '6', '7']
test_var = tkinter.StringVar(frm_2)
test_var.set(mylist[3])
test_dropdown = ttk.OptionMenu(frm_2, test_var, *mylist)
test_dropdown.pack(padx=4, pady=4)
print(mylist) # Results in ['1', '2', '3', '4', '5', '6', '7']
""" REAL IMPLEMENTATION [ALSO DOES NOT WORK] """
files = [f for f in listdir('saved') if isfile(join('saved', f))]
file_var = tkinter.StringVar(frm_2)
file_var.set(files[3])
file_dropdown = ttk.OptionMenu(frm_2, file_var, *files)
file_dropdown.pack(padx=4, pady=4)
print(files) # Results in ['DS_Store', 'test1', 'test2', 'test3']
""" BUTTON FUNCTIONALITY """
btn_1 = ttk.Button(frm_2, width=8, text="Load File")
btn_1['command'] = self.b1_action
btn_1.pack(side='left')
btn_2 = ttk.Button(frm_2, width=8, text="Cancel")
btn_2['command'] = self.b2_action
btn_2.pack(side='left')
btn_3 = ttk.Button(frm_2, width=8, text="Create New")
btn_3['command'] = self.b3_action
btn_3.pack(side='left')
btn_2.bind('<KeyPress-Return>', func=self.b3_action)
root.update_idletasks()
""" Position the window """
xp = (root.winfo_screenwidth() // 2) - (root.winfo_width() // 2)
yp = (root.winfo_screenheight() // 2) - (root.winfo_height() // 2)
geom = (root.winfo_width(), root.winfo_height(), xp, yp)
root.geometry('{0}x{1}+{2}+{3}'.format(*geom))
root.protocol("WM_DELETE_WINDOW", self.close_mod)
root.deiconify()
def b1_action(self, event=None):
print("B1")
def b2_action(self, event=None):
self.root.quit()
def b3_action(self, event=None):
print("B3")
def nothing(self):
print("nothing")
def close_mod(self):
pass
def time_out(self):
print ("TIMEOUT")
def to_clip(self, event=None):
self.root.clipboard_clear()
self.root.clipboard_append(self.msg)
def start_load_menu():
menu = LoadMenu()
menu.root.mainloop()
menu.root.destroy()
return menu.returning
Примечания
Этот код основан на ответе здесь для всплывающего окна, которое я адаптирую для конкретной цели (меню загрузки).
Я сократил этот код до минимума, чтобы воспроизвести проблему, но вы, вероятно, можете игнорировать определения функций и геометрию окна.
Все работает отлично, кроме этого; окно отображается в центре экрана, а кнопка с фактическими функциями закрывает окно, это просто странная причуда с OptionMenu, с которой я не могу найти никого, с кем еще борются ни здесь, ни на других форумах.
Если вы не видели ссылку вверху, вы можете найти демонстрацию проблемного поведения по этой ссылке. а>
Я использую Python 3.6.4 в OSX 10.12.6
EDIT:
С тех пор я протестировал этот код на виртуальной машине под управлением Hydrogen Linux, , и он отлично работает . Тогда мой вопрос немного изменится:
Как я могу убедиться, что этот код хорошо транслируется в OSX? Можно ли прочитать о расхождениях между запуском TKinter на разных платформах?
Я нашел эту страницу по вопросам, связанным с Python, TKinter и OSX, но даже при использовании рекомендованных пакетов TCL с последней стабильной версией Python эта проблема сохраняется.
РЕДАКТИРОВАТЬ 2:
Просто для обновления, с тех пор я нашел способ решения проблемы. Это не отвечает на вопрос о странном поведении OptionMenu, но я решил, что отредактирую. Честно говоря, я думаю, что Listbox, вероятно, лучше подходит для того, чем я хотел заниматься. Вот оно в действии.
Пожалуйста, дайте мне знать, если мне нужно внести какие-либо правки для ясности или предоставить дополнительную информацию. Поскольку я новичок в stackoverflow, у меня нет особых проблем с обменом опытом. Спасибо!
2 ответа
Я разобрался!
После дальнейшего изучения этой проблемы я сократил код до минимума (что, вероятно, мне следовало сделать перед публикацией здесь ...) и смог определить root.overrideredirect(True)
как строку с нарушением.
При использовании overrideredirect(True)
необходимо также использовать update_idletasks()
раньше, чтобы гарантировать правильное обновление виджета. Хотя кажется, что Linux по-прежнему может производить нормальное поведение без ручного обновления неактивных задач, OS X не может, поэтому возникает необходимость в предисловии к коду
root.update_idletasks()
Вот хороший отрывок из документации, которую я нашел в ответе Биллала BEGUERADJ на вопрос overrideredirect ().
Если вы хотите принудительно обновить отображение до следующего простоя приложения, вызовите метод w.update_idletasks () для любого виджета.
Некоторые задачи по обновлению отображения, такие как изменение размера и перерисовка виджетов, называются неактивными задачами, потому что они обычно откладываются до тех пор, пока приложение не завершит обработку событий и не вернется в основной цикл для ожидания новых событий.
Если вы хотите принудительно обновить отображение до следующего простоя приложения, вызовите метод w.update_idletasks () для любого виджета.
Хотя я до сих пор не понимаю, почему именно этот виджет ломается без update_idletasks()
в OSX, теперь я понимаю, почему рекомендуется использовать update_idletasks()
в сочетании с overrideredirect()
для обеспечения согласованного поведения.
Надеюсь, это поможет всем, кто может на этом зациклиться.
Если ничего не делать, кроме изменения «файлов» на жестко запрограммированный список, программа может работать на моем компьютере. Я больше ничем не могу вам помочь.
import tkinter
import tkinter.ttk as ttk
from os import listdir
from os.path import join, isfile
class LoadMenu(object):
def __init__(self):
root = self.root = tkinter.Tk()
root.title("Save Manager")
root.overrideredirect(True)
""" MAIN FRAME """
frm_1 = ttk.Frame(root)
frm_1.pack(ipadx=2, ipady=2)
""" MESSAGE LABEL """
self.msg = str("Would you like to load from a save file?")
message = ttk.Label(frm_1, text=self.msg)
message.pack(padx=8, pady=8)
""" INNER FRAME """
frm_2 = ttk.Frame(frm_1)
frm_2.pack(padx=4, pady=4)
""" TEST IMPLEMENTAITON [DOES NOT WORK] """
mylist = ['1', '2', '3', '4', '5', '6', '7']
test_var = tkinter.StringVar(frm_2)
test_var.set(mylist[3])
test_dropdown = ttk.OptionMenu(frm_2, test_var, *mylist)
test_dropdown.pack(padx=4, pady=4)
print(mylist) # Results in ['1', '2', '3', '4', '5', '6', '7']
""" REAL IMPLEMENTATION [ALSO DOES NOT WORK] """
##files = [f for f in listdir('saved') if isfile(join('saved', f))]
files=['a', 'b', 'c', 'd', 'e', 'f']
file_var = tkinter.StringVar(frm_2)
file_var.set(files[3])
file_dropdown = ttk.OptionMenu(frm_2, file_var, *files)
file_dropdown.pack(padx=4, pady=4)
print(files) # Results in ['DS_Store', 'test1', 'test2', 'test3']
""" BUTTON FUNCTIONALITY """
btn_1 = ttk.Button(frm_2, width=8, text="Load File")
btn_1['command'] = self.b1_action
btn_1.pack(side='left')
btn_2 = ttk.Button(frm_2, width=8, text="Cancel")
btn_2['command'] = self.b2_action
btn_2.pack(side='left')
btn_3 = ttk.Button(frm_2, width=8, text="Create New")
btn_3['command'] = self.b3_action
btn_3.pack(side='left')
btn_2.bind('<KeyPress-Return>', func=self.b3_action)
root.update_idletasks()
""" Position the window """
xp = (root.winfo_screenwidth() // 2) - (root.winfo_width() // 2)
yp = (root.winfo_screenheight() // 2) - (root.winfo_height() // 2)
geom = (root.winfo_width(), root.winfo_height(), xp, yp)
root.geometry('{0}x{1}+{2}+{3}'.format(*geom))
root.protocol("WM_DELETE_WINDOW", self.close_mod)
root.deiconify()
def b1_action(self, event=None):
print("B1")
def b2_action(self, event=None):
self.root.quit()
def b3_action(self, event=None):
print("B3")
def nothing(self):
print("nothing")
def close_mod(self):
pass
def time_out(self):
print ("TIMEOUT")
def to_clip(self, event=None):
self.root.clipboard_clear()
self.root.clipboard_append(self.msg)
##def start_load_menu():
menu = LoadMenu()
menu.root.mainloop()
## menu.root.destroy()
## return menu.returning
Похожие вопросы
Связанные вопросы
Новые вопросы
unix
Этот тег является ИСКЛЮЧИТЕЛЬНО для ПРОГРАММИРОВАНИЯ вопросов, непосредственно связанных с Unix; общие проблемы с программным обеспечением следует направлять на сайт Unix & Linux Stack Exchange или на Super User. Операционная система Unix - это ОС общего назначения, которая была разработана Bell Labs в конце 1960-х годов и сегодня существует в различных версиях.