gpt4 book ai didi

python - 在 PyGobject 中绘图 (python3)

转载 作者:太空狗 更新时间:2023-10-30 02:22:30 25 4
gpt4 key购买 nike

我正在尝试使用 PyGObject 和 python 3 编写简单的图形编辑器。我需要使用鼠标绘制不同颜色和宽度的线条。我发现了很多例子,比如 this但没有比这更复杂的了。

如何在“绘制”事件之间保存绘制的图像?是否有渐进的绘图方式,或者我是否必须在每个“绘制”事件上重新绘制 Pane ?我发现我可以保存路径,但如何保存绘制线条的宽度和颜色?有没有办法在“绘制”回调之外创建图像并仅在回调内应用(绘制)它?

Here这是我现在拥有的。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from gi.repository import Gtk, Gdk
import os

class App(object):

main_ui = os.path.join(os.path.dirname(__file__), 'gui.glade')

def __init__(self):
self.builder = Gtk.Builder()
self.builder.add_from_file(self.main_ui)

self.main_window.connect('destroy', self.quit)
self.mw_quit_button.connect('clicked', self.quit)

self.mw_graph_editor_button.connect('clicked', self.show_window, self.graph_editor_window)
self.graph_editor_window.connect('delete-event', self.hide_window_delete)

self.ge_menubar_file_quit.connect('activate', self.hide_window, self.graph_editor_window)
self.ge_toolbar_quit.connect('clicked', self.hide_window, self.graph_editor_window)

self.ge_drawingarea.connect('motion-notify-event', self.pointer_motion)
self.ge_drawingarea.connect('motion-notify-event', self.show_coordinates)
self.ge_drawingarea.connect('draw', self.draw_callback)

self.path = None
self.coord = (0, 0)
self.rgb = (0, 0, 0)

def __getattr__(self, name):
obj = self.builder.get_object(name)
if not obj:
raise AttributeError("Object {0} has no attribute {1}".format(self, name))
setattr(self, name, obj)
return obj

def draw_callback(self, drawingarea, cr):
if self.path:
cr.append_path(self.path)
cr.line_to(self.coord[0], self.coord[1])
cr.set_source_rgba(*self.rgb)
self.path = cr.copy_path_flat()
cr.stroke()

def show_coordinates(self, window, event):
self.ge_mouse_coordinates.set_label('X: {0:.0f} Y: {1:.0f}'.format(event.x, event.y))

def pointer_motion(self, widget, event):
if event.state & Gdk.ModifierType.BUTTON1_MASK:
self.draw(widget, event.x, event.y)
elif event.state & Gdk.ModifierType.BUTTON3_MASK:
self.draw(widget, event.x, event.y, True)

def draw(self, widget, x, y, erase=False):
self.coord = (x,y)
if erase:
self.rgb = (256, 256, 256)
else:
self.rgb = (0, 0, 0)
widget.queue_draw()

def show_window(self, widget, data):
data.show_all()

def hide_window_delete(self, widget, event):
widget.hide()
return True

def hide_window(self, widget, window):
window.hide()

def run(self):
self.main_window.show_all()
Gtk.main()

def quit(self, widget=None, data=None):
self.main_window.destroy()
Gtk.main_quit()


if __name__ == "__main__":
app = App()
app.run()

对不起我的英语,它不是我的母语。

最佳答案

你需要使用双缓冲技术:

http://en.wikipedia.org/wiki/Multiple_buffering#Double_buffering_in_computer_graphics

那就是你有一个图像,然后在该图像上绘制:该图像是“幕后”缓冲区。你可以有很多方法来为该图像绘制一些东西。然后,在响应“绘制”信号的回调中,即实际向图形内存中绘制内容的方法,您只需将“幕后”图像抛出即可。

代码中的理论(test.py):

import cairo
from gi.repository import Gtk
from os.path import abspath, dirname, join

WHERE_AM_I = abspath(dirname(__file__))

class MyApp(object):
"""Double buffer in PyGObject with cairo"""

def __init__(self):
# Build GUI
self.builder = Gtk.Builder()
self.glade_file = join(WHERE_AM_I, 'test.glade')
self.builder.add_from_file(self.glade_file)

# Get objects
go = self.builder.get_object
self.window = go('window')

# Create buffer
self.double_buffer = None

# Connect signals
self.builder.connect_signals(self)

# Everything is ready
self.window.show()

def draw_something(self):
"""Draw something into the buffer"""
db = self.double_buffer
if db is not None:
# Create cairo context with double buffer as is DESTINATION
cc = cairo.Context(db)

# Scale to device coordenates
cc.scale(db.get_width(), db.get_height())

# Draw a white background
cc.set_source_rgb(1, 1, 1)

# Draw something, in this case a matrix
rows = 10
columns = 10
cell_size = 1.0 / rows
line_width = 1.0
line_width, notused = cc.device_to_user(line_width, 0.0)

for i in range(rows):
for j in range(columns):
cc.rectangle(j * cell_size, i * cell_size, cell_size, cell_size)
cc.set_line_width(line_width)
cc.set_source_rgb(0, 0, 0)
cc.stroke()

# Flush drawing actions
db.flush()

else:
print('Invalid double buffer')

def main_quit(self, widget):
"""Quit Gtk"""
Gtk.main_quit()

def on_draw(self, widget, cr):
"""Throw double buffer into widget drawable"""

if self.double_buffer is not None:
cr.set_source_surface(self.double_buffer, 0.0, 0.0)
cr.paint()
else:
print('Invalid double buffer')

return False

def on_configure(self, widget, event, data=None):
"""Configure the double buffer based on size of the widget"""

# Destroy previous buffer
if self.double_buffer is not None:
self.double_buffer.finish()
self.double_buffer = None

# Create a new buffer
self.double_buffer = cairo.ImageSurface(\
cairo.FORMAT_ARGB32,
widget.get_allocated_width(),
widget.get_allocated_height()
)

# Initialize the buffer
self.draw_something()

return False

if __name__ == '__main__':
gui = MyApp()
Gtk.main()

空地文件(test.glade):

<?xml version="1.0" encoding="UTF-8"?>
<interface>
<!-- interface-requires gtk+ 3.0 -->
<object class="GtkWindow" id="window">
<property name="can_focus">False</property>
<property name="window_position">center-always</property>
<property name="default_width">800</property>
<property name="default_height">600</property>
<signal name="destroy" handler="main_quit" swapped="no"/>
<child>
<object class="GtkDrawingArea" id="drawingarea1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<signal name="draw" handler="on_draw" swapped="no"/>
<signal name="configure-event" handler="on_configure" swapped="no"/>
</object>
</child>
</object>
</interface>

依赖关系:

python 2:

sudo apt-get install python-cairo

python 3:

sudo apt-get install python3-gi-cairo

现在执行:

python test.py

python3 test.py

它的样子:

enter image description here

开罗的所有文档都可以在 http://cairographics.org/documentation/pycairo/3/reference/index.html 中找到

亲切的问候

关于python - 在 PyGobject 中绘图 (python3),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10270795/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com