我正在尝试使用PyGObject和python
3编写简单的图形编辑器。我需要使用鼠标绘制具有不同颜色和宽度的线条。我发现类似的例子很多本,但没有更复杂。
如何在“绘制”事件之间保存绘制的图像?是否有增量绘制方式,或者在每个“绘制”事件上都必须重新绘制窗格?我发现可以保存路径,但是如何保存绘制线条的宽度和颜色?有没有办法在’draw’回调之外创建图像并仅在回调内部应用(draw)它?
这是我现在所拥有的。
#!/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()
Glade文件( 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
看起来像什么:
可以在http://cairographics.org/documentation/pycairo/3/reference/index.html中找到有关cairo的所有文档。
亲切的问候
PyGObject 是 GTK+ 和 GStreamer 的 Python 绑定,完善 Python 3 支持。 通过全新的 gobject-introspection 技术实现模块化动态链接,免去过去等待特定 GObject 的 Python API 的过程。 包含 Python 2 和 Python 3 支持。 制作完整 GNOME 3 应用程序。
更改画笔大小和钢笔压力的不透明度 如果您使用图形绘制绘图板(例如 Wacom® 绘图板),则可以通过钢笔压力、角度、旋转或光笔轮来控制绘画工具。 选择“画笔”、“铅笔” 或其他绘画工具。 在选项栏中,执行下列某个操作: 单击“绘图板压力控制大小”按钮。 单击“绘图板压力控制不透明度”按钮。 注意:选取“窗口”>“画笔”可访问根据钢笔压力而改变角度、流量、散布程度、纹理深度以及描边圆度的其他控制选项
了解形状和路径 Adobe Photoshop 中的绘图包括创建矢量形状和路径。在 Photoshop 中,可以使用任何形状工具、钢笔工具或自由钢笔工具进行绘制。在选项栏中可以使用每个工具的选项。 在 Photoshop 中开始进行绘图之前,必须从选项栏中选取绘图模式。选取的绘图模式将决定是在自身图层上创建矢量形状、还是在现有图层上创建工作路径或是在现有图层上创建栅格化形状。 矢量形状是使用形状或
问题内容: 我正在尝试将一些 非常简单的 图形绘制成a,但是我无法使其正常工作。没有例外,但我也看不到任何结果。 更确切地说,我正在尝试创建一个并用单一颜色填充它。 这是我的代码: 不出所料,我得到了 Drawing … 输出两次。 有人可以建议为什么我可能无法提取吗? 问题答案: 我删除了代理类,并将其全部移至我的活动中。现在正在工作。固定代码如下:
我有一个抛物线图,抛物线方程的系数存储在数组中。在(mousemotionlistener)中,抛物线的系数被更改,我想用新的系数实时更新抛物线图。我怎么才能让这一切发生?
问题内容: 我正在开发的Java Swing GUI需要根据程序中生成的x和y坐标绘制2D图形。 为此有一个Swing组件吗? 还是有其他目的的开源软件包? 问题答案: 您应该查看具有Swing支持的JFreeChart。以下是一些示例: http://www.jfree.org/jfreechart/samples.html