https://ujk-ujk.blogspot.com/2025/03/wxruby3-ile-masaustu-uygulama_22.html
Selam WxRuby ile masa üstü uygulamalara gelişmiş widget'larla devam ediyoruz.
Bu bölümde Wx::ListBox, Wx::HTML::HtmlWindow ve Wx::ListCtrl widget'larını göreceğiz.
Wx kütüphanesinde gelişmiş elemanlar var, tree widget, bir HTML window, bir grid widget, bir listbox widget, bir list widget, veya gelişmiş stillendirme özelliklerine sahip editor widget gibi.
Wx::ListBox
ListBox nesnesi bir liste olarak verilen değerleri göstermek için kullanılır. ListBox nesnesi iki farklı şekilde üretilebilir, tek seçimli ya da çoklu seçimli olarak. Default olan tek seçimli olandır.
ListBox nesnesinin iki önemli olayı vardır. evt_listbox olayı listeden bir eleman seçince veya seçim değiştirilince tetiklenir. evt_listbox_dclick olayı ise listbox'a çift tıklanınca oluşur. Elemanların (seçeneklerin) index numarası sıfırdan başlar. Kaydırma çubukları eğer gerekirse otomatik gösterilir.
listbox.rb
require "wx"
class Örnek < Wx::Frame
def initialize(*args)
super(*args)
init_UI
end
def init_UI
set_size [350, 300]
set_title "Wx::ListBox"
centre
panel = Wx::Panel.new self
hbox = Wx::BoxSizer.new Wx::HORIZONTAL
@listbox = Wx::ListBox.new panel
hbox.add @listbox, 1, Wx::EXPAND | Wx::ALL, 20
btn_panel = Wx::Panel.new panel
vbox = Wx::BoxSizer.new Wx::VERTICAL
new_btn = Wx::Button.new btn_panel, Wx::ID_ANY, 'Yeni', size:[90, 30]
ren_btn = Wx::Button.new btn_panel, Wx::ID_ANY, 'Değiştir', size:[90, 30]
del_btn = Wx::Button.new btn_panel, Wx::ID_ANY, 'Sil', size:[90, 30]
clr_btn = Wx::Button.new btn_panel, Wx::ID_ANY, 'Temizle', size:[90, 30]
evt_button new_btn, :new_item
evt_button ren_btn, :on_rename
evt_button del_btn, :on_delete
evt_button clr_btn, :on_clear
evt_listbox_dclick @listbox, :on_rename
vbox.add 0, 20
vbox.add new_btn
vbox.add ren_btn, 0, Wx::TOP, 5
vbox.add del_btn, 0, Wx::TOP, 5
vbox.add clr_btn, 0, Wx::TOP, 5
btn_panel.sizer = vbox
hbox.add btn_panel, 1, Wx::EXPAND | Wx::RIGHT, 20
panel.sizer = hbox
end
def new_item(e)
text = Wx.get_text_from_user 'Yeni eleman değeri giriniz',
'Yeni Eleman Diyaloğu'
unless text == ""
@listbox.append text
end
end
def on_rename(e)
sel = @listbox.selection
text = @listbox.string sel
renamed = Wx.get_text_from_user 'Eleman yeni değeri giriniz',
'Değiştirme Diyaloğu', text
if renamed != ''
@listbox.delete sel
item_id = @listbox.insert renamed, sel
@listbox.selection = item_id
end
end
def on_delete(e)
sel = @listbox.selection
if sel != -1
@listbox.delete sel
end
end
def on_clear(e)
@listbox.clear
end
end
Wx::App.run {
Örnek.new(nil).show
}
Örnekte bir ListBox nesnesine yeni eleman eklenmesi, değiştirilmesi, silinmesi gösteriliyor.
@listbox = Wx::ListBox.new panel
hbox.add @listbox, 1, Wx::EXPAND | Wx::ALL, 20
ListBox nesnesi yatay boyutlandırıcıda dikey olarak yayılmış, her tarafında 20 piksel boşluk olarak yerleştiriliyor.
evt_listbox_dclick @listbox, :on_rename
LisBox elemanına çift tıklanınca da "Değiştir" butonu ile aynı metod çağrılıp değer değiştirme diyaloğu açılıyor.
def new_item(e)
text = Wx.get_text_from_user 'Yeni eleman değeri giriniz',
'Yeni Eleman Diyaloğu'
unless text == ""
@listbox.append text
end
end
@listbox.append text ile listeye yeni satır ekleniyor. Wx.get_text_from_user sınıf metodu birçok hazır Wx diyaloğundan biri.
def on_rename(e)
sel = @listbox.selection
text = @listbox.string sel
renamed = Wx.get_text_from_user 'Eleman yeni değeri giriniz',
'Değiştirme Diyaloğu', text
if renamed != ''
@listbox.delete sel
item_id = @listbox.insert renamed, sel
@listbox.selection = item_id
end
end
En karmaşık olan metod on_rename metodu. Önce @listbox.selection ile listeden seçili değerin index değerini alıyoruz. Eğer açılan diyalogdan bir değer girilirse önce eskisi silinip , sonra yeni değer @listbox.insert metodu ile aynı noktaya enjekte ediliyor.
def on_delete(e)
sel = @listbox.selection
if sel != -1
@listbox.delete sel
end
end
Kod gösteriyor ki değer seçilmemişse selection değeri -1 geliyor ve delete metodu verilen index'teki değeri siliyor.

Wx::HTML::HtmlWindow
Bu widget HTML sayfaları gösterir. Tam teşekküllü bir tarayıcı değildir.
Örneğin aşağıdaki program bazı temel istatistikleri verir.
page.html
<!DOCTYPE html>
<html>
<body bgcolor="#8e8e95">
<table cellspacing="5" border="0" width="250">
<tr width="200" align="left">
<td bgcolor="#e7e7e7"> En büyük</td>
<td bgcolor="#aaaaaa"> <b>9000</b></td>
</tr>
<tr align="left">
<td bgcolor="#e7e7e7"> Ortalama</td>
<td bgcolor="#aaaaaa"> <b>6076</b></td>
</tr>
<tr align="left">
<td bgcolor="#e7e7e7"> En küçük</td>
<td bgcolor="#aaaaaa"> <b>3800</b></td>
</tr>
<tr align="left">
<td bgcolor="#e7e7e7"> Ortanca</td>
<td bgcolor="#aaaaaa"> <b>6000</b></td>
</tr>
<tr align="left">
<td bgcolor="#e7e7e7"> Standart Sapma</td>
<td bgcolor="#aaaaaa"> <b>6076</b></td>
</tr>
</table>
</body>
</html>

Bu gösterilecek olan HTML sayfa ve kodu.
htmlwin.rb
require "wx"
class Örnek < Wx::Frame
def initialize(*args)
super(*args)
init_UI
end
def init_UI
set_size [350, 300]
set_title "Temel İstatistikler"
centre
panel = Wx::Panel.new self
hbox = Wx::BoxSizer.new Wx::HORIZONTAL
vbox = Wx::BoxSizer.new Wx::VERTICAL
htmlwin = Wx::HTML::HtmlWindow.new panel, Wx::ID_ANY, style: Wx::NO_BORDER
htmlwin.set_standard_fonts
htmlwin.load_file "page.html"
vbox.add -1, 10, 0
vbox.add htmlwin, 1, Wx::EXPAND | Wx::ALL, 9
btn_ok = Wx::Button.new panel, Wx::ID_ANY, 'Ok'
evt_button(btn_ok) { close }
hbox.add 100, -1, 1, Wx::EXPAND
hbox.add btn_ok, 0, Wx::TOP | Wx::BOTTOM | Wx::RIGHT, 10
vbox.add hbox, 0, Wx::EXPAND
panel.sizer = vbox
end
end
Wx::App.run {
Örnek.new(nil).show
}
Programı çalıştırınca Türkçe karakterlerin çıkmadığını gördüm. Sadece page.html dosyası kodlamasını notepad++ kullanarak ANSI'ye çevirince düzgün göründü.

Fakat ben ANSI'ye çevirmeden Türkçe karakterleri görmek istiyorum. Bu yüzden işi Ruby'ye bıraktım, dosya okumasını o yapsın.
#htmlwin.load_file "page.html"
htmlwin.set_page(File.read("page.html"))
Bu şekilde set_page metoduna içeriği string olarak verebiliyoruz, dosyayı okumayı Wx kütüphanesine değil Ruby'ye yaptırıyoruz.
Help penceresi
Wx::HTML::HtmlWindow nesnesini uygulamamızda yardım penceresi gösterirken de kullanabiliriz. Bağımsız bir pencere kullanabileceğimiz gibi uygulamanın bir parçası olan bir pencere de kullanabiliriz. Aşağıdaki örnek betik ikinci tekniği gösteriyor.
helpwindow.rb
require "wx"
class Örnek < Wx::Frame
def initialize(*args)
super(*args)
init_UI
end
def init_UI
set_size [450, 350]
set_title "Yardım Penceresi"
centre
toolbar = create_tool_bar
toolbar.add_tool 1, 'Çıkış', Wx::ArtProvider.get_bitmap(Wx::ART_QUIT)
toolbar.add_tool 2, 'Yardım',Wx::ArtProvider.get_bitmap(Wx::ART_HELP)
toolbar.realize
@splitter = Wx::SplitterWindow.new self
@panel_left = Wx::Panel.new @splitter, Wx::ID_ANY, style: Wx::BORDER_SUNKEN
@panel_right = Wx::Panel.new @splitter
vbox2 = Wx::BoxSizer.new Wx::VERTICAL
header = Wx::Panel.new @panel_right, Wx::ID_ANY
header.background_colour = '#6f6a59'
header.foreground_colour = 'white'
hbox = Wx::BoxSizer.new Wx::HORIZONTAL
st = Wx::StaticText.new header, Wx::ID_ANY, 'Yardım'
font = st.font
font.family = Wx::FONTFAMILY_ROMAN
font.point_size = 11
st.font = font
hbox.add st, 1, Wx::TOP | Wx::BOTTOM | Wx::LEFT, 8
close_btn = Wx::BitmapButton.new header, Wx::ID_ANY,
Wx::ArtProvider.get_bitmap(Wx::ART_CLOSE), style: Wx::NO_BORDER
close_btn.background_colour = '#6f6a59'
hbox.add close_btn, 0, Wx::TOP | Wx::BOTTOM, 8
header.sizer = hbox
vbox2.add header, 0, Wx::EXPAND
@help_win = Wx::HTML::HtmlWindow.new @panel_right, style:Wx::NO_BORDER
@help_win.set_page(File.read("help.html"))
vbox2.add @help_win, 1, Wx::EXPAND
@panel_right.sizer = vbox2
@panel_left.set_focus
@splitter.split_vertically @panel_left, @panel_right
@splitter.unsplit
evt_button close_btn, :close_help
evt_tool(1) { close }
evt_tool 2, :on_help
@panel_left.evt_key_down { |e| on_key_pressed e }
evt_html_link_clicked @help_win, :link_clicked
create_status_bar
end
def close_help(e)
@splitter.unsplit
@panel_left.set_focus
end
def on_help(e)
@splitter.split_vertically @panel_left, @panel_right
@panel_left.set_focus
end
def on_key_pressed(e)
keycode = e.key_code
#p keycode
if keycode == Wx::KeyCode::K_F1
@splitter.split_vertically @panel_left, @panel_right
@panel_left.set_focus
end
end
def link_clicked(e)
link = e.link_info.href
if link.start_with? "http"
p "dış link"
system "start #{link}"
else
@help_win.load_page link
end
end
end
Wx::App.run {
Örnek.new(nil).show
}
ve help.html
<!DOCTYPE html>
<html>
<body bgcolor="#ababab">
<h4>İçindekiler</h4>
<ul>
<li><a href="#temel">Uygulama Temelleri</a></li>
<li><a href="#gelişmiş">Gelişmiş Özellikler</a></li>
<li><a href="#sabitler">Kullanılan sabitler</a></li>
<li><a href="#info">Nasıl Yardım Alınır</a></li>
</ul>
<p>
<a name="temel">
<h6>Uygulama Temelleri</h6>
Uygulamamız güzel bir yugulamadır. Her işe yarar.
Birçok özelliği vardır.
</a>
</p>
<p>
<a name="gelişmiş">
<h6>Gelişmiş Özellikler</h6>
Birçok gelişmiş özelliklerden en önemlileri şunlardır:
<ul>
<li>Veri tabanı</li>
<li>PNG export</li>
<li>xml import</li>
</ul>
</a>
</p>
<p>
<a name="sabitler">
<h6>Kullanılan sabitler</h6>
Wx::ART_QUIT , Wx::ART_HELP , Wx::ART_CLOSE
</a>
</p>
<p>
<a name="info">
<h6>Nasıl Yardım Alınır</h6>
Blog <a href="https://ujk-ujk.blogspot.com/2025/03/wxruby3-ile-masaustu-
uygulama_22.html" target="_blank">
sayfasında</a> yorum yaparak yardım alabilirsiniz.
</a>
</p>
</body>
</html>
Yardım penceresi başlangıçta gizli. Pencereyi araç kutusunda butona tıklayarak ya da F1 tuşuna basarak açabiliriz. Yardım penceresini kapatmak için sağ üstteki kapatma düğmesine tıklayabiliriz.
@splitter.split_vertically @panel_left, @panel_right
@splitter.unsplit
Bir Splitter nesnesi içeriğinde solda ve sağda olmak üzere 2 panel yerleştiriyoruz. Sağdaki panelde yardım penceresi içeriğimiz var. unsplit metodu ile sadece soldaki panel kalıyor.
close_btn = Wx::BitmapButton.new header, Wx::ID_ANY,
Wx::ArtProvider.get_bitmap(Wx::ART_CLOSE), style: Wx::NO_BORDER
close_btn.background_colour = '#6f6a59'
Yardım penceresi bir HtmlWindow nesnesi ve üst köşesinde bir kapatma butonu var , görselini Wx standart görsellerinden seçtik.
@help_win = Wx::HTML::HtmlWindow.new @panel_right, style:Wx::NO_BORDER
@help_win.set_page(File.read("help.html"))
Yardım penceresi içeriğini help.html dosyasından okuyoruz. Önceki örnekte de gördüğümüz gibi , Türkçe karakter sorunu yaşamamak için dosyayı Ruby File.read metoduna okutup set_page metodu ile HtmlWindow nesnesine koyuyoruz.
@panel_left.evt_key_down { |e| on_key_pressed e }
Fokus sol paneldeyken klavyeden tuş basılırsa on_key_pressed olay metoduna gidiyoruz, orada da F1 tuşuna basılmışsa yardım penceresinin görünmesini sağlıyoruz. evt_key_down olay metodu bir widget nesnesine bağlı çalıştığı için olay metodu yönlendirmesi blok içinde bu gösterildiği şekilde yapılabiliyor.
evt_html_link_clicked @help_win, :link_clicked
.....
def link_clicked(e)
link = e.link_info.href
if link.start_with? "http"
p "dış link"
system "start #{link}"
else
@help_win.load_page link
end
end
Eğer yardım penceresinde bir link tıklandıysa ve harici bir adrese link ise system "start #{link}" satırı ile bağlantıyı sistemin default tarayıcısında açtırıyoruz. Aslında kullanılan sisteme göre bu satır değişik oluyor. Bu örnek Windows sistemine göre yazılmış.
if RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/
system "start #{link}"
elsif RbConfig::CONFIG['host_os'] =~ /darwin/
system "open #{link}"
elsif RbConfig::CONFIG['host_os'] =~ /linux|bsd/
system "xdg-open #{link}"
end
Şeklinde yazılması daha doğruymuş.

Wx::ListCtrl
ListCtrl elemanlar listesinin grafiksel gösterimi için kullanılır. ListBox sadece bir sütun halinde elemanları gösterirken ListCtrl bir'den fazla sütun gösterebilir. Örneğin dosya yöneticisi dizinler ve içlerindeki dosyaları ListCtrl kullanarak gösterebilir.
Bir ListCtrl 3 değişik formatta kullanılabilir. Liste görünümü, rapor görünümü ve ikon görünümü. Bu formatları belirlemek için Wx::LC_REPORT, Wx::LC_LIST ve Wx::LC_ICON stilleri kullanılır.
Wx::ListCtrl stilleri
- Wx::LC_LIST
- Wx::LC_REPORT
- Wx::LC_VIRTUAL
- Wx::LC_ICON
- Wx::LC_SMALL_ICON
- Wx::LC_ALIGN_LEFT
- Wx::LC_EDIT_LABELS
- Wx::LC_NO_HEADER
- Wx::LC_SORT_ASCENDING
- Wx::LC_SORT_DESCENDING
- Wx::LC_HRULES
- Wx::LC_VRULES
Örneğimizde ListCtrl nesnesinin temel özelliklerini kullanıyoruz.
actresses.rb
require "wx"
$data = [['Jessica Alba', 'Pomona', '1981'],
['Sigourney Weaver', 'New York', '1949'],
['Angelina Jolie', 'los angeles', '1975'],
['Natalie Portman', 'Jerusalem', '1981'],
['Rachel Weiss', 'London', '1971'],
['Scarlett Johansson', 'New York', '1984']]
class Örnek < Wx::Frame
def initialize(*args)
super(*args)
init_UI
end
def init_UI
set_size [350, 200]
set_title "Aktristler"
centre
hbox = Wx::BoxSizer.new Wx::HORIZONTAL
panel = Wx::Panel.new self
list = Wx::ListCtrl.new panel, Wx::ID_ANY, style:Wx::LC_REPORT
list.insert_column 0, 'isim', Wx::LIST_FORMAT_LEFT, 130
list.insert_column 1, 'yer', Wx::LIST_FORMAT_LEFT, 90
list.insert_column 2, 'yıl', Wx::LIST_FORMAT_RIGHT, 90
idx = 0
$data.each do |i|
list.insert_item idx, i[0]
list.set_item idx, 1, i[1]
list.set_item idx, 2, i[2]
idx += 1
end
hbox.add list, 1, Wx::EXPAND
panel.sizer = hbox
end
end
Wx::App.run {
Örnek.new(nil).show
}
Kodumuz aktristlerin bir listesini ListCtrl içinde gösteriyor.
list = Wx::ListCtrl.new panel, Wx::ID_ANY, style:Wx::LC_REPORT
ListCtrl nesnemizi rapor formatında üretiyoruz.
list.insert_column 0, 'isim', Wx::LIST_FORMAT_LEFT, 130
list.insert_column 1, 'yer', Wx::LIST_FORMAT_LEFT, 90
list.insert_column 2, 'yıl', Wx::LIST_FORMAT_RIGHT, 90
3 sütunumuzun başlıkları, stilleri ve genişlikleri.
idx = 0
$data.each do |i|
list.insert_item idx, i[0]
list.set_item idx, 1, i[1]
list.set_item idx, 2, i[2]
idx += 1
end
ListCtrl listesine değerleri iki metodla giriyoruz. Her satırın başında insert_item ile ilk hücre içeriğini yerleştiriyoruz. Daha sonra set_item ile diğer sütunlardaki hücre değerlerini giriyoruz.

Drag - Drop
Masaüstü uygulamalarda drag-and-drop bir nesneyi mouse ile tutup çekerek başka bir konuma bırakmayı ifade ediyor. Bu sürükle-bırak eylemleri karmaşık işleri görsel olarak yapabilme imkanı sunar.
Sürükle-bırak eyleminde bir veriyi bir kaynak verisinden çekip bir hedef veri içine bırakıyoruz. O zaman ihtiyacımız olan şeyler.
- Bir veri
- Bir veri kaynağı
- Bir veri hedefi
Wx kütüphanesinde tanımlı iki veri hedefi var: Wx::TextDropTarget ve Wx::FileDropTarget.
Wx::TextDropTarget
TextDropTarget nesnesi ön tanımlı bir text verisi bırakma hedefi.
dragdrop_text.rb
require "wx"
class MyTextDropTarget < Wx::TextDropTarget
def initialize(object)
super() # parantezler mecbur
@object = object
end
def on_drop_text(x, y, data)
@object.insert_item 0, data
return true
end
end
class Örnek < Wx::Frame
def initialize(*args)
super(*args)
init_UI
end
def init_UI
set_size [400, 400]
set_title "Text sürükle-bırak"
centre
splitter1 = Wx::SplitterWindow.new self, style: Wx::SP_3D
splitter2 = Wx::SplitterWindow.new splitter1, style: Wx::SP_3D
home_dir = Dir.home
@dir_wid = Wx::GenericDirCtrl.new splitter1, dir: home_dir,
style: Wx::DIRCTRL_DIR_ONLY
@lc1 = Wx::ListCtrl.new splitter2, style: Wx::LC_LIST
@lc2 = Wx::ListCtrl.new splitter2, style: Wx::LC_LIST
dt = MyTextDropTarget.new @lc2
@lc2.drop_target = dt
evt_list_begin_drag @lc1, :on_drag_init
tree = @dir_wid.tree_ctrl
splitter2.split_horizontally @lc1, @lc2, 150
splitter1.split_vertically @dir_wid, splitter2, 200
evt_tree_sel_changed tree, :on_select
on_select 0
end
def on_drag_init(e)
text = @lc1.get_item_text e.index
tdo = Wx::TextDataObject.new text
tds = Wx::DropSource.new @lc1
tds.data = tdo
tds.do_drag_drop
end
def on_select(e)
list = Dir.children(@dir_wid.path)
@lc1.clear_all
@lc2.clear_all
list.each do |item|
unless item.start_with? '.'
@lc1.insert_item 0, item
end
end
end
end
Wx::App.run {
Örnek.new(nil).show
}
Örnekte bir dosya sistemini Wx::GenericDirCtrl nesnesi ile gösteriyoruz. Seçilen dizin içeriği sağ üstteki listede gösterilir. Dosya ve dizin isimleri sürüklenerek sağ alttaki listeye bırakılabilir.
def on_drop_text(x, y, data)
@object.insert_item 0, data
return true
end
Wx::TextDropTarget nesnesine bir şey sürüklenip bırakılınca ne yapılacağını belirtmek için on_drop_text metodu üzerine yazılır. Burada da @object bir ListCtrl nesnesi ve sürüklenip bırakılan text insert_item metodu ile listeye ekleniyor.
dt = MyTextDropTarget.new @lc2
@lc2.drop_target = dt
Bir bırakma hedefi belirleniyor ve bu hedef drop_target= (ya da set_drop_target) metodu ile sağ alt ListCtrl nesnesi yapılıyor.
evt_list_begin_drag @lc1, :on_drag_init
Sürükleme işlemi @lc1 nesnesinde başladığında on_drag_init olay işleme metodu çağrılıyor.
def on_drag_init(e)
text = @lc1.get_item_text e.index
tdo = Wx::TextDataObject.new text
tds = Wx::DropSource.new @lc1
....
Sürükleme başladığında tutulmakta olan yazıyı içeren Wx::TextDataObject nesnesi oluşturuyoruz. Bırakma kaynağı olarak @lc1 listesini belirliyoruz.
tds.data = tdo
tds.do_drag_drop
Bırakma kaynağı data değeri olarak sürüklenmekte olan text'i belirtiyoruz ve do_drag_drop ile sürükle-bırak eylemini başlatıyoruz. Yani verimiz tdo , veri kaynağımız tds, veri hedefimiz dt nesneleri olarak bir sürükle-bırak tasarlıyoruz.

Wx::FileDropTarget
FileDropTarget bir dosya yöneticisinden sürüklenen dosyaları bırakmak için kullanılan bir nesne.
dragdrop_file.rb
require "wx"
class FileDrop < Wx::FileDropTarget
def initialize(window)
super() # parantezler mecbur
@window = window
end
def on_drop_files(x, y, filenames)
for name in filenames
@window.write_text File.read(name)
end
return true
end
end
class Örnek < Wx::Frame
def initialize(*args)
super(*args)
init_UI
end
def init_UI
set_size [400, 400]
set_title "Dosya sürükle-bırak"
centre
text = Wx::TextCtrl.new self, style: Wx::TE_MULTILINE
dt = FileDrop.new text
text.set_drop_target dt
end
end
Wx::App.run {
Örnek.new(nil).show
}
Uygulama penceresine Wiindows gezgininden bir dosyayı sürüklersek dosya içeriğini TextCtrl nesnesi içeriğine ekler.
def on_drop_files(x, y, filenames)
for name in filenames
....
Bir kerede bir'den fazla dosya sürükleyebilirsiniz.
@window.write_text File.read(name)
Text dosyası içeriği okunup uygulamaızın penceresine yazılır.
text = Wx::TextCtrl.new self, style: Wx::TE_MULTILINE
dt = FileDrop.new text
text.set_drop_target dt
TextCtrl nesnemiz sürükle-bırak hedefi.

WxRuby Grafikleri
Eğlenceli bir konuya geldik. Başarılı olursak güzel grafik çizimleri yapacağız. GDI (Graphics Device Interface) grafikler çalışmak için bir arabirim. Monitör, printer veya bir dosya gibi grafik nesneleri ile etkileşimi sağlar. GDI yardımıyla yazılımcı bir monitör ya da printer'da verilerini donanımdan bağımsız gösterebilir. Yazılımcı tarafından bakılırsa GDI grafiklerle çalışabileceği bir kısım sınıftan ibarettir. GDI'da 2D vektör grafikler, image ve font'lar vardır.
Çizim yapabilmek için bir device context (DC) nesnesi üretmemiz gerekir. WxRuby'de bu bir Wx::DC nesnesi. Ancak çizimlerimiz için Wx::DC nesnesi kullanmayız, kullanacağımız çıktı cihazına göre türetilmiş alt sınıflarından birini kullanırız.
- Wx::BufferedDC
- Wx::BufferedPaintDC
- Wx::PostScriptDC
- Wx::MemoryDC
- Wx::PrinterDC
- Wx::ScreenDC
- Wx::ClientDC
- Wx::PaintDC
- Wx::WindowDC
Wx::ScreenDC nesnesi ekranda herhangi bir yere çizim yapabilir. Wx::WindowDC tüm pencere geneline çizim yapar (sadece Windows'ta). Wx::ClientDC pencerenin kullanım alanına çizim yapar (title ve border hariç alan). Wx::PaintDC de kullanım alanına çizer ama PaintDC ile Wx::PaintEvent'den çizim yapılabilir (olay işleyici içinde) ClientDC tam tersi. Wx::MemoryDC ile bitmap olarak çizim yapılır. Wx::PostScriptDC ile PostScript dosyalarına çizim yapılır. Wx::PrinterDC ile printer'a çizim yapılır (sadece Windows'ta).
Basit bir çizgi çizmek
İlk örneğimizde pencere kullanım alanına bir çizgi çizeceğiz. draw_line(x1, y1, x2, y2) metodunu kullanacağız.
draw_line.rb
require "wx"
class Örnek < Wx::Frame
def initialize(*args)
super(*args)
init_UI
end
def init_UI
set_size [300, 200]
set_title "DrawLine"
centre
tmr = Wx::Timer.new self
tmr.start_once(2000)
evt_timer tmr, :draw_line
end
def draw_line(e)
Wx::ClientDC.draw_on self do |dc|
dc.draw_line 50, 60, 190, 60
end
end
end
Wx::App.run {
Örnek.new(nil).show
}
Pencere kullanım alanında program başladıktan 2 saniye sonra yatay bir çizgi çiziliyor.
tmr = Wx::Timer.new self
tmr.start_once(2000)
evt_timer tmr, :draw_line
Bir Wx::Timer nesnesini 2000 milisaniye sonra bir kereliğine tetiklenecek şekilde ayarlıyoruz. Zamanlayıcı dolunca draw_line olay işleme metodumuzu çağırıyoruz. Metod adının çizim yapan DC metoduyla benzerliği sadece tesadüf.
def draw_line(e)
Wx::ClientDC.draw_on self do |dc|
dc.draw_line 50, 60, 190, 60
end
end
Bu yapıyı ClientDC dokümanından öğrendim. ClientDC nesnesinin çizimi yapacağı yer self, yani penceremizin kendisi. Blok içinde dc değişkeninde çizim metodlarını çağırabiliriz. Sol kenardan 50 piksel , yukarı kenardan 60 piksel içerden başlayarak soldan 190, yukarıdan 60 içeriye kadar çizgi çiziliyor, yani yatay bir çizgi.
Şunu belirtelim, pencere boyutlarını çizgiyi örtecek kadar küçültürsek çizgi kaybolur. Pencere boyutu değiştirilince özellikle büyütürken yeni açılan yerler tekrar boyanır. Minimize maksimize edince , üzerine başka pencere gelince vs. Bu yok olma sorununu çözmek için her seferinde çizgiyi yeniden çizmemiz gerekir, bu amaçla Wx::PaintEvent nesnesi kullanılabilir.

draw_line2.rb
require "wx"
class Örnek < Wx::Frame
def initialize(*args)
super(*args)
init_UI
end
def init_UI
set_size [300, 200]
set_title "DrawLine 2"
centre
evt_paint :draw_line
end
def draw_line(e)
self.paint do |dc|
dc.draw_line 50, 60, 190, 60
end
end
end
Wx::App.run {
Örnek.new(nil).show
}
Aynı çizgiyi çiziyoruz ama bu sefer pencere yeniden boyanınca.
evt_paint :draw_line
Pencerenin yeniden boyanması olayını draw_line metodumuza bağlıyoruz.
def draw_line(e)
self.paint do |dc|
dc.draw_line 50, 60, 190, 60
end
end
Bu sefer çizimi yapmak için PaintDC kullanıyoruz.
Bilgisayar grafikleri
İki çeşit grafik çizme tekniği vardır: vektör ve raster grafikler. Raster grafikler resimleri piksellerden oluşturur. Vektör grafikler geometrik grafik nesnelerini kullanırlar, örneğin noktalar, çizgiler, eğriler, çokgenler vs. ile resmi oluştururlar. Bu geometrik temel şekiller matematik hesaplarla çizilir.
Her iki tip bilgisayar grafiğinin de avantaj ve dezavantajları vardır. Vektör grafiğin, rastere göre üstünlükleri:
- Küçük hafıza işgal ederler
- Sınırsız zoom yapılabilir
- Kaydırma , boyut değiştirme, renk değiştirme ve döndürme resim kalitesini değiştirmez
Temel şekiller
Aşağıdakiler temel şekillerden bazıları
- Noktalar
- Çizgiler
- Çoklu çizgiler
- Çokgenler
- Daireler
- Elipsler
- Eğriler
DC öznitelikleri
Device context nesnelerinin bağlı özellikleri var. Örneğin pen ya da font gibi. Wx::Brush alanları renklendirmek için kullanılan bir araç. Şekillerin içlerinin boyamak için kullanılırlar. Bir rengi ve bir stili vardır. Wx::Pen şekillerin kenar çizgilerini belirler. Rengi, genişliği ve stili vardır. Wx::Font yazıların görünüşünü belirler.
Temel elemanlar
Aşağıdaki satırlarda çeşitli nesneleri göreceğiz,
Colour
Colour kırmızı, yeşil, mavi (RGB) renklerin parlaklık değerlerinin birleştirilmesiyle oluşan bir renktir. Geçerli parlaklık değeri 0-255 arasında olur. Renk belirlemenin 4 değişik yolu vardır. Bir Wx::Colour nesnesi oluştururuz ve oluştururken RGB değerini veririz. Bu değeri girmenin 4 yöntemi vardır,
Wx::Colour.new 0, 0, 255
Wx::Colour.new "blue"
Wx::Colour.new "#0000FF"
Wx::Colour.new Wx::BLUE
Hazır tanımlı birçok renk adı var.
AQUAMARINE | BLACK |
BLUE | BLUE VIOLET |
BROWN | CADET BLUE |
CORAL | CORNFLOWER BLUE |
CYAN | DARK GREY |
DARK GREEN | DARK OLIVE GREEN |
DARK ORCHID | DARK SLATE BLUE |
DARK SLATE GREY | DARK TURQUOISE |
DIM GREY | FIREBRICK |
FOREST GREEN | GOLD |
GOLDENROD | GREEN |
GREEN YELLOW | INDIAN RED |
KHAKI | LIGHT BLUE |
LIGHT GREY | LIGHT STEEL BLUE |
LIME GREEN | MAGENTA |
MAROON | MEDIUM AQUAMARINE |
MEDIUM BLUE | MEDIUM ORCHID |
MEDIUM SEA GREEN | MEDIUM SLATE BLUE |
MEDIUM SPRING GREEN | MEDIUM TURQUOISE |
MEDIUM VIOLET RED | MIDNIGHT BLUE |
NAVY | ORANGE |
ORANGE RED | ORCHID |
PALE GREEN | PINK |
PLUM | PURPLE |
RED | SALMON |
SEA GREEN | SIENNA |
SKY BLUE | SLATE BLUE |
SPRING GREEN | STEEL BLUE |
TAN | THISTLE |
TURQUOISE | VIOLET |
WHEAT | WHITE |
YELLOW | YELLOW GREEN |
| |
Aşağıdaki örnek bazı renkleri kullanıyor.
colours.rb
require "wx"
class Örnek < Wx::Frame
def initialize(*args)
super(*args)
init_UI
end
def init_UI
set_size [400, 300]
set_title "DrawLine 2"
centre
evt_paint :on_paint
end
def on_paint(e)
self.paint do |dc|
dc.pen = Wx::Pen.new '#d4d4d4'
dc.brush = Wx::Brush.new '#c56c00'
dc.draw_rectangle 10, 15, 90, 60
dc.brush = Wx::Brush.new '#1ac500'
dc.draw_rectangle 130, 15, 90, 60
dc.brush = Wx::Brush.new '#539e47'
dc.draw_rectangle 250, 15, 90, 60
dc.brush = Wx::Brush.new '#004fc5'
dc.draw_rectangle 10, 105, 90, 60
dc.brush = Wx::Brush.new '#c50024'
dc.draw_rectangle 130, 105, 90, 60
dc.brush = Wx::Brush.new '#9e4757'
dc.draw_rectangle 250, 105, 90, 60
dc.brush = Wx::Brush.new '#5f3b00'
dc.draw_rectangle 10, 195, 90, 60
dc.brush = Wx::Brush.new '#4c4c4c'
dc.draw_rectangle 130, 195, 90, 60
dc.brush = Wx::Brush.new '#785f36'
dc.draw_rectangle 250, 195, 90, 60
end
end
end
Wx::App.run {
Örnek.new(nil).show
}
9 dikdörtgen çiziyoruz hepsi başka renk
dc.brush = Wx::Brush.new '#785f36'
dc.draw_rectangle 250, 195, 90, 60
brush nesnesi rengini hexa desimal formatta veriyoruz. brush değeri şekillerin içinin dolgu rengi. Dikdörtgen çizmek için draw_rectangle metodu kullanılır.

Wx::Pen
Pen nesnesi grafik çiziminin ana elemanlarındandır. Çizgiler , eğriler , dikdörtgenler , elipsler ve dairelerin kenarları onunla çizilir.
Wx::Pen.new colour, width = 1, style = Wx::PenStyle::PENSTYLE_SOLID
Wx::Pen nesnesi üretici metodu 3 parametre değeri alır, renk, genişlik ve stil. Başlıca çizgi stilleri şunlar:
- Wx::PENSTYLE_SOLID
- Wx::PENSTYLE_DOT
- Wx::PENSTYLE_LONG_DASH
- Wx::PENSTYLE_SHORT_DASH
- Wx::PENSTYLE_DOT_DASH
- Wx::PENSTYLE_TRANSPARENT
pens.rb
require "wx"
class Örnek < Wx::Frame
def initialize(*args)
super(*args)
init_UI
end
def init_UI
set_size [400, 300]
set_title "Wx::Pen"
centre
evt_paint :on_paint
end
def on_paint(e)
self.paint do |dc|
dc.pen = Wx::Pen.new '#4c4c4c', 3, Wx::PENSTYLE_SOLID
dc.draw_rectangle 10, 15, 90, 60
dc.pen = Wx::Pen.new '#4c4c4c', 3, Wx::PENSTYLE_DOT
dc.draw_rectangle 130, 15, 90, 60
dc.pen = Wx::Pen.new '#4c4c4c', 3, Wx::PENSTYLE_LONG_DASH
dc.draw_rectangle 250, 15, 90, 60
dc.pen = Wx::Pen.new '#4c4c4c', 3, Wx::PENSTYLE_SHORT_DASH
dc.draw_rectangle 10, 105, 90, 60
dc.pen = Wx::Pen.new '#4c4c4c', 3, Wx::PENSTYLE_DOT_DASH
dc.draw_rectangle 130, 105, 90, 60
dc.pen = Wx::Pen.new '#4c4c4c', 3, Wx::PENSTYLE_TRANSPARENT
dc.draw_rectangle 250, 105, 90, 60
end
end
end
Wx::App.run {
Örnek.new(nil).show
}
Eğer bir brush değeri vermezsek default renkte (beyaz) brush kullanılır. Dikdörtgenlerin kenar çizgileri seçtiğimiz Wx::Pen değeri ile çizilir. Sonuncuda kenar çizgisi yok , çünkü transparent.

Join ve Cap
Bir Pen nesnesinin Join ve Cap adında iki özelliği daha vardır. Join çizgilerin birleştiği yerin şeklini belirler ve set_join (veya join =) metodu ile belirtilir. Değerler şunlar.
- Wx::JOIN_MITER
- Wx::JOIN_BEVEL
- Wx::JOIN_ROUND
JOIN_MITER kullanınca çizgiler tam köşe şeklinde birleşir. JOIN_BEVEL kullanınca köşeye çapraz bir kesik atılır. JOIN_ROUND kullanınca köşeler yuvarlatılmış olur.
Cap çizgi uçlarının nasıl olacağını belirler ve set_cap (veya cap= ) metodu ile ayarlanır . Opsiyonlar
- Wx::CAP_ROUND
- Wx::CAP_PROJECTING
- Wx::CAP_BUTT
CAP_ROUND kullanınca çizgi uçları yuvarlatılmış olur. CAP_PROJECTING ve CAP_BUTT kullanınca çizgi uçları köşeli olur. Aradaki fark, CAP_PROJECTING kullanınca çizgi boyu verilen sınırı çizgi kalınlığının yarısı kadar aşar. CAP_ROUND da kullanınca çizgi boyu aynı şekilde aşma olur.
joins_caps.rb
require "wx"
class Örnek < Wx::Frame
def initialize(*args)
super(*args)
init_UI
end
def init_UI
set_size [400, 300]
set_title "Join ve Cap"
centre
evt_paint :on_paint
end
def on_paint(e)
self.paint do |dc|
pen = Wx::Pen.new '#4c4c4c', 10, Wx::PENSTYLE_SOLID
pen.join = Wx::JOIN_MITER
dc.pen = pen
dc.draw_rectangle 15, 15, 80, 50
pen.join = Wx::JOIN_BEVEL
dc.pen = pen
dc.draw_rectangle 125, 15, 80, 50
pen.join = Wx::JOIN_ROUND
dc.pen = pen
dc.draw_rectangle 235, 15, 80, 50
pen.cap = Wx::CAP_BUTT
dc.pen = pen
dc.draw_line 30, 150, 150, 150
pen.cap = Wx::CAP_PROJECTING
dc.pen = pen
dc.draw_line 30, 190, 150, 190
pen.cap = Wx::CAP_ROUND
dc.pen = pen
dc.draw_line 30, 230, 150, 230
pen2 = Wx::Pen.new '#4c4c4c', 1, Wx::PENSTYLE_SOLID
dc.pen = pen2
dc.draw_line 30, 130, 30, 250
dc.draw_line 150, 130, 150, 250
dc.draw_line 155, 130, 155, 250
end
end
end
Wx::App.run {
Örnek.new(nil).show
}
pen = Wx::Pen.new '#4c4c4c', 10, Wx::PENSTYLE_SOLID
Join ve Cap özellikleri için çizgi kalınlığımız 1 pikselden fazla olmalı.
dc.draw_line 150, 130, 150, 250
dc.draw_line 155, 130, 155, 250
Çizgilerin sonuna denk gelecek aralarına 5 piksel olan iki ince çizgi çiziyoruz ki etkileri görelim.

3. dikdörtgenin köşelerinin yuvarlak olması gerekiyordu, ama olmadı. Sanırım Windows'ta bu işi beceremedi. Ama şöyle yapınca oluyor.
pen1.set_join Wx::JOIN_ROUND
pen1.cap = Wx::CAP_BUTT
dc.pen = pen1
dc.draw_rectangle 235, 15, 80, 50
Gradyenler
Bilgisayar grafiklerinde gradyen karanlıktan parlağa ya da bir renkten diğerine yumuşak geçişi ifade eder. 2 boyutlu çizim programlarında gradyenler 3 boyutluymuş gibi derinlikler verme amacıyla çok kullanılır.
gradient_fill_linear(rect, initialColour, destColour,
nDirection = Wx::Direction::RIGHT)
Bu metod rect ile verilen dikdörtgen alanı boyar. Renk initialColour renginden başlar, destColour renginde biter. Rengin değişim yönü nDirection ile belirtilir, default yönü sağa doğrudur.
gradients.rb
require "wx"
class Örnek < Wx::Frame
def initialize(*args)
super(*args)
init_UI
end
def init_UI
set_size [400, 300]
set_title "Gradients"
centre
evt_paint :on_paint
end
def on_paint(e)
self.paint do |dc|
dc.gradient_fill_linear Wx::Rect.new(20, 20, 180, 40),
'#ffec00', '#000000', Wx::NORTH
dc.gradient_fill_linear Wx::Rect.new(20, 80, 180, 40),
'#ffec00', '#000000', Wx::SOUTH
dc.gradient_fill_linear Wx::Rect.new(20, 140, 180, 40),
'#ffec00', '#000000', Wx::EAST
dc.gradient_fill_linear Wx::Rect.new(20, 200, 180, 40),
'#ffec00', '#000000', Wx::WEST
dc.gradient_fill_linear Wx::Rect.new(220, 20, 50, 120),
'#cccccc', '#222222', Wx::WEST
dc.gradient_fill_linear Wx::Rect.new(270, 20, 50, 120),
'#cccccc', '#222222', Wx::EAST
end
end
end
Wx::App.run {
Örnek.new(nil).show
}
Ben parametrede Wx::Rect.new(20, 20, 180, 40) gibi yeni nesne üretme kodlarını sevmiyorum, sanki C++ kod yazıyormuşum gibi geliyor. Bu amaçla gradient_fill_linear metodu tanımlamasına baktım. Metodun kaynak dosyası yerini view source linkini tıklayıp öğrendim ,
# File 'lib/wx/doc/gen/dc.rb', line 698
Bu dosyayı Ruby kurulumumun WxRuby3 gem klasöründe buldum , benim kurulumumda tam olarak C:\Ruby34-x64\lib\ruby\gems\3.4.0\gems\wxruby3-1.5.1\lib\wx\doc\gen\dc.rb dosyası. İlgili satırları buldum.
# Fill the area specified by rect with a linear gradient, starting
from initialColour and eventually fading to destColour.
#
# The nDirection specifies the direction of the colour change,
default is to use initialColour on the left part of the rectangle and
destColour on the right one.
# @param rect [Wx::Rect]
# @param initialColour [Wx::Colour,String,Symbol]
# @param destColour [Wx::Colour,String,Symbol]
# @param nDirection [Wx::Direction]
# @return [void]
def gradient_fill_linear(rect, initialColour, destColour,
nDirection=Wx::Direction::RIGHT) end
Malesef rect parametresinin sadece Wx::Rect nesnesi aldığını yazıyor. Ama renkler sembol değer alıyormuş, hemen denedim.
dc.gradient_fill_linear Wx::Rect.new(20, 20, 180, 40),
:red, :pink, Wx::NORTH
İnanır mısınız çalışıyor. İsmi verilen renkleri kullanabiliyoruz. Kaynak koduna bakmak öğrenmek için faydalı demek ki. rect parametresine gelince , bu konuda bir yardımcı kod yazmaya karar verdim. Başından beri takip ediyorsanız Wx::GridBagSizer sınıfı koduna pos ve span değerlerini array olarak girmek amacıyla bir yardımcı kod yazdığım my_wx_helper.rb dosyam vardı, ona ilave yapacağım.
class Wx::GridBagSizer
wx_add = instance_method :add
wx_redefine_method :add do |*args|
if args[1].class == Array && args[1].length == 2
args[1] = Wx::GBPosition.new args[1][0], args[1][1]
end
if args[2].class == Array && args[2].length == 2
args[2] = Wx::GBSpan.new args[2][0], args[2][1]
end
wx_add.bind(self).call(*args)
end
end
Benzer bir taklayı Wx::DC sınıfındaki gradient_fill_linear metoduna yapacağım.
my_wx_helper.rb
class Wx::GridBagSizer
wx_add = instance_method :add
wx_redefine_method :add do |*args|
if args[1].class == Array && args[1].length == 2
args[1] = Wx::GBPosition.new args[1][0], args[1][1]
end
if args[2].class == Array && args[2].length == 2
args[2] = Wx::GBSpan.new args[2][0], args[2][1]
end
wx_add.bind(self).call(*args)
end
end
class Wx::DC
wx_gradient_fill_linear = instance_method :gradient_fill_linear
wx_redefine_method :gradient_fill_linear do |*args|
if args[0].class == Array && args[0].length == 4
args[0] = Wx::Rect.new args[0][0], args[0][1], args[0][2], args[0][3]
end
wx_gradient_fill_linear.bind(self).call(*args)
end
end
Artık kodumuz daha kısa olabilir.
require "wx"
require "./my_wx_helper"
.....
def on_paint(e)
self.paint do |dc|
dc.gradient_fill_linear [20, 20, 180, 40], "Medium Blue", :cyan, Wx::NORTH
dc.gradient_fill_linear [20, 80, 180, 40], '#ffec00', '#000000', Wx::SOUTH
dc.gradient_fill_linear [20, 140, 180, 40], '#ffec00', '#000000', Wx::EAST
dc.gradient_fill_linear [20, 200, 180, 40], '#ffec00', '#000000', Wx::WEST
dc.gradient_fill_linear [220, 20, 50, 120], '#cccccc', '#222222', Wx::WEST
dc.gradient_fill_linear [270, 20, 50, 120], '#cccccc', '#222222', Wx::EAST
end
end
.....

Wx::Brush
Brush temel elemanlardan biri, şekillerin içlerini boyamak için kullanılır. Olası brush tipleri:
- Wx::BRUSHSTYLE_SOLID
- Wx::BRUSHSTYLE_STIPPLE
- Wx::BRUSHSTYLE_BDIAGONAL_HATCH
- Wx::BRUSHSTYLE_CROSSDIAG_HATCH
- Wx::BRUSHSTYLE_FDIAGONAL_HATCH
- Wx::BRUSHSTYLE_CROSS_HATCH
- Wx::BRUSHSTYLE_HORIZONTAL_HATCH
- Wx::BRUSHSTYLE_VERTICAL_HATCH
- Wx::BRUSHSTYLE_TRANSPARENT
brushes.rb
require "wx"
class Örnek < Wx::Frame
def initialize(*args)
super(*args)
init_UI
end
def init_UI
set_size [400, 300]
set_title "Brushes"
centre
evt_paint :on_paint
end
def on_paint(e)
self.paint do |dc|
dc.brush = Wx::Brush.new '#4c4c4c', Wx::BRUSHSTYLE_CROSS_HATCH
dc.draw_rectangle 10, 15, 90, 60
dc.brush = Wx::Brush.new '#4c4c4c', Wx::BRUSHSTYLE_SOLID
dc.draw_rectangle 130, 15, 90, 60
dc.brush = Wx::Brush.new '#4c4c4c', Wx::BRUSHSTYLE_BDIAGONAL_HATCH
dc.draw_rectangle 250, 15, 90, 60
dc.brush = Wx::Brush.new '#4c4c4c', Wx::BRUSHSTYLE_CROSSDIAG_HATCH
dc.draw_rectangle 10, 105, 90, 60
dc.brush = Wx::Brush.new '#4c4c4c', Wx::BRUSHSTYLE_FDIAGONAL_HATCH
dc.draw_rectangle 130, 105, 90, 60
dc.brush = Wx::Brush.new '#4c4c4c', Wx::BRUSHSTYLE_HORIZONTAL_HATCH
dc.draw_rectangle 250, 105, 90, 60
dc.brush = Wx::Brush.new '#4c4c4c', Wx::BRUSHSTYLE_VERTICAL_HATCH
dc.draw_rectangle 10, 195, 90, 60
dc.brush = Wx::Brush.new '#4c4c4c', Wx::BRUSHSTYLE_TRANSPARENT
dc.draw_rectangle 130, 195, 90, 60
end
end
end
Wx::App.run {
Örnek.new(nil).show
}
Bu örnekte 8 değişik brush tipi kullanılıyor.

Kandi paternimiz
Ön tanımlı paternleri kullanmak zorunda değiliz, kendi paternimizi tanımlayabiliriz.
custom_patterns.rb
require "wx"
class Örnek < Wx::Frame
def initialize(*args)
super(*args)
init_UI
end
def init_UI
set_size [400, 150]
set_title "Kendi Paternimiz"
centre
evt_paint :on_paint
end
def on_paint(e)
self.paint do |dc|
dc.pen = Wx::Pen.new '#C7C3C3'
brush1 = Wx::Brush.new(Wx::Bitmap.new('bardejov.jpg'))
dc.brush = brush1
dc.draw_rectangle 10, 15, 90, 60
brush2 = Wx::Brush.new(Wx::Bitmap.new('mincol.jpg'))
dc.brush = brush2
dc.draw_rectangle 130, 15, 90, 60
brush3 = Wx::Brush.new(Wx::Bitmap.new('patern.png'))
dc.brush = brush3
dc.draw_rectangle 250, 15, 90, 60
end
end
end
Wx::App.run {
Örnek.new(nil).show
}
Resimleri patern olarak kullanabiliriz.
brush3 = Wx::Brush.new(Wx::Bitmap.new('patern.png'))
dc.brush = brush3
dc.draw_rectangle 250, 15, 90, 60
Son resimdeki küçük bir resim dosyası ve alanı doldurana kadar tekrarlanarak çoğaltılıyor.

draw_point metodu
En basit grafik nesnesi bir noktadır.
draw_point(x, y)
Bu metod x, y koordinatına bir nokta çizer.
points.rb
require "wx"
class Örnek < Wx::Frame
def initialize(*args)
super(*args)
init_UI
end
def init_UI
set_size [250, 150]
set_title "Noktalar"
centre
evt_paint :on_paint
end
def on_paint(e)
self.paint do |dc|
dc.pen = Wx::Pen.new :red
1000.times do
w, h = size
x = rand(1...w)
y = rand(1...h)
dc.draw_point x, y
end
end
end
end
Wx::App.run {
Örnek.new(nil).show
}
Bir tek noktayı görmek zor , bu yüzden 1000 tane çiziyoruz.
dc.pen = Wx::Pen.new :red
Noktalarımız kırmızı renkte olacak
w, h = size
x = rand(1...w)
y = rand(1...h)
Pencere genişlik ve yüksekliğini w ve h değişkenlerine alıyoruz, sonra da bu alan içinde rastgele bir koordinat belirliyoruz.

Şekiller
Şekiller daha gelişmiş grafik nesneler, örneğimizde çeşitli şekiller çiziyoruz.
shapes.rb
require "wx"
class Örnek < Wx::Frame
def initialize(*args)
super(*args)
init_UI
end
def init_UI
set_size [380, 320]
set_title "Şekiller"
centre
evt_paint :on_paint
end
def on_paint(e)
self.paint do |dc|
dc.pen = Wx::Pen.new "#777"
dc.brush = Wx::Brush.new "#777"
dc.draw_ellipse 20, 20, 90, 60
# x, y, width, height
dc.draw_rounded_rectangle 130, 20, 90, 60, 10
# x, y, width, height, radius
dc.draw_arc 240, 40, 340, 40, 290, 20
# xStart, yStart, xEnd, yEnd, xcenter, ycenter
dc.draw_rectangle 20, 120, 80, 50
# x, y, width, height
dc.draw_polygon [[130, 140], [180, 170], [180, 140], [220, 110], [140, 100]]
# points_arrays, xoffset, yoffset, fill_style
dc.draw_spline [[240, 170], [280, 170], [285, 110], [325, 110]]
# points_arrays
dc.draw_lines [[20, 260], [100, 260], [20, 210], [100, 210]]
# points_arrays, xoffset, yoffset
dc.draw_circle 170, 230, 35
# x, y, radius
dc.draw_rectangle 250, 200, 60, 60
end
end
end
Wx::App.run {
Örnek.new(nil).show
}

Bölgeler
Device context region adı verilen parçalara bölünebilir. Bir bölge dikdörtgen ya da daire gibi bir şekil olabilir. Union, Intersect, Substract ve Xor işlemleri ile karmaşık bölgeler oluşturabiliriz. Bölgeler çevreleme , doldurma ve kırpma işlerinde kullanılabilir.
Bölgeleri üç şekilde oluştururuz. En kolayı dik dörtgen bir bölge oluşturmaktır. Diğer bölgeler noktalardan ve bitmap resimlerden oluşturulabilir.
Bölgelere girmeden önce küçük bir örnek oluşturacağız. Bu kısmı kolay anlaşılabilir parçalara ayıracağız. Okul matematiğimizi tekrar gözden geçirmek gerekebilir, burada güzel bir makale var.
lines.rb
require "wx"
class Örnek < Wx::Frame
def initialize(*args)
super(*args)
init_UI
end
def init_UI
set_size [400, 250]
set_title "Çizgiler"
centre
evt_paint :on_paint
end
def on_paint(e)
self.paint do |dc|
size_x, size_y = get_client_size
dc.set_device_origin size_x/2, size_y/2
radius = Math.hypot size_x/2, size_y/2
angle = 0
while (angle < 2 * Math::PI) do
x = radius * Math.cos(angle)
y = radius * Math.sin(angle)
dc.draw_line [0, 0], [x, y]
angle = angle + 2 * Math::PI / 360
end
end
end
end
Wx::App.run {
Örnek.new(nil).show
}
Örneğimizde 1 derece aralıklı 360 tane çizgiyi tüm pencereye dolduruyoruz.
include Math
Math modülünü dahil ederek PI sabitinin , sin, cos ve hypot metodlarının başına sürekli Math:: yazmaktan kurtulabiliriz.
dc.set_device_origin size_x/2, size_y/2
Alanın koordinat merkezini sol üst köşeden pencere ortasına alıyoruz.
radius = hypot size_x/2, size_y/2
En uzun çizgi boyu olarak köşeye olan uzaklığı hipotenüs hesabı ile buluyoruz.
x = radius * cos(angle)
y = radius * sin(angle)
Çizginin bir ucu merkezde olacak diğer ucu da sinüs ve kosinüs ile açıya göre hesaplanan noktalarda.

Kırpmak
Kırpma sayesinde çizim alanını belli bir bölgeye sınırlarız. Çizim alanını kırpmak için set_clipping_region (veya clipping_region = ) metodunu kullanırız.
Aşağıdaki örnekte bir önceki örneğimizi kırpma sayesinde geliştiriyoruz.
region.rb
require "wx"
include Math
class Örnek < Wx::Frame
def initialize(*args)
super(*args)
init_UI
end
def init_UI
set_size [400, 250]
set_title "Region"
centre
evt_paint :on_paint
end
def on_paint(e)
self.paint do |dc|
size_x, size_y = get_client_size
dc.set_device_origin size_x/2, size_y/2
region = Wx::Region.new [10, 130], [130, 10]
dc.device_clipping_region = region
radius = hypot size_x/2, size_y/2
angle = 0
while (angle < 2 * PI) do
x = radius * cos(angle)
y = radius * sin(angle)
dc.draw_line [0, 0], [x, y]
angle = angle + 2 * PI / 360
end
dc.destroy_clipping_region
end
end
end
Wx::App.run {
Örnek.new(nil).show
}
Yine aynı çizgileri çiziyoruz ama bu sefer pencerenin belli bir kısmında çizim gerçekleşebiliyor.
region = Wx::Region.new [10, 130], [130, 10]
dc.device_clipping_region = region
2 nokta ile bir dikdörtgenin köşelerini belirliyoruz ve device_clipping_region = metodu ile (ya da set_device_clipping_region) çizim yapılabilecek alanı belirliyoruz.
dc.destroy_clipping_region
Çizim bitince bölgemizi yok ediyoruz.

Bölge operasyonları
Bölgeler karmaşık şekiller üretmekte kullanılabilir. 4 işlemimiz var, union, intersect, substract, xor.
Örneğimiz dört işlemi de kullanıyor.
region_operations.rb
require "wx"
include Math
class Örnek < Wx::Frame
def initialize(*args)
super(*args)
init_UI
end
def init_UI
set_size [400, 250]
set_title "Regions"
centre
evt_paint :on_paint
end
def on_paint(e)
self.paint do |dc|
dc.pen = Wx::Pen.new '#d4d4d4'
dc.draw_rectangle 20, 20, 50, 50
dc.draw_rectangle 30, 40, 50, 50
dc.brush = Wx::Brush.new '#ffffff'
dc.draw_rectangle 100, 20, 50, 50
dc.draw_rectangle 110, 40, 50, 50
region1 = Wx::Region.new 100, 20, 50, 50
region2 = Wx::Region.new 110, 40, 50, 50
region1.intersect region2
rect = region1.box
dc.device_clipping_region = region1
dc.brush = Wx::Brush.new '#ff0000'
dc.draw_rectangle rect
dc.destroy_clipping_region
dc.brush = Wx::Brush.new '#ffffff'
dc.draw_rectangle 180, 20, 50, 50
dc.draw_rectangle 190, 40, 50, 50
region1 = Wx::Region.new 180, 20, 50, 50
region2 = Wx::Region.new 190, 40, 50, 50
region1.union region2
dc.device_clipping_region = region1
rect = region1.box
dc.brush = Wx::Brush.new '#fa8e00'
dc.draw_rectangle rect
dc.destroy_clipping_region
dc.brush = Wx::Brush.new '#ffffff'
dc.draw_rectangle 20, 120, 50, 50
dc.draw_rectangle 30, 140, 50, 50
region1 = Wx::Region.new 20, 120, 50, 50
region2 = Wx::Region.new 30, 140, 50, 50
region1.xor region2
rect = region1.box
dc.device_clipping_region = region1
dc.brush = Wx::Brush.new '#619e1b'
dc.draw_rectangle rect
dc.destroy_clipping_region
dc.brush = Wx::Brush.new '#ffffff'
dc.draw_rectangle 100, 120, 50, 50
dc.draw_rectangle 110, 140, 50, 50
region1 = Wx::Region.new 100, 120, 50, 50
region2 = Wx::Region.new 110, 140, 50, 50
region1.subtract region2
rect = region1.box
dc.device_clipping_region = region1
dc.brush = Wx::Brush.new '#715b33'
dc.draw_rectangle rect
dc.destroy_clipping_region
dc.brush = Wx::Brush.new '#ffffff'
dc.draw_rectangle 180, 120, 50, 50
dc.draw_rectangle 190, 140, 50, 50
region1 = Wx::Region.new 180, 120, 50, 50
region2 = Wx::Region.new 190, 140, 50, 50
region2.subtract region1
rect = region2.box
dc.device_clipping_region = region2
dc.brush = Wx::Brush.new '#0d0060'
dc.draw_rectangle rect
dc.destroy_clipping_region
end
end
end
Wx::App.run {
Örnek.new(nil).show
}
Örnekte 6 değişik region operasyonu yapıyoruz.
region1 = Wx::Region.new 100, 20, 50, 50
region2 = Wx::Region.new 110, 40, 50, 50
region1.intersect region2
Bu operasyon iki region kesişimini alıyor.

Ölçü birimleri
DC nesnesine bir yazı ya da şekil çizerken aslında biz piksel değil mantıksal boyutlar veriyoruz. Default ölçü birimi piksel olduğu için yazdığımız sayılar piksel olarak değerlendiriliyor. Mantıksal birimler ve DC nesnesinin birimleri farklı olabilir. İnsanların kullandığı birim milimetre iken , ekran piksel kullanır, printer için 1200 dpi (dots per inch - inç başına nokta sayısı) olabilir.
Bizim girdiğimiz koordinatları kullanılan DC birimlerine çevirme işlemine mapping mode deniyor.
Mapping Mode | Logical Unit |
Wx::MM_TEXT | 1 piksel |
Wx::MM_METRIC | 1 milimetre |
Wx::MM_LOMETRIC | Milimetreni 1/10'u |
Wx::MM_POINTS | 1 point, inç'in 1/72'si |
Wx::MM_TWIPS | point'in 1/20'si veya inç'in 1/1440'ı |
Defaulr mapping mode Wx::MM_TEXT , bu durumda yazdığımız her birim ekranda bir piksele karşı geliyor. İnsanlar genelde ekranda bir şeyi pozisyonlamak için ya da web sayfası tasarımlarında hep piksel kullanırlar. Eğer milimetre düşünmek istersek elimizde 2 mod var, Wx::MM_METRIC ve Wx::MM_LOMETRIC
Başka moda geçmak için set_map_mode (ya da map_mode= ) metodu kullanılır.
Cetvel örneği
Cetvel ile ekranda milimetrik ölçüm yapmaya çalışacağız.
ruler.rb
require "wx"
RW = 701 # cetvel genişlik
RM = 10 # cetvel marjin
RH = 80 # cetvel yükseklik
class Örnek < Wx::Frame
def initialize(*args)
super(*args)
init_UI
end
def init_UI
set_size [RW + 2*RM, RH]
@font = Wx::Font.new 7, Wx::FONTFAMILY_DEFAULT, Wx::FONTSTYLE_NORMAL,
Wx::FONTWEIGHT_BOLD, false, 'Courier 10 Pitch'
set_title "Cetvel"
centre
evt_paint :on_paint
evt_left_down :on_left_down
evt_motion :on_mouse_move
evt_left_up :on_left_up
evt_right_down :on_right_down
end
def on_paint(e)
self.paint do |dc|
#dc.map_mode = Wx::MM_LOMETRIC
dc.brush = Wx::Brush.new Wx::Bitmap.new('patern.png')
dc.draw_rectangle 0, 0, RW+2*RM, RH
dc.font = @font
dc.pen = Wx::Pen.new '#F8FF25'
dc.text_foreground = '#F8FF25'
for i in (0..RW)
if (i % 100 == 0)
dc.draw_line i+RM, 0, i+RM, 10
w, h = dc.text_extent(i.to_s)
dc.draw_text i.to_s, i+RM-w/2, 11
elsif (i % 20 == 0)
dc.draw_line i+RM, 0, i+RM, 8
elsif (i % 2 == 0)
dc.draw_line i+RM, 0, i+RM, 4
end
end
end
end
def on_left_down(e)
x, y = client_to_screen(e.position)
ox, oy = position
dx = x - ox
dy = y - oy
@delta = [dx, dy]
end
def on_mouse_move(e)
if e.dragging and e.left_is_down
set_cursor Wx::Cursor.new(Wx::CURSOR_HAND)
x, y = client_to_screen e.get_position
fp = [x - @delta[0], y - @delta[1]]
move fp
end
end
def on_left_up(e)
set_cursor Wx::Cursor.new(Wx::CURSOR_ARROW)
end
def on_right_down(e)
close
end
end
Wx::App.run {
Örnek.new(nil, style: Wx::FRAME_NO_TASKBAR | Wx::NO_BORDER | Wx::STAY_ON_TOP).show
}
Bir cetvel yapıyoruz. Cetvelimiz default olan piksel modunda çalışıyor.
Wx::App.run {
Örnek.new(nil,
style: Wx::FRAME_NO_TASKBAR | Wx::NO_BORDER | Wx::STAY_ON_TOP).show
}
Stil olarak görev çubuğunda görünmeyen , etiket barı olmayan ve her şeyin üstünde duran bir pencere yaptık.
dc.brush = Wx::Brush.new Wx::Bitmap.new('patern.png')
dc.draw_rectangle 0, 0, RW+2*RM, RH
Arkaplana bir patern koyduk.
w, h = dc.text_extent(i.to_s)
dc.draw_text i.to_s, i+RM-w/2, 11
text_extent metodu çizim alanının kullandığı yazı ölçüleriyle o argümanındaki yazının kapladığı boyutu döndürür.
def on_mouse_move(e)
if e.dragging and e.left_is_down
set_cursor Wx::Cursor.new(Wx::CURSOR_HAND)
x, y = client_to_screen e.get_position
fp = [x - @delta[0], y - @delta[1]]
move fp
end
end
Penceremizin etiket barı olmadığı için mouse ile tutup çekerek kaydırıyoruz.
def on_right_down(e)
close
end
Sağ tıklama ile uygulamayı kapatabiliriz.
Grafikler kısmı burada bitiyor. Sonraki bölümde kendi widget'larımızı oluşturacağız inşallah. Şimdilik kalın sağlıcakla..

Hiç yorum yok:
Yorum Gönder