В настоящее время я реализую образец пользовательского интерфейса для neovim и решил использовать Tkinter/python из-за популярности/простоты платформы. Проблема, с которой я сталкиваюсь, заключается в том, что tkinter, кажется, «складывает» обновления пользовательского интерфейса, когда высота окна пересекает определенный порог.
Вот видео, демонстрирующее проблему.
Правое окно — это эмулятор терминала под управлением neovim, а левое — подключенная к нему программа Tkinter UI. Идея состоит в том, что пользовательский интерфейс tkinter должен отражать экран терминала neovim, включая размеры. В этом видео никогда не отвлекайте внимание от окна терминала, поэтому единственные события, которые должен обрабатывать Tk, исходят от подключения к neovim (виртуальные события «nvim», которые описывают обновления экрана)
Первая часть видео показывает, что все работает хорошо, когда высота окна маленькая, но начинает отставать обновления, когда я увеличиваю высоту.
Вот код программы Tkinter. Хотя neovim API очень новый и все еще находится в активной разработке (код может быть непонятен для некоторых читателей), я думаю, что проблема, которую я пытаюсь решить, близка к реализации эмулятора терминала (с использованием текстового виджета Tk): он должен обрабатывать большие Пакеты обновлений форматированного текста эффективно.
Я очень неопытен в программировании GUI. Является ли Tkinter мудрым выбором для этой задачи? Если да, то может ли кто-нибудь подсказать, что я делаю неправильно?
Чтобы немного объяснить, что происходит: Neovim API является потокобезопасным, а метод vim.next_event()
блокируется (без активного ожидания, он использует цикл событий libuv внизу) до тех пор, пока не будет получено событие.
Когда вызов vim.next_event()
возвращается, он уведомляет поток Tkinter, используя generate_event
, который будет выполнять фактическую обработку событий (он также буферизует события между redraw:start
и redraw:stop
для оптимизации обновлений экрана).
Таким образом, на самом деле есть два цикла событий, работающих параллельно, причем цикл фоновых событий передает цикл событий Tkinter потокобезопасным способом (метод generate_event
— один из немногих, которые можно вызывать из других потоков).
after idle
будет срабатывать). Вы можете просто заполнить цикл событий большим количеством событий, чтобы перерисовка происходила только после того, как всплеск прошел. Добавьте к этому, что вы искусственно ограничиваете свой объект Queue размером 1, поэтому с ужасной многопоточностью Python вы платите много затрат на изменение потока повсюду. - person schlenk   schedule 19.06.2014