滚动事件后在 Gtk.DrawingArea() 中维护开罗绘图
Maintaining a Cairo drawing in Gtk.DrawingArea() after scroll event
我正在为一些图像开发一个注释工具,并决定使用 GTK 来完成这项任务。我有一个 Gtk.DrawingArea() 嵌套在 Gtk.Viewport() 中,它嵌套在 Gtk.ScrolledWindow() 中以启用绘图区域的滚动。绘图区域包含一个图像,并且在每次单击鼠标事件时使用 Cairo 在图像顶部绘制形状。
如果我理解正确,默认情况下滚动会导致 Gtk.DrawingArea() 重绘,这会使所有形状消失。有什么办法(除了保留坐标列表并在每个滚动事件上重新绘制每个形状)来保持这些形状吗?
import gi
import math
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk, GdkPixbuf
class MainWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title = "Test")
self.drag = False
self.drag_x = 0
self.drag_y = 0
self.pos = []
viewport = Gtk.Viewport()
self.darea = Gtk.DrawingArea()
self.darea.connect("draw", self.expose)
self.pixbuf = GdkPixbuf.Pixbuf.new_from_file("anntool/test.jpg")
self.darea.set_size_request(self.pixbuf.get_width(), self.pixbuf.get_height());
self.maximize() # maximize window on load
grid = Gtk.Grid()
self.add(grid)
scrolled = Gtk.ScrolledWindow()
scrolled.set_hexpand(True)
scrolled.set_vexpand(True)
scrolled.set_kinetic_scrolling(True)
self.v_scroll = scrolled.get_vadjustment()
self.h_scroll = scrolled.get_hadjustment()
scrolled.add_events(Gdk.EventMask.POINTER_MOTION_MASK | Gdk.EventMask.BUTTON_PRESS_MASK | Gdk.EventMask.BUTTON_RELEASE_MASK)
scrolled.connect("button-release-event", self.release)
scrolled.connect("button-press-event", self.click)
scrolled.connect("motion-notify-event", self.mousemove)
# scrolled.connect("scroll_event", self.scroll)
viewport.add(self.darea)
scrolled.add(viewport)
grid.add(scrolled)
def click(self, widget, event):
if (event.button == 1):
cr = self.darea.get_parent_window().cairo_create()
x = self.h_scroll.get_value() + event.x
y = self.v_scroll.get_value() + event.y
cr.arc(x, y, 10, 0, 2 * math.pi)
cr.set_source_rgba(0.0, 0.6, 0.0, 1)
cr.fill()
if (event.button == 2):
self.drag = True
self.drag_x = event.x
self.drag_y = event.y
self.pos = [self.h_scroll.get_value(), self.v_scroll.get_value()]
def release(self, widget, event):
self.drag = False
default = Gdk.Cursor(Gdk.CursorType.ARROW)
widget.get_window().set_cursor(default)
def mousemove(self, widget, event):
if self.drag:
self.h_scroll.set_value(self.pos[0] + self.drag_x - event.x)
self.v_scroll.set_value(self.pos[1] + self.drag_y - event.y)
hand = Gdk.Cursor(Gdk.CursorType.HAND1)
widget.get_window().set_cursor(hand)
def scroll(self, widget, event):
print("scrolled")
def expose(self, widget, event):
Gdk.cairo_set_source_pixbuf(event, self.pixbuf, 0, 0)
event.paint()
win = MainWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
正如 Uli Schlachter 指出的那样,重绘是在每个滚动事件上执行的,因此需要跟踪添加的点(例如使用列表)并重绘上面代码中 expose()
函数中的每个点。
我正在为一些图像开发一个注释工具,并决定使用 GTK 来完成这项任务。我有一个 Gtk.DrawingArea() 嵌套在 Gtk.Viewport() 中,它嵌套在 Gtk.ScrolledWindow() 中以启用绘图区域的滚动。绘图区域包含一个图像,并且在每次单击鼠标事件时使用 Cairo 在图像顶部绘制形状。
如果我理解正确,默认情况下滚动会导致 Gtk.DrawingArea() 重绘,这会使所有形状消失。有什么办法(除了保留坐标列表并在每个滚动事件上重新绘制每个形状)来保持这些形状吗?
import gi
import math
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk, GdkPixbuf
class MainWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title = "Test")
self.drag = False
self.drag_x = 0
self.drag_y = 0
self.pos = []
viewport = Gtk.Viewport()
self.darea = Gtk.DrawingArea()
self.darea.connect("draw", self.expose)
self.pixbuf = GdkPixbuf.Pixbuf.new_from_file("anntool/test.jpg")
self.darea.set_size_request(self.pixbuf.get_width(), self.pixbuf.get_height());
self.maximize() # maximize window on load
grid = Gtk.Grid()
self.add(grid)
scrolled = Gtk.ScrolledWindow()
scrolled.set_hexpand(True)
scrolled.set_vexpand(True)
scrolled.set_kinetic_scrolling(True)
self.v_scroll = scrolled.get_vadjustment()
self.h_scroll = scrolled.get_hadjustment()
scrolled.add_events(Gdk.EventMask.POINTER_MOTION_MASK | Gdk.EventMask.BUTTON_PRESS_MASK | Gdk.EventMask.BUTTON_RELEASE_MASK)
scrolled.connect("button-release-event", self.release)
scrolled.connect("button-press-event", self.click)
scrolled.connect("motion-notify-event", self.mousemove)
# scrolled.connect("scroll_event", self.scroll)
viewport.add(self.darea)
scrolled.add(viewport)
grid.add(scrolled)
def click(self, widget, event):
if (event.button == 1):
cr = self.darea.get_parent_window().cairo_create()
x = self.h_scroll.get_value() + event.x
y = self.v_scroll.get_value() + event.y
cr.arc(x, y, 10, 0, 2 * math.pi)
cr.set_source_rgba(0.0, 0.6, 0.0, 1)
cr.fill()
if (event.button == 2):
self.drag = True
self.drag_x = event.x
self.drag_y = event.y
self.pos = [self.h_scroll.get_value(), self.v_scroll.get_value()]
def release(self, widget, event):
self.drag = False
default = Gdk.Cursor(Gdk.CursorType.ARROW)
widget.get_window().set_cursor(default)
def mousemove(self, widget, event):
if self.drag:
self.h_scroll.set_value(self.pos[0] + self.drag_x - event.x)
self.v_scroll.set_value(self.pos[1] + self.drag_y - event.y)
hand = Gdk.Cursor(Gdk.CursorType.HAND1)
widget.get_window().set_cursor(hand)
def scroll(self, widget, event):
print("scrolled")
def expose(self, widget, event):
Gdk.cairo_set_source_pixbuf(event, self.pixbuf, 0, 0)
event.paint()
win = MainWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
正如 Uli Schlachter 指出的那样,重绘是在每个滚动事件上执行的,因此需要跟踪添加的点(例如使用列表)并重绘上面代码中 expose()
函数中的每个点。