原文: https://zetcode.com/gfx/pycairo/basicdrawing/

在 PyCairo 教程的这一部分中,我们绘制了一些基本图元。 我们使用填充和描边操作,笔划线,线帽和线连接。

直线

线是非常基本的矢量对象。 要画一条线,我们使用两个方法调用。 通过move_to()调用指定起点。 线的终点通过line_to()调用指定。

lines.py

  1. #!/usr/bin/python
  2. '''
  3. ZetCode PyCairo tutorial
  4. In this program, we connect all mouse
  5. clicks with a line.
  6. Author: Jan Bodnar
  7. Website: zetcode.com
  8. Last edited: April 2016
  9. '''
  10. from gi.repository import Gtk, Gdk
  11. import cairo
  12. class MouseButtons:
  13. LEFT_BUTTON = 1
  14. RIGHT_BUTTON = 3
  15. class Example(Gtk.Window):
  16. def __init__(self):
  17. super(Example, self).__init__()
  18. self.init_ui()
  19. def init_ui(self):
  20. self.darea = Gtk.DrawingArea()
  21. self.darea.connect("draw", self.on_draw)
  22. self.darea.set_events(Gdk.EventMask.BUTTON_PRESS_MASK)
  23. self.add(self.darea)
  24. self.coords = []
  25. self.darea.connect("button-press-event", self.on_button_press)
  26. self.set_title("Lines")
  27. self.resize(300, 200)
  28. self.set_position(Gtk.WindowPosition.CENTER)
  29. self.connect("delete-event", Gtk.main_quit)
  30. self.show_all()
  31. def on_draw(self, wid, cr):
  32. cr.set_source_rgb(0, 0, 0)
  33. cr.set_line_width(0.5)
  34. for i in self.coords:
  35. for j in self.coords:
  36. cr.move_to(i[0], i[1])
  37. cr.line_to(j[0], j[1])
  38. cr.stroke()
  39. del self.coords[:]
  40. def on_button_press(self, w, e):
  41. if e.type == Gdk.EventType.BUTTON_PRESS \
  42. and e.button == MouseButtons.LEFT_BUTTON:
  43. self.coords.append([e.x, e.y])
  44. if e.type == Gdk.EventType.BUTTON_PRESS \
  45. and e.button == MouseButtons.RIGHT_BUTTON:
  46. self.darea.queue_draw()
  47. def main():
  48. app = Example()
  49. Gtk.main()
  50. if __name__ == "__main__":
  51. main()

在我们的示例中,我们用鼠标左键随机单击窗口。 每次点击都存储在一个列表中。 当我们右键单击窗口时,所有点都与列表中的每个其他点相连。 右键单击将清除窗口。

  1. class MouseButtons:
  2. LEFT_BUTTON = 1
  3. RIGHT_BUTTON = 3

GTK 文档仅声明鼠标左键的编号为 1,鼠标右键的编号为 3。我们创建了一个自定义类,其中包含一些鼠标键的标识符。

  1. self.darea.set_events(Gdk.EventMask.BUTTON_PRESS_MASK)

默认情况下,某些事件未启用。 鼠标按下事件就在其中。 因此,我们需要使用set_event()方法启用鼠标按下事件。

  1. self.darea.connect("button-press-event", self.on_button_press)

在此代码示例中,我们对鼠标按下事件做出反应。

  1. cr.set_source_rgb(0, 0, 0)
  2. cr.set_line_width(0.5)

线条以黑色墨水绘制,宽度为 0.5 点。

  1. for i in self.coords:
  2. for j in self.coords:
  3. cr.move_to(i[0], i[1])
  4. cr.line_to(j[0], j[1])
  5. cr.stroke()

我们将列表中的每个点连接到其他每个点。 stroke()调用画线。

  1. del self.coords[:]

最后,将删除所有坐标。 现在,我们可以创建另一个对象。

  1. def on_button_press(self, w, e):
  2. if e.type == Gdk.EventType.BUTTON_PRESS \
  3. and e.button == MouseButtons.LEFT_BUTTON:
  4. self.coords.append([e.x, e.y])
  5. ...

如果按下鼠标左键,我们会将其 x 和 y 坐标添加到self.coords列表中。

  1. if e.type == Gdk.EventType.BUTTON_PRESS \
  2. and e.button == MouseButtons.RIGHT_BUTTON:
  3. self.darea.queue_draw()

在按下鼠标右键的情况下,我们调用queue_draw()方法来重绘绘图区域。 所有的点都用线连接。

PyCairo 中的基本绘图 - 图1

图:直线

填充和描边

描边操作绘制形状的轮廓,填充操作填充形状的内部。

fillstroke.py

  1. #!/usr/bin/python
  2. '''
  3. ZetCode PyCairo tutorial
  4. This code example draws a circle
  5. using the PyCairo library.
  6. Author: Jan Bodnar
  7. Website: zetcode.com
  8. Last edited: April 2016
  9. '''
  10. from gi.repository import Gtk
  11. import cairo
  12. import math
  13. class Example(Gtk.Window):
  14. def __init__(self):
  15. super(Example, self).__init__()
  16. self.init_ui()
  17. def init_ui(self):
  18. darea = Gtk.DrawingArea()
  19. darea.connect("draw", self.on_draw)
  20. self.add(darea)
  21. self.set_title("Fill & stroke")
  22. self.resize(230, 150)
  23. self.set_position(Gtk.WindowPosition.CENTER)
  24. self.connect("delete-event", Gtk.main_quit)
  25. self.show_all()
  26. def on_draw(self, wid, cr):
  27. cr.set_line_width(9)
  28. cr.set_source_rgb(0.7, 0.2, 0.0)
  29. w, h = self.get_size()
  30. cr.translate(w/2, h/2)
  31. cr.arc(0, 0, 50, 0, 2*math.pi)
  32. cr.stroke_preserve()
  33. cr.set_source_rgb(0.3, 0.4, 0.6)
  34. cr.fill()
  35. def main():
  36. app = Example()
  37. Gtk.main()
  38. if __name__ == "__main__":
  39. main()

在示例中,我们绘制了一个圆圈,并用纯色填充。

  1. import math

用于绘制圆的pi常数需要此模块。

  1. cr.set_line_width(9)
  2. cr.set_source_rgb(0.7, 0.2, 0.0)

我们使用set_line_width()方法设置线宽。 我们使用set_source_rgb()方法将光源设置为深红色。

  1. w, h = self.get_size()

在这里,我们获得了窗口的宽度和高度。 我们需要这些值使圆在窗口上居中。

  1. cr.translate(w/2, h/2)
  2. cr.arc(0, 0, 50, 0, 2*math.pi)
  3. cr.stroke_preserve()

使用translate()方法,我们将图形原点移动到窗口的中心。 我们希望我们的圈子居中。 arc()方法向 Cairo 图形上下文添加了新的圆形路径。 最后,stroke_preserve()方法绘制圆的轮廓。 与stroke()方法不同,它还保留了形状以供以后绘制。

  1. cr.set_source_rgb(0.3, 0.4, 0.6)
  2. cr.fill()

我们使用fill()方法更改绘制颜色,并用新颜色填充圆。

PyCairo 中的基本绘图 - 图2

图:填充和描边

笔划线

每条线可以用不同的笔划线绘制。 笔笔划线定义线条的样式。 笔划线由set_dash()方法指定。 该模式由笔划线列表设置,笔划线列表是浮点值的列表。 他们设置笔划线图案的开和关部分。 stroke()方法使用笔划线创建一条线。 如果笔划线为 0,则禁用笔划线。 如果笔划线的数量为 1,则假定使用对称模式,其中交替的开和关部分由笔划线中的单个值指定。

  1. def on_draw(self, wid, cr):
  2. cr.set_source_rgba(0, 0, 0, 1)
  3. cr.set_line_width(2)
  4. cr.set_dash([4.0, 21.0, 2.0])
  5. cr.move_to(40, 30)
  6. cr.line_to(250, 30)
  7. cr.stroke()
  8. cr.set_dash([14.0, 6.0])
  9. cr.move_to(40, 50)
  10. cr.line_to(250, 50)
  11. cr.stroke()
  12. cr.set_dash([1.0])
  13. cr.move_to(40, 70)
  14. cr.line_to(250, 70)
  15. cr.stroke()

我们用三个不同的笔划线画了三条线。

  1. cr.set_dash([4.0, 21.0, 2.0])

我们有三个数字的模式。 我们绘制了 4 个点,未绘制 21 个,绘制了 2 个点,然后绘制了 4 个点,绘制了 21 个点。 和 2 未绘制。 该模式轮流直到行尾。

  1. cr.set_dash([14.0, 6.0])

在这种模式下,我们总是绘制 14 点,未绘制 6 点。

  1. cr.set_dash([1.0])

在这里,我们创建了一个对称图案的笔划线,该图案交替出现单个接通和断开点。

PyCairo 中的基本绘图 - 图3

图:笔划线

线帽

线帽是线的端点。

  • Cairo.LINE_CAP_BUTT
  • Cairo.LINE_CAP_ROUND
  • Cairo.LINE_CAP_SQUARE

Cairo 有三种不同的线帽样式。

PyCairo 中的基本绘图 - 图4

图:正方形,圆和端帽

带有cairo.LINE_CAP_SQUARE帽的线的大小与带有cairo.LINE_CAP_BUTT帽的线的大小不同。 如果一行的宽度是 x 单位,则带cairo.LINE_CAP_SQUARE上限的行的大小将恰好是 x 单位; 开头x / 2个单位,结尾x / 2个单位。

  1. def on_draw(self, wid, cr):
  2. cr.set_source_rgba(0, 0, 0, 1)
  3. cr.set_line_width(12)
  4. cr.set_line_cap(cairo.LINE_CAP_BUTT)
  5. cr.move_to(30, 50)
  6. cr.line_to(150, 50)
  7. cr.stroke()
  8. cr.set_line_cap(cairo.LINE_CAP_ROUND)
  9. cr.move_to(30, 90)
  10. cr.line_to(150, 90)
  11. cr.stroke()
  12. cr.set_line_cap(cairo.LINE_CAP_SQUARE)
  13. cr.move_to(30, 130)
  14. cr.line_to(150, 130)
  15. cr.stroke()
  16. cr.set_line_width(1.5)
  17. cr.move_to(30, 35)
  18. cr.line_to(30, 145)
  19. cr.stroke()
  20. cr.move_to(150, 35)
  21. cr.line_to(150, 145)
  22. cr.stroke()
  23. cr.move_to(155, 35)
  24. cr.line_to(155, 145)
  25. cr.stroke()

该示例绘制具有三个不同线帽的三条线。 通过绘制三条额外的细垂直线,它还将以图形方式显示线的大小差异。

  1. cr.set_line_width(12)

我们的生产线将是 12 个单位宽。 默认线宽为 2。

  1. cr.set_line_cap(cairo.LINE_CAP_ROUND)
  2. cr.move_to(30, 90)
  3. cr.line_to(150, 90)
  4. cr.stroke()

在这里,我们用cairo.LINE_CAP_ROUND帽画一条水平线。

  1. cr.set_line_width(1.5)
  2. cr.move_to(30, 35)
  3. cr.line_to(30, 145)
  4. cr.stroke()

这是用来说明大小差异的三条垂直线之一。

PyCairo 中的基本绘图 - 图5

图:直线的端帽

线连接

可以使用三种不同的连接样式来连接线。

  • Cairo.LINE_JOIN_MITER
  • Cairo.LINE_JOIN_BEVEL
  • Cairo.LINE_JOIN_ROUND

PyCairo 中的基本绘图 - 图6

图:斜角,圆角,斜接线连接

  1. def on_draw(self, wid, cr):
  2. cr.set_line_width(14)
  3. cr.rectangle(30, 30, 100, 100)
  4. cr.set_line_join(cairo.LINE_JOIN_MITER)
  5. cr.stroke()
  6. cr.rectangle(160, 30, 100, 100)
  7. cr.set_line_join(cairo.LINE_JOIN_BEVEL)
  8. cr.stroke()
  9. cr.rectangle(100, 160, 100, 100)
  10. cr.set_line_join(cairo.LINE_JOIN_ROUND)
  11. cr.stroke()

在此示例中,我们绘制了三个具有各种线连接的粗矩形。

  1. cr.set_line_width(14)

线宽为 14 个单位。

  1. cr.rectangle(30, 30, 100, 100)
  2. cr.set_line_join(cairo.LINE_JOIN_MITER)
  3. cr.stroke()

在这里,我们绘制一个具有cairo.LINE_JOIN_MITER连接样式的矩形。

PyCairo 中的基本绘图 - 图7

图:直线连接

贝塞尔曲线

贝塞尔曲线是由数学公式定义的曲线。 绘制曲线的数学方法由 PierreBézier 在 1960 年代后期创建,用于雷诺的汽车制造。

  1. curve_to(x1, y1, x2, y2, x3, y3)

curve_to()方法将三次贝塞尔曲线样条添加到路径。 参数为第一控制点的 x 和 y 坐标,第二控制点的 x 和 y 坐标以及曲线末端的 x 和 y 坐标。

  1. def on_draw(self, wid, cr):
  2. cr.move_to(20, 40)
  3. cr.curve_to(320, 200, 330, 110, 450, 40)
  4. cr.stroke()

在此示例中,使用curve_to()方法绘制了贝塞尔曲线。

PyCairo 中的基本绘图 - 图8

图:贝塞尔曲线

在 PyCairo 教程的这一章中,我们做了一些基本的绘制。