(2017.11.14 追加記事;
gtk2,gtk3 で図形を描画します。(Gtk::DrawingArea,Cairo::Context,Gdk::Drawable)
図形を描画する方法は主に2つあります。
A.Cairo::Context を使う方法
B.Gdk::Drawable を使う方法(gtk2のみ)
どちらも、最初に Gtk::DrawingArea(描画用ウィジェット)を作成して、そのウィジェット上に図形を描画していきます。
GTK3 は、A. Cairo::Context を使う方法のみになりました。
Use cairo for drawing
In GTK+ 3, the GDK drawing API (...) has been removed. All drawing in GTK+ 3 is done via cairo.The GdkGC and GdkImage objects, as well as all the functions using them, are gone.
参考)
A.
→・(12) Drawing Area And Cairo - Ruby/GTK2 Tutorial - Ruby-GNOME2 Project Website
→・(12.3) Ruby Cairo Tutorial
・(12.3.1) Cairo's Drawing Model
・(12.3.2) Drawing with Cairo
→・Painting with Cairo in Ruby GTK - ZetCode
→・PyCairo tutorial - ZetCode
B.
→・ウインドウへの直接描画(2) - Gdk/Drawable - Ruby-GNOME2 Project Website
→・Drawing Widgets - Ruby/GTK2 Tutorial - Ruby-GNOME2 Project Website
→・gtkmandel.rb - iso.enat.jp さんのブログ
→・[ruby-list/42528] Gdk/GC の foreground - ruby_list
・[ruby-list/42529] Re/ Gdk/GC の foreground - ruby_list
1-2)DrawingArea の設定
○DrawingArea のサイズを設定する
○DrawingArea のサイズを設定する
幅(width)、高さ(height)をピクセル単位で設定します
-1;サイズ指定なし
○背景の色を設定する
・gtk2;
・gtk2;
state(状態);Gtk::STATE_NORMAL(または :normal);通常状態(これ以外は無効?)
color(色) ;・Gdk::Color.new(red, green, blue)
red, green, blue はそれぞれ 0 - 65535 の値
spec は'green'など代表的色名、
または '#FF0000' のようにRGBそれぞれ 00 - FF の値
・gtk3;
設定方法が変わりました
→ 2-A-2) を参照
設定方法が変わりました
→ 2-A-2) を参照
1-3)描画の設定
・detailed_signal:"expose_event";gtk2
"draw" ;gtk3
・{ |widget, *args| 処理 }
widget;シグナルを発行したウィジット(ここでは DrawingArea)
*args;gtk3では、Cairo::Contextが入ります
(Gtk::DrawingArea.window.create_cairo_context と同じことになります)
gtk2では、Gdk::EventExpose が入ります(使い道がない?)
*args;gtk3では、Cairo::Contextが入ります
(Gtk::DrawingArea.window.create_cairo_context と同じことになります)
gtk2では、Gdk::EventExpose が入ります(使い道がない?)
処理;描画する処理を書きます
※描画するには、
※描画するには、
Gtk::DrawingArea.signal_connect("draw") do |widget, context|
(描画処理)
end
のブロック内に描画処理を記述します1-4)Gdk::Drawable を作る
実際に描画する準備として Drawableクラスが必要なので、DrawingArea から作成します
※gtk3 では、signal_connect("draw") { |widget, context| ... } のブロック変数 context に Cairo::Context が代入されるので作らなくてもよい場合もあります
○Gtk::DrawingArea#window
DrawingArea が持つ Gdk::Window(Gtkではなく、Gdk)を呼び出します
Gdk::Window は Gdk::Drawableクラスを継承しているので、Drawableの持つ描画メソッドが使えます
※ただし、signal_connect のブロック内でないと作れないようです
2.描画する
2-A.Cairo::Context を使う方法
画像描画ライブラリcairo を使って図形を描画する方法です
2-A-1)Cairo::Context を作る
○Gdk::Drawable#create_cairo_context
Gtk::DrawingArea#window で Gdk::Drawableが作れるので(ただし、signal_connect のブロック内)、
Gtk::DrawingArea.window.create_cairo_context で Cairo::Context が作れます
※ もしくは、gtk3では
Gtk::DrawingArea#signal_connect("draw") { |widget, context| ... }
の contex に Cairo::Context が入ります
2-A-1)Cairo::Context を作る
○Gdk::Drawable#create_cairo_context
Gtk::DrawingArea#window で Gdk::Drawableが作れるので(ただし、signal_connect のブロック内)、
Gtk::DrawingArea.window.create_cairo_context で Cairo::Context が作れます
※ もしくは、gtk3では
Gtk::DrawingArea#signal_connect("draw") { |widget, context| ... }
の contex に Cairo::Context が入ります
2-A-2)図形を描く
上述(1-3))したように
Gtk::DrawingArea#signal_connect のブロック内に記述します
○Cairo::Context#set_source_rgb(r, g, b)
○Cairo::Context#set_source_rgba(r, g, b, a)
色の設定をする
・red, green, blue (, alpha);0-1.0
○Cairo::Context#set_line_width(width)
線の太さを設定する(1.0 が標準)
○Cairo::Context#scale(x_scale, y_scale)
座標の拡大率を設定する(1.0で等倍)
○Cairo::Context#move_to(x, y)
点を打つ座標を指定する
○Cairo::Context#line_to(x, y)
前の座標から(x, y)までの直線を引く(経路を)指定をする
○Cairo::Context#stroke
指定された経路を線で描く
○Cairo::Context#rectangle(x1, y1, x2, y2)
四角を描く
○Cairo::Context#arc(x, y, radius, starting_point, ending_point)
円弧を描く
・中心;x, y
・半径;radius
・描画開始点;starting_point(角度;ラジアン 0 〜 2*Math::PI)
・描画終了点;ending_point
○Cairo::Context#fill
図形内部に色を塗る
○Cairo::Context#paint
Gtk::DrawingArea 全体に色を塗る
※ gtk3では、Gtk::DrawingArea の背景色の設定はこれを使います(→ 前述 1-2) 参照)
○Cairo::Context#destroy
Cairo::Context を廃棄します
※ gtk2では、macOSの場合;
Gtk::DrawingArea.signal_connect("expose_event") do |widget, event|
(描画処理)
end
の描画処理のブロックの最後に Cairo::Context#destroy をしないと、終了時に毎回クラッシュレポートが表示されます
→・[gtk2] "DrawingArea + Cairo" on macOS; crash reports emerge ・ Issue #1081 ・ ruby-gnome2/ruby-gnome2 - GitHub
※ 注意)
・gtk3:mac の Retina Display だと、すべてのウィジェットが2倍に拡大表示されてしまいます
→・[gtk3] Gtk/DrawingArea shows the 2 * scaling on Mac Retina display ・ Issue #1079 ・ ruby-gnome2/ruby - GitHub
→・HiDPI/Retina display support and gtk3-port branch? (2014) — GIMP Development — gimpusers.com→・[gtk3] Gtk/DrawingArea shows the 2 * scaling on Mac Retina display ・ Issue #1079 ・ ruby-gnome2/ruby - GitHub
(license; public domain)
・gtk_drawing_1_gtk2.rb
require 'gtk2'window = Gtk::Window.newwindow.set_size_request(400, 300)cyan = Gdk::Color.new(0, 65535, 65535) # RGB; 0-65535yellow = Gdk::Color.parse('#FFFF00') # RGB; 00-FF (parseを使った作り方)drawing_area = Gtk::DrawingArea.newdrawing_area.set_size_request(290,160)drawing_area.modify_bg(:normal, cyan)drawing_area.signal_connect("expose_event") do |widget, event|context = widget.window.create_cairo_contextcontext.set_source_rgb(1.0, 0, 0) # RGB; 0-1.0context.set_line_width(1)context.move_to( 0, 10)context.line_to( 25, 10)context.line_to( 37, 0)context.line_to( 49, 10)context.line_to(289, 10)context.line_to(289, 159)context.line_to( 0, 159)context.line_to( 0, 10)context.strokecontext.set_source_rgb(1.0, 0, 1.0)context.arc(20, 40, 10, 0, 2 * Math::PI)context.fill
context.destroy # macOSの場合、終了時にクラッシュレポートが出るので必要endtext_area = Gtk::TextView.newtext_area.set_size_request(150, 50)text_area.buffer.text = 'Hello World!'text_area.modify_base(:normal, yellow)fixed = Gtk::Fixed.newfixed.put(drawing_area, 20, 20)fixed.put(text_area, 80, 80)window.add(fixed)window.show_allwindow.signal_connect("destroy") { Gtk.main_quit }Gtk.main
# macOS Retina Display だと拡大表示されるrequire 'gtk3'window = Gtk::Window.newwindow.set_size_request(400, 300)yellow = Gdk::RGBA::new(1.0, 1.0, 0, 1.0) # RGBA; 0-1.0drawing_area = Gtk::DrawingArea.newdrawing_area.set_size_request(290,160)drawing_area.signal_connect("draw") do |widget, context|context.set_source_rgb(0, 1.0, 1.0) # RGB; 0-1.0context.paint # 背景色を塗るcontext.set_source_rgb(1.0, 0, 0)context.set_line_width(1)context.move_to( 0, 10)context.line_to( 25, 10)context.line_to( 37, 0)context.line_to( 49, 10)context.line_to(289, 10)context.line_to(289, 159)context.line_to( 0, 159)context.line_to( 0, 10)context.strokecontext.set_source_rgb(1.0, 0, 1.0)context.arc(20, 40, 10, 0, 2 * Math::PI)context.fillendtext_area = Gtk::TextView.newtext_area.set_size_request(150, 50)text_area.buffer.text = 'Hello World!'text_area.override_background_color(:normal, yellow)fixed = Gtk::Fixed.newfixed.put(drawing_area, 20, 20)fixed.put(text_area, 80, 80)window.add(fixed)window.show_allwindow.signal_connect("destroy") { Gtk.main_quit }Gtk.main
※ macOS で Retina Display だと、2倍に拡大表示されてしまう

(MacBook Pro 2016; Retina Display)

(MacBook Air 2016; non Retina Display)
2-B.Gdk::Drawable を使う方法(gtk2のみ)
2-B-1)Gdk::GC(graphics context)を作る
まとめると、signal_connect のブロック内で
Gdk::GC.new(Gtk::DrawingArea.window) または、
2-B-2)Gdk::GC(graphics context)の設定をする
○Gdk::GC#set_rgb_fg_color(color)
色の設定をする
・color;・Gdk::Color.new(red, green, blue)
○Gdk::GC#set_line_attributes(line_width, line_style, cap_style, join_style)
2-B-3)図形を描く
・gc;Gdk::GC (graphics context)
・gtk_drawing_2.rb

(MacBook Pro 2016; Retina Display)

(MacBook Air 2016; non Retina Display)
2-B.Gdk::Drawable を使う方法(gtk2のみ)
2-B-1)Gdk::GC(graphics context)を作る
Gdk::Drawable の描画メソッドを使うには Gdk::GCが必要になります
○Gdk::GC.new(drawable)
○Gdk::GC.new(drawable)
・drawable; Gdk::Drawable
Gdk::Drawable を作るには、Gtk::DrawingArea.window(上述 A.B.4)または、
まとめると、signal_connect のブロック内で
Gdk::GC.new(Gtk::DrawingArea.window) または、
Gtk::DrawingArea.style.fg_gc(Gtk::DrawingArea.state)
で作ります2-B-2)Gdk::GC(graphics context)の設定をする
○Gdk::GC#set_rgb_fg_color(color)
色の設定をする
・color;・Gdk::Color.new(red, green, blue)
red, green, blue はそれぞれ 0 - 65535 の値
spec は'green'など代表的色名、
または '#FF0000' のようにRGBそれぞれ 00 - FF の値
○Gdk::GC#set_line_attributes(line_width, line_style, cap_style, join_style)
・line_width;線の太さ(整数)
・line_style;実線か点線か;GdkLineStyle
(LINE_SOLID,LINE_ON_OFF_DASH,LINE_DOUBLE_DASH)
・cap_style;線の端の設定;GdkCapStyle
・cap_style;線の端の設定;GdkCapStyle
(CAP_NOT_LAST,CAP_BUTT,CAP_ROUND,CAP_PROJECTING)
・join_style: 複数の線の設定;GdkJoinStyle
(JOIN_MITER,JOIN_ROUND,JOIN_BEVEL)
描画処理メソッドは、Gdk::Drawableのものなので、
Gtk::DrawingArea.window
で Gdk::Drawableを作って(上述 1-4))から使います
さらに、上述(1-3))の通り
→・Drawing Widgets - Ruby/GTK2 Tutorial - Ruby-GNOME2 Project WebsiteGtk::DrawingArea.window
で Gdk::Drawableを作って(上述 1-4))から使います
さらに、上述(1-3))の通り
Gtk::DrawingArea.signal_connect("expose_event") do |widget, event|
(描画処理)
end
のブロック内に描画処理を記述します
・gc;Gdk::GC (graphics context)
・gtk_drawing_2.rb
require 'gtk2'window = Gtk::Window.newwindow.set_size_request(400, 300)cyan = Gdk::Color.new( 0, 65535, 65535) # RGB; 0-65535red = Gdk::Color.new(65535, 0, 0)magenta = Gdk::Color.new(65535, 0, 65535)yellow = Gdk::Color.parse('#FFFF00') # RGB; 00-FF (parseを使った作り方)drawing_area = Gtk::DrawingArea.newdrawing_area.set_size_request(290,160)drawing_area.modify_bg(:normal, cyan)drawing_area.signal_connect("expose_event") do |widget, event|gc = Gdk::GC.new(widget.window) # signal_connectのループ内でないとnilになる#gc = widget.style.fg_gc(widget.state) # これでも可gc.set_rgb_fg_color(red)widget.window.draw_lines(gc,[[ 0, 10],[ 25, 10],[ 37, 0],[ 49, 10],[289, 10],[289, 159],[ 0, 159],[ 0, 10]])gc.rgb_fg_color = magentawidget.window.draw_arc(gc, true, 10, 30, 20, 20, 0, 64 * 360)endtext_area = Gtk::TextView.newtext_area.set_size_request(150, 50)text_area.buffer.text = 'Hello World!'text_area.modify_base(:normal, yellow)fixed = Gtk::Fixed.newfixed.put(drawing_area, 20, 20)fixed.put(text_area, 80, 80)window.add(fixed)window.show_allwindow.signal_connect("destroy") { Gtk.main_quit }Gtk.main