新規作成  編集  Ruby-GNOME2 Project Website  ページ一覧  検索  更新履歴  編集履歴  RSS  ログイン

ウインドウへの直接描画(2) - Gdk::Drawable

ウインドウへの直接描画 - Gdk::Drawable

Ruby/GTK(2)用です #suzuki@cis.iwate-u.ac.jp が少し書き換えました。

Gdk::Drawableは、Gdk::Pixmap, Gdk::Windowのスーパークラスで、ウィジェット自体に直接描画する場合に使用します。 ここでは、主にGdk::Windowを例に使っていますが、基本的にはGdk::Pixmap, Gdk::Bitmap?でも同様です。 GTK+の各ウィジェットはGdk::Drawableにあるメソッドを使用して描画を行います(実際はC言語で記述されているのですが)。したがって、これらのクラス、メソッドを直接使うというのはあまりないかもしれませんが、これらを駆使すれば自分なりの新しいウィジェットを作ることもできるかもしれません。 それから、通常、Ruby/GTK上でお絵かきをする場合は、Gtk::DrawingAreaとかGtk::Curve, Gtk::Preview?等を使った方が良いかもしれません、ってまだ勉強してないのでそちらの方は知らないんですけど(^^;)。

直線を描画する

ここでは、Gtk::Windowが持つGdk::Window自体に直線を描画してみます。 <IMG SRC="draw_line.jpg" ALT="表示イメージ" ALIGN="RIGHT">

require 'gtk2'

window = Gtk::Window.new
window.set_size_request(100, 100)
window.set_app_paintable(true)           #(1)
window.realize                           #(2)

drawable = window.window                 #(3)

p geometry = drawable.geometry       #(4)
width = geometry[2]
height = geometry[3]

gc = Gdk::GC.new(drawable)               #(5)

green = Gdk::Color.new(0, 65535, 0)      #(6)
colormap = Gdk::Colormap.system          #(7)
colormap.alloc_color(green, false, true) #(8)

window.signal_connect("expose_event") do |win, evt|   #(9)
  p "expose_event"
  gc.set_foreground(green)                    #(10)
  drawable.draw_line(gc, 0, 0, width, height) #(11)
end

window.show_all

Gtk.main



 * (1)でGtk::Widget#set_paintable(paintable)でそのWidget上で描画が可能かどうかを指定します。これがfalseだと描画できません。
 * (2)でwindowを先にrealizeしています。ここでrealizeしておかないと、(3)のdrawableがnilになります。
 * (3)ではGtk::Windowが持つ、Gdk::Window(Gtk,Gdkの違いに注意してください)をdrawableに代入しています。
 * (4)のGdk::Drawable#get_geometryは、そのGdk::Drawableのジオメトリ情報を配列の形で取得できます。配列の先頭から、[x, y, width, height, depth]です。x, yはGdk::Drawableの左上隅のx,y座標、width, height, depthはそれぞれ幅、高さ、色の深さです。ここではそのうちのwidth,heightを使用します。
 * (5)でdrawableのグラフィックコンテキストを取得します。グラフィックコンテキストについては<A HREF="gc.html">Gdk::GC</A>を参照してください。
 * (6),(7),(8)で緑色を生成して、それをカラーマップに登録しています。うーん、やっぱり美しくない....。まぁ、この辺の話は<A HREF="color.html">カラーの扱い</A>も参考にしてやってください。
 * (9)でシグナルGtk::Widget::SIGNAL_EXPOSE_EVENTを補足して、その中で描画処理を行っています。EXPOSE_EVENTというのはウインドウが別のウインドウに隠れている状態から前面に来たとき発生するイベントですので、ここではウインドウが前面に出るたびに再描画をしています(実際に試してみてください、イベントが発生する度に"expose_event"と表示されます)。したがって、ここに重い処理を書く場合は、ちょっと工夫が必要そうです。

そうそう、ここで渡されるwinはwindowと同じものです。

  • (10)で描画色を緑色に設定しています。Gdk::Drawableに描画する場合はその前にGdk::GC#set_foreground(color)でカラーを指定してあげます。ただし、ここで指定するGdk::Colorは必ずカラーマップへアロケートされていなければなりません((6),(7),(8)を行ったもののみ)。
  • (11)で実際に描画します。

Gdk::Drawable#draw_line(gc,x1,y1,x2,y2)

  • gc - グラフィックコンテキスト(Gdk::GC)
  • x1,y1 - 始点のx,y座標
  • x2,y2 - 終点のx,y座標

点・四角・円などを描画する

直線以外にもいろいろと描画するためのメソッドが用意されていますので、それらを使ってみます。 <IMG SRC="draw_others.jpg" ALT="表示イメージ" ALIGN="RIGHT">

require 'gtk2'

window = Gtk::Window.new
window.set_size_request(200,150)
window.set_app_paintable(true)  
window.realize                

drawable = window.window    

geometry = drawable.geometry
width  = geometry[2]
height = geometry[3]

gc = Gdk::GC.new(drawable)

red     = Gdk::Color.new(65535, 0, 0)
green   = Gdk::Color.new(0, 65535, 0)
blue    = Gdk::Color.new(0, 0, 50000)
gray    = Gdk::Color.new(30000, 30000, 30000)
yellow  = Gdk::Color.new(65535, 65535, 0)
orange  = Gdk::Color.new(65535, 50000, 0)
skyblue = Gdk::Color.new(30000, 30000, 65535)

colormap = Gdk::Colormap.system
colormap.alloc_color(red, false, true)
colormap.alloc_color(green, false, true)
colormap.alloc_color(blue, false, true)
colormap.alloc_color(gray, false, true)
colormap.alloc_color(yellow, false, true)
colormap.alloc_color(orange, false, true)
colormap.alloc_color(skyblue, false, true)

window.signal_connect("expose_event") do |win, evt|   
  gc.set_foreground(red)
  drawable.draw_point(gc, 10, 10)
  drawable.draw_point(gc, 10, 12)
  drawable.draw_point(gc, 10, 14)

  gc.set_foreground(blue)
  drawable.draw_points(gc, [[20, 10], [20, 12], [20, 14]])

  gc.set_foreground(green)
  drawable.draw_lines(gc, [[30, 10], [50, 30], [30, 40], [40, 50]])

  gc.set_foreground(gray)
  drawable.draw_segments(gc, [[60, 10, 80, 30], [90, 40, 100, 20]])

  gc.set_foreground(yellow)
  drawable.draw_rectangle(gc, true, 110, 10, 20, 20) 
  drawable.draw_rectangle(gc, false, 150, 10, 30, 20) 

  gc.set_foreground(orange)
  drawable.draw_arc(gc, false, 10, 70, 50, 50, 0, 360 * 64) 
  drawable.draw_arc(gc, false, 70, 70, 50, 50, 360 * 10, 360 * 64 / 4) 
  drawable.draw_arc(gc, true, 70, 90, 50, 50, 0, 360 * 64 / 4) 

  gc.set_foreground(skyblue)
  drawable.draw_polygon(gc, false, [[160, 50], [150, 80], [190, 90]])
  drawable.draw_polygon(gc, true, [[150, 90], [140, 130], [180, 140]])
end

window.show_all
Gtk.main


* Gdk::Drawable#draw_point(gc, x, y)
  (x,y)に点を描画します。
* Gdk::Drawable#draw_points(gc, array)
  array = [[x1, y1], [x2, y2], [x3, y3], .....]という感じで配列を指定すると、それぞれの点をまとめて描画します。
* Gdk::Drawable#draw_lines(gc, array)
  複数の点を指定し、指定された点を順番に結んだ線を描画します。
  こちらも、Gdk::Drawable#draw_points()と同様に、array = [[x1, y1], [x2, y2], [x3, y3], .....]と点の配列を渡します。
* Gdk::Drawable#draw_segments(gc, array)
  こちらも複数の線を描画します。Gdk::Drawable#draw_lines()とは異なり、複数の線を指定し、それぞれの線はそれぞれ独立した線になります。配列は、
  array = [[x11, y11, x12, y12], [x21, y21, x22, y22] ....]
  のように指定します。
* Gdk::Drawable#draw_rectangle(gc, filled, x, y, width, height)
  四角形を描画します。filledにtrueを指定すると、四角形の内側を塗りつぶし、falseを指定すると塗りつぶしません。
* Gdk::Drawable#draw_arc(gc, filled, x, y, width, height, angle1, angle2)
  円を描画します。ちょっと難しいです。
  最初の方の引数は四角形と同じです。widthとheightが同じであれば円になりますし、違くなれば楕円です。angle1は、円の始点の位置を角度で指定します。0が時計の3時に当たる部分を意味します。angle1の単位は1/64度ですので、360 * 64でちょうど一周分です。angle2は終点の位置をangle1からの相対角度で指定します。単位はangle1と同じで、完全な円を描く場合は360 * 64を指定します。
* Gdk::Drawable#draw_polygon(gc, array)
  複数の点を指定し、指定された点を順番に結んでいきます。Gdk::Drawable#draw_lines()に近いのですが、最後の点と最初の点を結んで矩形にするところが異なります。。配列は、
  array = [[x1, y1], [x2, y2], [x3, y3] ....]
  のように指定します。

文字を描画する

直接文字列を表示することもできます。

require 'gtk2'

window = Gtk::Window.new
window.set_size_request(150,100)
window.set_app_paintable(true)
window.realize

drawable = window.window

gc = Gdk::GC.new(drawable)

red  = Gdk::Color.new(65535, 0, 0)
blue = Gdk::Color.new(0, 0, 50000)

colormap = Gdk::Colormap.system
colormap.alloc_color(red, false, true)
colormap.alloc_color(blue, false, true)

fontdesc = Pango::FontDescription.new
fontdesc.set_family("URW Gothic L")
fontdesc.set_style(Pango::STYLE_ITALIC)
fontdesc.set_weight(Pango::WEIGHT_BOLD)
fontdesc.set_size(25*1000)

layout = Pango::Layout.new(window.pango_context)
layout.font_description=fontdesc

window.signal_connect("expose_event") do |win, evt|
  gc.set_foreground(red)
  layout.text="フォントテスト\nfont test"
  drawable.draw_layout(gc, 20, 20, layout)
  gc.set_foreground(blue)
  layout.text="font test"
  drawable.draw_layout(gc, 20, 100, layout)
end

 window.show_all
 Gtk.main

Gdk::Drawable#draw_layout(gc, x, y, layout)

  • gc - グラフィックコンテキスト(Gdk::GC)
  • x, y - 描画を行う左上隅の座標
  • layout - 文字列の他にfontやスタイルを含み、パラグラフを表すPang::Layoutクラスのオブジェクト

XPM画像を描画する

XPM画像を描画してみます。画像は<A HREF="r.xpm">こちら</A>を利用してください。

require 'gtk'

window = Gtk::Window.new
window.set_size_request(170, 170)
window.set_app_paintable(true)
window.realize

drawable = window.window

pix, mask = Gdk::Pixmap.create_from_xpm(drawable, nil, "r.xpm")

gc = Gdk::GC.new(drawable)

window.signal_connect("expose_event") do |win, evt|
  #drawable.draw_pixmap(gc, pix, 0, 0, 30, 30, -1, -1)  #(1)
  drawable.draw_drawable(gc, pix, 30, 30, 60, 60, 40, 40)
end

window.show_all
Gtk.main

Gdk::Drawable#draw_drawable(gc, pixmap, xsrc, ysrc, xdest, ydest, width, height)でPixmapを描画しますが、結構いろいろ指定する必要があります。それぞれの意味については下図を参照してください。 なお、 width, heightにそれぞれ-1を指定すると、その画像自体の大きさが指定されます。コメントしてある(1)の記述方法が一般的だと思います。

<TABLE ALIGN="CENTER" CELLSPACING=0 BORDER=1><TR><TD><IMG SRC="draw_xpm.jpg" ALT="表示イメージ"></TD></TR></TABLE>

XPM画像と透明化

ちょっと本題からズレてしまうのですが、XPM画像を描画し、さらに背景を透明にしてみます。画像は同じく<A HREF="r.xpm">こちら</A>を利用してください。

require 'gtk2'

window = Gtk::Window.new
window.set_size_request(200,200)
window.set_app_paintable(true)
window.realize

drawable = window.window

pix, mask = Gdk::Pixmap.create_from_xpm(drawable, nil, "r.xpm")

gc = Gdk::GC.new(drawable)

window.shape_combine_mask(mask, 30, 30) 

window.signal_connect("expose_event") do |win, evt|
  drawable.draw_pixmap(gc, pix, 0, 0, 30, 30, -1, -1)
end

window.show_all
Gtk.main

Gtk::Window#shape_combine_mask(mask, x, y)の maskにマスク範囲のGdk::Bitmap?を、x, yにマスク位置の左上隅の座標を指定します。

サンプルは「カラーの扱い」→「指定したPixmapをちょっとだけ明るく表示する」(<A HREF="color.html#convert_direct">ここ</A>と<A HREF="color.html#convert_pseudo">ここ</A>)にありますのでそちらを参考にしてください。

更新日時:2009/11/03 16:32:41
キーワード:
参照:[ウインドウへの直接描画(Gdk::Drawable編)]