GTK3 DrawingArea не рендерится/не обновляется, кроме как когда отводит взгляд и оглядывается назад
Я переношу некоторый старый код с gtk2 на gtk3 и сталкиваюсь с проблемами при обновлении/рендеринге/обновлении. Итак, gtk3 перешел на использованиеdrawвместо старогоexpose_eventи это привело к тому, что контекст стал аргументом функции, и я выяснил этот бит. Теперь в документации GTK3 я нашел это:
Сигналы рисования обычно подаются, когда область рисования впервые появляется на экране или когда она закрыта другим окном, а затем открыта. Вы также можете форсировать событие экспонирования, добавив в «область повреждения» окна области рисования; gtk_widget_queue_draw_area() и gdk_window_invalidate_rect() — одинаково хорошие способы сделать это. Затем вы получите сигнал отрисовки для недопустимой области.
И в моем коде я делаю это недействительным следующим образом:
import gi
gi.require_version('Gtk', '3.0')
gi.require_version('Gdk', '3.0')
from gi.repository import Gdk as gdk
from gi.repository import Gtk as gtk
from gi.repository import Pango as pango
from gi.repository import GLib as glib
def draw(self, ctx):
"""Draw the canvas."""
# wallpaper
ctx.set_source_rgb(0., 0., 0.)
ctx.rectangle(0, 0, 1, 1)
ctx.fill()
ctx.set_line_width(0.005)
ctx.set_line_join(cairo.LINE_JOIN_ROUND)
txtstart = 0.05
for i in sorted(self.draw_que):
item = self.draw_que[i]
#...
#DRAW WHAT'S IN QUEUE
#...
glib.timeout_add(self.refresh_interval, self.redraw)
def on_draw(self, widget, context):
"""Callback for draw (used to be expose_event)."""
rect = widget.get_allocation()
context.rectangle(0, 0, rect.width, rect.height)
context.clip()
context.scale(rect.width, rect.height)
self.draw(context)
return False
def redraw(self):
"""Callback for the idle_add drawing-loop."""
if self.get_property('window'):
alloc = self.get_allocation()
rect = gdk.Rectangle(0, 0, alloc.width, alloc.height)
self.get_property('window').invalidate_rect(rect, True)
self.get_property('window').process_updates(True)
И хоть убей, я не могу понять, почему область рисования обновляется только при переключении между окнами. я установилrefresh_interval = 50миллисекунд, и если я напечатаю refresh_interval прямо подglib.timeout_addcall, я получаю несколько отпечатков каждый раз, когда переключаюсь с окна графического интерфейса на терминал и обратно, в противном случае он ничего не печатает и явно не обновляется вообще, если только переключение окна не произошло.
Короче говоря, draw_queue[i] рисуется каждый раз, когда я переключаю активные окна, а затем «приклеивается» к этому значению, пока я снова не переключусь, а затем обновляется примерно четыре раза (поэтому перерисовка происходит в течение 200 мс). И моя цель - постоянно обновлять область рисования (каждые 50 мс).
Любые советы о том, как это исправить?
Использование Ubuntu 20.04, python 3.8 и gtk3
Раньше это работало над реализацией gtk2
Вот скриншот, когда я печатаю время события рисования:я печатаю текущее время каждый раз <code>on_draw</code>вызывается и вручную запускает программу, несколько раз переключает окна и закрывает программу.:wq
То же в тексте:
pygame 2.1.2 (SDL 2.0.16, Python 3.8.10)
Hello from the pygame community. https://www.pygame.org/contribute.html
Connecting to: <tobiiresearch.implementation.EyeTracker.EyeTracker object at 0x7ff0d53e5790>
draw event received at 2023-01-25 20:40:20.356367
draw event received at 2023-01-25 20:40:20.370740
draw event received at 2023-01-25 20:40:20.387894
draw event received at 2023-01-25 20:40:20.408587
draw event received at 2023-01-25 20:40:25.214985
draw event received at 2023-01-25 20:40:29.183180
draw event received at 2023-01-25 20:40:29.209396
draw event received at 2023-01-25 20:40:29.236468
draw event received at 2023-01-25 20:40:29.252261
draw event received at 2023-01-25 20:40:29.270075
draw event received at 2023-01-25 20:40:29.287464
draw event received at 2023-01-25 20:40:29.301483
draw event received at 2023-01-25 20:40:29.320029
draw event received at 2023-01-25 20:40:29.336251
draw event received at 2023-01-25 20:40:29.352848
draw event received at 2023-01-25 20:40:29.373359
draw event received at 2023-01-25 20:40:30.231043
draw event received at 2023-01-25 20:40:30.484992
ldrop mainloop stopped.
ldrop instance deleted.
1 ответ
Починил это.
Теперь я должен признать, что я не уверен на 100%, почему это работало в версии gtk2 с
Итак, в основном мой контроллер разделен на две части, представления и пользовательский интерфейс находятся в отдельных файлах. И так в отдельных петлях. (Это структура, которую я получил в старом коде python2, и да, я никогда раньше не работал с gtk или каким-либо графическим интерфейсом, поэтому мне потребовалось некоторое время, чтобы понять, что происходит.)
Итак, вкратце, у меня есть:
class Controller(EventEmitter):
"""Main controller of the class. Views+ui separated to different files."""
def __init__(self):
"""Constructor."""
# run the superclass constructor
EventEmitter.__init__(self)
# Model initialization code
self.sensors = []
self.tags = []
# ...
# all root dirs, plugins and such set here
# ...
def add_model(self, model):
"""Add a model to listen for."""
model.on("data", self.on_data) #Called when new data comes in
model.on("close_controller", self.on_close_controller)
model.on("start_collecting_data", self.on_start_collecting_data)
model.on("stop_collecting_data", self.on_stop_collecting_data)
model.on("log_message", self.on_log_message)
model.on("query", self.on_query)
def on_data(self, dp):
"""Callback for data-signal."""
if self.data_callback is not None:
glib.idle_add(self.data_callback, dp)
self.emit("draw") # All I did here is add this row
Все, что я сделал в
class ControllerView:
"""A pygtk-view for drop controller."""
def __init__(self, ctrl, savedir):
"""Constructor."""
# view knows the controller function calls
self.ctrl = ctrl
self.ctrl.on("sensorcount_changed", self.on_sensors_changed)
self.ctrl.on("participant_id_updated", self.on_id_updated)
self.ctrl.on("log_update", self.on_log_update)
self.ctrl.on("error", self.on_error)
self.ctrl.on("draw", self.on_draw) # Added this here to catch the draw event
# Then I added the on_draw reaction to the draw event
def on_draw(self):
"""Callback for draw event"""
self.draw_area.queue_draw()
Я знаю, что это, вероятно, не лучший способ исправить это, так как теперь изображение обновляется каждый раз, когда датчик отправляет данные (насколько мне известно, до 250 Гц), и отрисовки со скоростью 20 или 25 кадров в секунду будет более чем достаточно. ... Так что теперь это будет намного тяжелее. Любые предложения по исправлению этого?