6 Mart 2025 Perşembe

WxRuby3 ile Masaüstü Uygulama Geliştirmek 1

https://ujk-ujk.blogspot.com/2025/03/wxruby3-ile-masaustu-uygulama.html
İçindekiler +

 Selam Ruby ile masaüstü program yazmak üzerine neler yapabilirim bir göreyim dedim ve başladım denemelere. Denemelerimi Windows'ta yaptım. Windows üzerinde bende kurulu olan versiyon ruby 3.4.2 (2025-02-15 revision d2930f8e7a) +PRISM [x64-mingw-ucrt] olarak geliyor. Ruby installer sitesinden Ruby+Devkit 3.4.2-1 (x64) versiyonu indirip kurdum. 


WxRuby3 Kurulumu

WxRuby3 GUI kütüphanesini yüklemek için komut isteminde 

gem install wxruby3

komutunu girdim ve sıkıntısız yüklendi. Sizde sorun olurssa bendeki versiyon Ruby ile deneme yaparsınız. 

Hemen deneme yapmak için hello.rb adında bir dosya üretip içine şu kodu yazdım.

require 'wx'
Wx::App.run { puts 'Merhaba Dünya!' }


Aslında bu kod pek bir şey yapmıyor, eğer çalışırsa konsola Merhaba Dünya! yazıp bitiyor. Bu programın amacı WxRuby kütüphanesi kullanımının başarılı olduğunu görmek. Programı incelersek 

require 'wx' komutu kurduğumuz WxRuby3 Gem dosyalarının programımızda kullanılacağını belirtiyor. 

Wx::App sınıfı , ana Wx programı sınıfı. Bu sınıfın run metodunu çağırarak Wx uygulaması çalıştırılıyor. run metoduna verilen blok içindeki program bir Wx uygulaması olarak çalıştırılıyor. Dökümanına bakarsak run metodu Wx::App sınıfının bir oluşumunu üretiyor ve verilen kod bloğunu da bu nesnenin #on_init olayına bağlıyor, Yani nesne üretilince bloktaki kod çalışıyor. 

Şimdi bir pencere üreterek ekranımızda gösteren bir kod yazalım bloğun içine. 

require 'wx'
Wx::App.run { Wx::Frame.new(nil, title: 'Merhaba Dünya!').show }


Bu kod jenerik bir Frame (pencere) nesnesi üretiyor ve onun show metodunu çağırıyor. new metodunun ilk argümanı nil olarak verilmiş , bu Frame nesnesinin parent değeri. Bu değerin nil olması penceremizin bağımsız bir pencere olduğunu gösteriyor. Eğer buraya bir Wx::Window nesnesi beliritilirse penceremiz o nesneyle beraber minimize ve restore olacakmış (tabi kendi bağımsız olarak minimize de edilebilecek). İkinci argüman ise isimlendirilmiş olarak :title değerini belirtiyor, adından da anlaşılabileceği gibi pencere etiketinde yazan yazıyı belirliyor. İlerleyen zamanda başka argümanlar da kullanacağız. 

show metodu uygulandığı pencereyi göstermek (ya da gizlemek) için kullanılıyor. 

Şimdi programı çalıştıralım. 


Karşımıza default boyutta ve default pozisyonda bir pencere açılacaktır. 


Uygulama sınıfı tanımlamak

Daha karmaşık uygulamalar yazarken Wx::App sınıfından türetilmiş kendi sınıfımızı tanımlamak çok daha faydalı olacaktır.  Bu sayede #initialize, #on_init ve #on_exit metodlarının üzerine yazarak istediğimiz davranışı göstermesini yönetebiliriz. 

hello2.rb

require 'wx'

class MyApp < Wx::App
  def initialize
    super
    @frame = nil
  end
  attr_reader :frame
 
  # run deyince çalışacak
  def on_init
    @frame = Wx::Frame.new(nil, title: 'Merhaba Dünya!')
    @frame.show
  end
 
  # pencereyi kapatınca çalışacak
  def on_exit
    puts 'Çıkıyoruz.'
  end
end

MyApp.run


Burada #on_init ve #on_exit metodlarının üzerine yazılmıyor, orjinal Wx::App sınıfında bu metodlar yok. Bu yüzden tanımlamalarında super ifadesi kullanılmıyor. 

Eğer sınıfta on_init tanımlı değilse run metodu argümanında verilen blok çalıştırılır. Eğer on_init metodu tanımlanmışsa (ki bizim ürettiğimiz sınıfta mevcut) o zaman run metodu bu on_init metodunu çalıştıracaktır. Bu yüzden kod bloğu bermeden sadece MyApp.run demek yeterli olmuştur.

Uygulamanın oluşum nesnesine uygulama hala aktifken 

 Wx.get_app

olarak erişebiliriz. 



Pencere sınıfı tanımlamak

Kendi pencere sınıfımızı tanımlayıp onu da kullanabiliriz. Böylece pencere içindeki elemanları daha düzenli kodlayabiliriz. 

hello3.rb

require 'wx'

class TheFrame < Wx::Frame
  def initialize(title)
    super(nil, title: title)
    panel = Wx::Panel.new(self)
    button = Wx::Button.new(panel, label: 'Bana Tıklayınız')
    button.evt_button(Wx::ID_ANY) do
      Wx.message_box('Merhaba. Bana tıkladığın için teşekkürler!',
        'Buton olayı')
    end
  end
end

class MyApp < Wx::App
  def initialize
    super
    @frame = nil
  end
  attr_reader :frame
 
  # run deyince çalışacak
  def on_init
    @frame = TheFrame.new('Merhaba Dünya!')
    @frame.show
  end
 
  # pencereyi kapatınca çalışacak
  def on_exit
    puts 'Çıkıyoruz.'
  end
end

MyApp.run

ve çıktısı



Wx::Frame

Wx::Frame sınıfı oluşum kodu kalıbı

Wx::Frame.new(parent, id, title, pos = Wx::DEFAULT_POSITION,
    size = Wx::DEFAULT_SIZE, style = Wx::DEFAULT_FRAME_STYLE,
    name = Wx::FRAME_NAME_STR)

id : Pencereyi simgeleyen sayı , default -1

pos (Array(Integer, Integer), Wx::Point) : Pencrenin sol üst köşesinin ekrana göre pozisyonu - x, y

  frame = Wx::Frame.new(nil, pos: [150, 50])


size (Array(Integer, Integer), Wx::Size)  : Pencere boyutu - genişlik, yükseklik

  frame = Wx::Frame.new(nil, size: [400, 200])


style (Integer) : Bir çok flag bitlerinden oluşan stil sayısı default olarak 

    MINIMIZE_BOX | MAXIMIZE_BOX | RESIZE_BORDER | SYSTEM_MENU | CAPTION |
CLOSE_BOX | CLIP_CHILDREN


Örnek :

no_minimize.rb

require "wx"

Wx::App.run {
  Wx::Frame.new(nil,
    style: Wx::MAXIMIZE_BOX | Wx::RESIZE_BORDER |
          Wx::SYSTEM_MENU | Wx::CAPTION |  Wx::CLOSE_BOX).show
}




Boyut ve Pozisyon

Pencere boyutunu iki şekilde belirtiriz. Ya pencereyi oluştururken ya da sonradan set_size metodunu çağırarak. 

set_size.rb

require "wx"

class Örnek < Wx::Frame
  def initialize(parent, title)
    super(parent, title: title,
        size: [350, 250])
  end
end

Wx::App.run {
  Örnek.new(nil, 'Boyutlandırma').show
}


Sonradan boyutlandırırsak

require "wx"

class Örnek < Wx::Frame
  def initialize(parent, title)
    super(parent, title: title)
  end
end

Wx::App.run {
  p = Örnek.new(nil, 'Boyutlandırma')
  p.set_size 100,200,350,250
  p.show
}
# x=100 - y=200 - w=350 - h=250

ya da pozisyon belirtmeden

  p.set_size [350, 250]


Pencereyi istediğimiz yere kaydırabiliriz. 

move.rb

require "wx"

class Örnek < Wx::Frame
  def initialize(parent, title)
    super(parent, title: title,
        size: [300, 200])
    move [800, 200]
  end
end

Wx::App.run {
  Örnek.new(nil, 'Kaydırma').show
}




Ekranı Ortalamak

Pencerenin ekranı ortalaması için centre metodunu kullanırız. 

merkezleme.rb

require "wx"

class Örnek < Wx::Frame
  def initialize(parent, title)
    super(parent, title: title,
        size: [300, 200])
    centre
  end
end

Wx::App.run {
  Örnek.new(nil, 'Ortalama').show
}


Yatay ya da dikey olarak da ortalamak mümkün.

    centre  Wx::Orientation::VERTICAL
    centre  Wx::Orientation::HORIZONTAL




Menüler, Toolbarlar

Bir GUI uygulamasının temel öğelerinden biri menülerdir. Bir MenuBar nesnesi içinde Menu nesneleri barındırır. 


Basit Menü

simple_menu.rb

require "wx"

class Örnek < Wx::Frame
  def initialize(*args)
    super(*args)
    init_UI
  end
  def init_UI
    set_size [300, 200]
    set_title "Basit Menü"
    centre

    menubar = Wx::MenuBar.new
    file_menu = Wx::Menu.new
    file_item = file_menu.append(Wx::ID_EXIT, "&Çıkış", "Uygulamadan çıkış")
    menubar.append file_menu, "&Dosya"
    set_menu_bar menubar

    evt_menu(file_item) { close }
  end
end

Wx::App.run {
  Örnek.new(nil).show
}



Önce bir MenuBar nesnesi oluşturuyoruz. menubar = Wx::MenuBar.new

Sonra üzerine eklemek için bir Menu nesnesi ekliyoruz. file_menu = Wx::Menu.new

Menu nesnesine eleman ekliyoruz (popup içinde görünen)  file_item = file_menu.append(Wx::ID_EXIT, "&Çıkış", "Uygulamadan çıkış")

& karakteri hangi harfin önüne gelirse Alt tuşuna basıldığında o harfin altı çizili olur (tuşlar ile menü seçme standardı)

Daha sonra Menu nesnemizi MenuBar nesnemize başlığını belirterek ekliyoruz. menubar.append file_menu, "&Dosya"

Son olarak Frame#set_menu_bar metodu ile MenuBar nesnemizi penceremize ekliyoruz. set_menu_bar menubar

Eklediğimiz menüye tıklanınca ne olacağını da evt_menu olay işleme metoduna verdiğimiz kod bloğunda belirtiyoruz. evt_menu(file_item) { close }

Burada tıklanınca Frame#close metodu çağrılıyor, yani pencere kapatılıp uygulama bitiriliyor. 



İkonlar ve kısayollar

Sıradaki örneğimiz temelde önceki ile aynı, ancak bu sefer Wx::MenuItem oluşum nesnesini elle oluşturacağız.

icons_shortcuts.rb

require "wx"

class Örnek < Wx::Frame
  def initialize(*args)
    super(*args)
    init_UI
  end
  def init_UI
    set_size [300, 200]
    set_title "İkonlar ve Kısayollar"
    centre

    menubar = Wx::MenuBar.new
    file_menu = Wx::Menu.new
    qmi = Wx::MenuItem.new(file_menu, Wx::ID_EXIT, "&Çıkış\tCTRL+Q")
    qmi.set_bitmap(Wx::Bitmap.new('exit_16.png'))
    file_menu.append qmi
    menubar.append file_menu, "&Dosya"
    set_menu_bar menubar

    evt_menu(Wx::ID_EXIT) { close }
  end
end

Wx::App.run {
  Örnek.new(nil).show
}


qmi nesnesini oluştururken standart Wx::ID_EXIT id değerini kullandık. Wx::StandardID sınıfında tanımlı birçok hazır ID değeri var. Kendimizde bir sayı girebiliriz ama karışıklık olmasın diye hazırlardan işimize uyan varsa onu kullanmak daha iyidir. 

Logo için resim dosyasını internetten bulup koydum. 

Olay işleyici satırına 

    evt_menu(qmi) { close }

de yazsak çalışır, id de versek çalışır. "&Çıkış\tCTRL+Q" değeri tuş takımı yardımıyla Alt+d+ç kombinasyonu ile çıkabileceğimiz gibi, hiç menü açmadan Ctrl+q basarak da uygulamadan çıkabiliriz. \t ile kısayol tuşu bildiriliyor.




Alt menü ve seperatörler

Her menüde alt menüler de olabilir. Bir de mesela Yeni Aç, Kaydet gibi menü elemanları ile Çıkış elemanı arasına bir ayırıcı (separator) koysak iyi olur.

submenu.rb

require "wx"

class Örnek < Wx::Frame
  def initialize(*args)
    super(*args)
    init_UI
  end
  def init_UI
    set_size [350, 250]
    set_title "Alt Menü"
    centre

    menubar = Wx::MenuBar.new
    file_menu = Wx::Menu.new

    file_menu.append Wx::ID_NEW, '&Yeni'
    file_menu.append Wx::ID_OPEN, '&Aç'
    file_menu.append Wx::ID_SAVE, '&Kaydet'
    file_menu.append_separator

    imp = Wx::Menu.new
    imp.append Wx::ID_ANY, "Haber listesi al..."
    imp.append Wx::ID_ANY, "Yer imlerini al..."
    imp.append Wx::ID_ANY, "Eposta al..."

    file_menu.append_sub_menu imp, "I&mport"

    file_menu.append Wx::ID_EXIT, "&Çıkış\tCTRL+Q"

    menubar.append file_menu, "&Dosya"
    set_menu_bar menubar

    evt_menu(Wx::ID_EXIT) { close }
  end
end

Wx::App.run {
  Örnek.new(nil).show
}


Alt menümüz yine bir Wx::Menu nesnesi ve üst menüye append_sub_menu metodu ile ekleniyor. İlk argüman eklenecek olan Wx::Menu nesnesi ikinci de menü başlık yazısı. 

Ayrıcı eklemek içinse append_separator metodu kullanılıyor.


İstersek hazır bulunan ikonları menülere ekleyebiliriz. 

    file_menu.append(Wx::ID_NEW, '&Yeni').
        set_bitmap(Wx::ArtProvider.get_bitmap(Wx::ART_NEW))
    file_menu.append(Wx::ID_OPEN, '&Aç').
        set_bitmap(Wx::ArtProvider.get_bitmap(Wx::ART_FILE_OPEN))
    file_menu.append(Wx::ID_SAVE, '&Kaydet').
        set_bitmap(Wx::ArtProvider.get_bitmap(Wx::ART_FILE_SAVE))


Dökümanda sabitler listesinde ART_ ile başlayan sabitleri deneyebilirsiniz. 





Checkbox menü elemanı

3 çeşit menü elemanı vardır. 

  • normal eleman
  • check eleman
  • radio eleman

Aşağıdaki örnekte check menü elemanı görülüyor. Check menü tiklenebilir bir menü elemanı görüntüsü verir. 

checkmenu_item.rb

require "wx"

class Örnek < Wx::Frame
  def initialize(*args)
    super(*args)
    init_UI
  end
  def init_UI
    set_size [350, 250]
    set_title "Check Menü Elemanı"
    centre

    toolbar = create_tool_bar
    toolbar.add_tool Wx::ID_EXIT, "",
      Wx::ArtProvider.get_bitmap(Wx::ART_QUIT)
    toolbar.realize

    statusbar = create_status_bar
    statusbar.set_status_text "Ready"

    menubar = Wx::MenuBar.new
    view_menu = Wx::Menu.new

    shst = view_menu.append Wx::ID_ANY, "Durum çubuğunu göster",
        "Araç çubuğunu göster", Wx::ITEM_CHECK
    shtl = view_menu.append Wx::ID_ANY, "Araç çubuğunu göster",
        "Araç çubuğunu göster", Wx::ITEM_CHECK

    view_menu.check shst.id, true
    view_menu.check shtl.id, true

    menubar.append view_menu, "&Görünüm"
    set_menu_bar menubar

    evt_menu(shst) { shst.checked? ? statusbar.show : statusbar.hide }
    evt_menu(shtl) { shtl.checked? ? toolbar.show : toolbar.hide }
    evt_menu(Wx::ID_EXIT) { close }
  end
end

Wx::App.run {
  Örnek.new(nil).show
}


Görünüm menümüzün içine iki tane check menü elemanı ekledik. Bu iki menü elemanı ile durum çubuğu ve araç çubuğunu gösterip gizliyoruz. 

    shst = view_menu.append Wx::ID_ANY, "Durum çubuğunu göster",
        "Araç çubuğunu göster", Wx::ITEM_CHECK
    shtl = view_menu.append Wx::ID_ANY, "Araç çubuğunu göster",
        "Araç çubuğunu göster", Wx::ITEM_CHECK

view_menu nesnemizin append metodu ilk iki parametresini daha önce kullandık, id numarası ve menüde yazan yazı. Üçüncü parametre yardım yazısı, dördüncü ise kind (yani tür) bilgisi. Dördüncü argümanda Wx::ITEM_CHECK girerek menü elemanının bir tiklemeli menü elemanı olduğunu bildiriyoruz. Sonrasında 

    view_menu.check shst.id, true
    view_menu.check shtl.id, true

satırları ile her iki menü elemanının da başlangıçta tiklenmiş olarak gelmesini sağlıyoruz. Bu arada deneme yapalım derken basit de olsa durum ve araç çubuğu eklemesini de gördük .

Menülere tıklanınca yapılacaklar

    evt_menu(shst) { shst.checked? ? statusbar.show : statusbar.hide }
    evt_menu(shtl) { shtl.checked? ? toolbar.show : toolbar.hide }

satırlarındaki olay işleme kodları ile belirleniyor. checked? metodu menü elemanının o anda seçili olup olmadığını test ediyor. show ve hide metodları ise hemen tüm kontrollerdeki gibi uygulandığı nesnenin görünmesi ya da gizlenmesini sağlıyor.



Bağlamsal menüler

Bağlamsal menü (context menu) değişik bağlamlarda değişik menülerin açılması şeklinde oluşan menülerdir. Örneğin tarayıcınızda sayfa içine sağ tıklarsanız başka menü, adrese sağ tıklarsanız başka bir menü, pencere başlığına tıklayınca başka bir menü açılır. Bunlara bazen popup menü de denir. 

context_menu.rb

require "wx"

class MyPopupMenu < Wx::Menu

  def initialize(*args, parent)
    super(*args)

    @parent = parent

    mmi = Wx::MenuItem.new(self, Wx::ID_ANY, 'Minimize')
    append mmi
    evt_menu(mmi) { on_minimize }

    cmi = Wx::MenuItem.new(self, Wx::ID_ANY, 'Kapat')
    append cmi
    evt_menu(cmi) { on_close }
  end

  def on_minimize
    @parent.iconize
  end

  def on_close
    @parent.close
  end
end

class Örnek < Wx::Frame
  def initialize(*args)
    super(*args)
    init_UI
  end
  def init_UI
    set_size [350, 250]
    set_title "Bağlamsal Menü"
    centre

    evt_right_down { |e| on_right_down(e) }
  end

  def on_right_down(e)
    popup_menu MyPopupMenu.new(self), e.get_position
  end
end

Wx::App.run {
  Örnek.new(nil).show
}


Öncelikle Wx::Menu sınıfından kendi MyPopupMenu sınıfımızı üretiyoruz. 

    mmi = Wx::MenuItem.new(self, Wx::ID_ANY, 'Minimize')
    append mmi
    evt_menu(mmi) { on_minimize }

Bu satırlarla menümüze yeni bir menü elemanı ekliyoruz. Olay işlemeyi eğer kod bloğu içinde yapmayacaksak dışarıdan başka bir oluşum metodu da çağırabiliriz. 

    evt_right_down { |e| on_right_down(e) }
  end

  def on_right_down(e)
    popup_menu MyPopupMenu.new(self), e.get_position
  end

Burada görülense dışarıdan çağrılan metoda olay bilgisini içeren bir nesne göndermek. Frame üzerinde sağ tıklanan yeri bulmak için get_position metodu ile olay bilgisinden çekiyoruz, ve popup orada açıyoruz. 

Şimdi çalıştırıp pencere içinde bir yere sağ tıklarsak.




Araç Kutuları

Menülerde bir hiyerarşi içinde uygulamamıza gerekli tüm işlemleri menülerimizde toplarız. Araç kutularında ise çok kullanılan bazı işlemleri hızlıca erişilebilir biçimde penceremize koyarız. Wx::Frame nesnesinde araç kutusu oluşturmak için create_tool_bar metodunu çağırırız.

toolbar.rb

require "wx"

class Örnek < Wx::Frame
  def initialize(*args)
    super(*args)
    init_UI
  end
  def init_UI
    set_size [350, 250]
    set_title "Basit Araç Kutusu"
    centre

    toolbar = create_tool_bar
    qtool = toolbar.add_tool Wx::ID_EXIT, "Çıkış",
      Wx::ArtProvider.get_bitmap(Wx::ART_QUIT)
    toolbar.realize

    evt_menu(qtool) { close }
  end
end

Wx::App.run {
  Örnek.new(nil).show
}


Örnekte araç kutumuzda bir tane araç butonu var ve uygulamadan çıkılmasını sağlıyor. 

    toolbar = create_tool_bar

Araç kutumuzu üretir. Default olarak araç kutumuz yatay olur, sınır çizgileri yoktur ve ikonlar gösterir. 

    qtool = toolbar.add_tool Wx::ID_EXIT, "Çıkış",
      Wx::ArtProvider.get_bitmap(Wx::ART_QUIT)

Bu satır da bir araç butonu ekliyor. add_tool metodu ilk parametresi id değeri, ikinci ise etiket yazısı (ki bu yazı görünmez), üçüncüsü de butondaki resim. 

    toolbar.realize

Bütün araç butonlarımız bittikten sonra realize metodu ile aktif hale getiriyoruz. 


Eğer bir'den fazla araç kutusu olacaksa farklı davranmak gerekir. 

toolbars.rb

require "wx"

class Örnek < Wx::Frame
  def initialize(*args)
    super(*args)
    init_UI
  end
  def init_UI
    set_size [350, 250]
    set_title "Araç Kutuları"
    centre

    vbox = Wx::VBoxSizer.new

    toolbar1 = Wx::ToolBar.new(self)
    toolbar1.add_tool Wx::ID_NEW, "",
      Wx::ArtProvider.get_bitmap(Wx::ART_NEW)
    toolbar1.add_tool Wx::ID_OPEN, "",
      Wx::ArtProvider.get_bitmap(Wx::ART_FILE_OPEN)
    toolbar1.add_tool Wx::ID_SAVE, "",
      Wx::ArtProvider.get_bitmap(Wx::ART_FILE_SAVE)
    toolbar1.realize

    toolbar2 = Wx::ToolBar.new(self)
    toolbar2.add_tool Wx::ID_EXIT, "",
      Wx::ArtProvider.get_bitmap(Wx::ART_QUIT)
    toolbar2.realize

    vbox.add toolbar1, 0, Wx::EXPAND
    vbox.add toolbar2, 0, Wx::EXPAND
    set_sizer vbox

    evt_tool(Wx::ID_EXIT) { close }
  end
end

Wx::App.run {
  Örnek.new(nil).show
}


Bu örnekte iki tane yatay araç kutusu üretiyoruz.

    toolbar1 = Wx::ToolBar.new(self)
...
    toolbar2 = Wx::ToolBar.new(self)

Bu iki araç kutusunu dikey bir yerleşim yardımcısına yerleştirdik.




Aktif-Pasif araç butonları

Aşağıdaki örnekte araç butonlarının aktif veya pasif olmasını göreceğiz. Ayrıca araç kutumuza bir ayırıcı da ekleyeceğiz.

undo_redo.rb

require "wx"

class Örnek < Wx::Frame
  def initialize(*args)
    super(*args)
    init_UI
  end
  def init_UI
    set_size [350, 250]
    set_title "Undo Redo"
    centre

    @count = 5

    vbox = Wx::VBoxSizer.new

    @toolbar = create_tool_bar
    tundo = @toolbar.add_tool Wx::ID_UNDO, "",
      Wx::ArtProvider.get_bitmap(Wx::ART_UNDO)
    tredo = @toolbar.add_tool Wx::ID_REDO, "",
      Wx::ArtProvider.get_bitmap(Wx::ART_REDO)
    @toolbar.enable_tool Wx::ID_REDO, false
    @toolbar.add_separator
    texit = @toolbar.add_tool Wx::ID_EXIT, "",
      Wx::ArtProvider.get_bitmap(Wx::ART_QUIT)
    @toolbar.realize

    evt_tool(Wx::ID_UNDO) { on_undo }
    evt_tool(Wx::ID_REDO) { on_redo }
    evt_tool(Wx::ID_EXIT) { close }
  end

  def on_undo
    if @count > 1 and @count <= 5
      @count -= 1
    end

    if @count == 1
        @toolbar.enable_tool Wx::ID_UNDO, false
    end

    if @count == 4
        @toolbar.enable_tool Wx::ID_REDO, true
    end
  end

  def on_redo
    if @count < 5 and @count >= 1
      @count += 1
    end

    if @count == 5
        @toolbar.enable_tool Wx::ID_REDO, false
    end

    if @count == 2
        @toolbar.enable_tool Wx::ID_UNDO, true
    end
  end
end

Wx::App.run {
  Örnek.new(nil).show
}


Uygulamamızda 3 tane araç butonu ekledik , biri uygulamadan çıkmak için diğerleri de undo-redo (geri al - yinele) işlemlerini simüle etmek için. 

    @toolbar.enable_tool Wx::ID_REDO, false
    @toolbar.add_separator

İlk başta redo butonu pasif durumda olacak , pasif yapmak için enable_tool metodunu kullanıyoruz. Araç butonu gruplarını birbirinden ayırmak için add_separator metodunu kullanıyoruz. Bu bazı işletim sistemlerinde bir çizgi eklerken mesela bende sadece butonlar arasını biraz boşlukla açıyor. 

  def on_undo
    if @count > 1 and @count <= 5
      @count -= 1
    end

    if @count == 1
        @toolbar.enable_tool Wx::ID_UNDO, false
    end

    if @count == 4
        @toolbar.enable_tool Wx::ID_REDO, true
    end
  end

Undo ve redo işlemlerinin simülasyonunu yapıyoruz. 4 tane değişimimiz varmış ve geri alacak bir şey kalmayınca undo butonu pasif oluyor. İlk değişikliği geri alınca redo butonunu aktif ediyoruz. Benzer lojik redo butonu için de geçerli. 

Bu bölümde WxRuby3 uygulama geliştirmede menüleri ve araç kutularını inceledik. Pencere yerleşimi ile devam edelim.




WxRuby'de Yerleşim Yönetimi

Tipik bir uygulamada birçok widget bulunur (ben bunlara 'zımbırtı' diyorum, bazen 'kontrol' dendiği de olur). Bu widget'lar başka barındırıcı widget'lar içine konarak yerleşimleri yönetilir. Wx kütüphanesinde yerleşimi sabit pozisyonlama ile ya da boyutlandırıcılar ile yönetmek mümkün, ve bu biraz karmaşık bir iş.


Mutlak pozisyonlama

Programlayıcı her kontrolün yerleşeceği yeri ve boyutlarını piksel olarak bildirir. Mutlak pozisyonlamanın bazı dezavantajları vardır.

  • Pencere boyutu değişince kontrollerin boyutu ve yerleşimi orantılı olarak değişmez. Bu yüzden genellikle boyutu değiştirilemeyen bilgilendirme pencerelerinde falan kullanılır.
  • Değişik işletim sistemlerinde (ve hatta ayarları değişik olan aynı sistemlerde bile) farklı görünen uygulamalar oluşur. 
  • Uygulamanızda yazı font'unu değiştirmek yerleşimde bozulmalara sebep olabilir.
  • Yerleşimi değiştirmeye karar verdiğimizde tüm yerleşimi elden geçirmemiz gerekir ki bu hem sıkıcı hem de yorucu olur.

Bazen , mesela denemeler yaparken , mutlak pozisyonlama ile hızlıca deneme yapabiliriz. Ancak gerçek dünya uygulamaları, boyutlandırıcıların kullanılmasını gerektirir.

Uygulama örneğimizde resimler olacak ve pencere boyutu değiştirilince resimlerin pozisyonunun otomatik değişmediğini göreceğiz. 

absolute.rb

require "wx"

class Örnek < Wx::Frame
  def initialize(*args)
    super(*args)
    init_UI
  end
  def init_UI
    set_size [350, 300]
    set_title "Mutlak Pozisyonlama"
    centre

    @panel = Wx::Panel.new(self)
    @panel.background_colour = "gray"

    load_images

    @mincol.position = [20, 20]
    @bardejov.position = [40, 160]
    @rotunda.position = [170, 50]
  end

  def load_images
    @mincol = Wx::StaticBitmap.new(@panel, Wx::ID_ANY,
            Wx::Bitmap.new("mincol.jpg", Wx::BITMAP_TYPE_ANY))

    @bardejov = Wx::StaticBitmap.new(@panel, Wx::ID_ANY,
            Wx::Bitmap.new("bardejov.jpg", Wx::BITMAP_TYPE_ANY))

    @rotunda = Wx::StaticBitmap.new(@panel, Wx::ID_ANY,
            Wx::Bitmap.new("rotunda.jpg", Wx::BITMAP_TYPE_ANY))
  end
end

Wx::App.run {
  Örnek.new(nil).show
}






Boyutlandırıcı kullanmak

Boyutlandırıcılar mutlak pozisyonlama için verdiğimiz tüm dezavantajları halleder. WxRuby kütüphanesinde şu boyutlandırıcılar var.

  • Wx::BoxSizer
  • Wx::StaticBoxSizer
  • Wx::GridSizer
  • Wx::FlexGridSizer
  • Wx::GridBagSizer


Wx::BoxSizer

Wx::BoxSizer boyutlandırıcı içine kontrollerimizi yatay ya da dikey olarak sıralayabiliriz. Karmaşık yerleşimler oluşturmak için bir boyutlandırıcı içine diğerini koyarak kombinasyonlar üretebiliriz. 

    box = Wx::BoxSizer(integer orient)
    box.add(Wx::Window window, integer proportion=0,
            integer flag=0, integer border=0)


Yeni boyutlandırıcı tanımlarken verilen orient parametresi yatay ya da dikey yerleşim için kullanılacağını belirtir. Buraya Wx::VERTICAL veya Wx::HORIZONTAL girilir. Boyutlandırıcıya bir kontrol eklemek için add metodunu kullanırız. Parametrelere bir bakalım.

proportion parametresi eklenen kontrolün boyutlandırıcının verilen yönünde nasıl yayılacağını ve boyutlandırıcı boyutu değişince nasıl davranacağını belirler. Değer 0 ise boyutunu değiştirmez, 1 ise diğer 1 olanlarla beraber orantılı yayılır, 2 ise diğerlerine oranla 2 katı yayılır. 

flag parametresi ise kontrolün boyutlandırıcı içindeki davranışını daha ileri seviyelerde ayarlarız. Kontroller arasında çizilecek sınırları belirleyebiliriz, kontroller arasında verilecek boşluk belirleyebiliriz. Bir liste dökümanda var. Sınır bilgisi border değerinin hangi kenarlara uygulanacağı da bu flag içinde belirtilir. Flag bitleri birbirine veya işareti | ile bağlanır (ki zaten tamsayı değerler veya ediliyor). Örneğin Wx::LEFT | Wx::BOTTOM ile solda ve altta border değerini uygulayacağımızı belirtiriz. 

  • Wx::LEFT
  • Wx::RIGHT
  • Wx::BOTTOM
  • Wx::TOP
  • Wx::ALL

Panele boyutlandırıcı eklerken set_sizer metodu kullanılır. 

border.rb

require "wx"

class Örnek < Wx::Frame
  def initialize(*args)
    super(*args)
    init_UI
  end
  def init_UI
    set_size [350, 300]
    set_title "Border"
    centre

    panel = Wx::Panel.new(self)
    panel.background_colour = "#4f5049"

    vbox = Wx::BoxSizer.new(Wx::VERTICAL)

    midPan = Wx::Panel.new(panel)
    midPan.background_colour = "#ededed"

    vbox.add midPan, Wx::ID_ANY, Wx::EXPAND | Wx::ALL, 20
    panel.set_sizer vbox
  end
end

Wx::App.run {
  Örnek.new(nil).show
}


Yukarıdaki kodda içteki paneli boyutlandırıcıya eklerken etrafında biraz boşluk bıraktık. 

    vbox.add midPan, Wx::ID_ANY, Wx::EXPAND | Wx::ALL, 20

midPan panelini (bu arada isimi keşke mid_pan yazsam daha Ruby olurdu), vbox boyutlandırıcısına eklerken 20 piksel sınır belirledik. Sınırın her tarafta olması da flag değerine girilen Wx::ALL biti tarafından belirtiliyor.

Eğer Wx::EXPAND bayrağını kullanırsak widget'imiz boyutlandırıcı içinde yayılabildiği kadar her yöne yayılır. Son olarak widget'imizin yaslanmasını da bayraklar ile belirleyebiliriz.

  • Wx::ALIGN_LEFT
  • Wx::ALIGN_RIGHT
  • Wx::ALIGN_TOP
  • Wx::ALIGN_BOTTOM
  • Wx::ALIGN_CENTER_VERTICAL
  • Wx::ALIGN_CENTER_HORIZONTAL
  • Wx::ALIGN_CENTER

Çalıştıralım




Sınıfına git örneği

Önümüzdeki örnekte farklı birçok yöntem göreceğiz. 

goto_class.rb

require "wx"

class Örnek < Wx::Frame
  def initialize(*args)
    super(*args)
    init_UI
  end
  def init_UI
    #set_size [350, 300]
    set_title "Sınıfına Git"
    centre

    panel = Wx::Panel.new(self)

    font = Wx::SystemSettings.get_font(Wx::SYS_SYSTEM_FONT)
    font.point_size = 9

    vbox = Wx::BoxSizer.new(Wx::VERTICAL)

    hbox1 = Wx::BoxSizer.new(Wx::HORIZONTAL)
    st1 = Wx::StaticText.new(panel, label: 'Class Adı :')
    st1.font = font
    hbox1.add st1, 0, Wx::RIGHT, 8
    tc = Wx::TextCtrl.new(panel)
    hbox1.add tc, 1
    vbox.add hbox1, 0, Wx::EXPAND|Wx::LEFT|Wx::RIGHT|Wx::TOP, 10

    vbox.add -1, 10

    hbox2 = Wx::BoxSizer.new(Wx::HORIZONTAL)
    st2 = Wx::StaticText.new(panel, label: 'Eşleşen Sınıflar :')
    st2.set_font font
    hbox2.add st2
    vbox.add hbox2, 0, Wx::LEFT | Wx::TOP, 10

    vbox.add -1, 10

    hbox3 = Wx::BoxSizer.new(Wx::HORIZONTAL)
    tc2 = Wx::TextCtrl.new(panel, style: Wx::TE_MULTILINE)
    hbox3.add tc2, 1, Wx::EXPAND
    vbox.add hbox3, 1, Wx::LEFT|Wx::RIGHT|Wx::EXPAND, 10

    vbox.add -1, 25

    hbox4 = Wx::BoxSizer.new(Wx::HORIZONTAL)
    cb1 = Wx::CheckBox.new(panel, label: 'Büyük/Küçük Duyarlı')
    cb1.font = font
    hbox4.add cb1
    cb2 = Wx::CheckBox.new(panel, label: 'İçiçe Sınıflar')
    cb2.font = font
    hbox4.add cb2, 0, Wx::LEFT, 10
    cb3 = Wx::CheckBox.new(panel, label: 'Non-Project Sınıflar')
    cb3.font = font
    hbox4.add cb3, 0, Wx::LEFT, 10
    vbox.add hbox4, 0, Wx::LEFT, 10

    vbox.add -1, 25

    hbox5 = Wx::BoxSizer.new(Wx::HORIZONTAL)
    btn1 = Wx::Button.new(panel, label: 'Tamam', size: [70, 30])
    hbox5.add btn1
    btn2 = Wx::Button.new(panel, label: 'Kapat', size: [70, 30])
    hbox5.add btn2, 0, Wx::LEFT|Wx::BOTTOM, 5
    vbox.add hbox5, 0, Wx::ALIGN_RIGHT|Wx::RIGHT, 10

    panel.set_sizer vbox
  end
end

Wx::App.run {
  Örnek.new(nil).show
}


Gördüğünüz üzere yerleşimleri kombinasyon yaptık. Bir dikey boyutlandırıcı, 5 yatay boyutlandırıcı var.

    font = Wx::SystemSettings.get_font(Wx::SYS_SYSTEM_FONT)
    font.point_size = 9

Sistemden SYS_SYSTEM_FONT yazı tipini alıp boyutunu 9 olarak ayarlayıp kontrollerimizde kullanıyoruz. Wx::SystemFont dökümanında sistemden alınan font isimleri var. 

    vbox.add hbox1, 0, Wx::EXPAND|Wx::LEFT|Wx::RIGHT|Wx::TOP, 10

    vbox.add -1, 10

Boyutlandırıcı içine eleman eklerken kenarlarında istediğimiz boşlukları bayrak bitleri ve border argümanı ile ayarlayabiliyorduk. Yukarıdaki satırda hbox1 eklenirken solu, sağı ve üstünde 10 piksel boşluk veriliyor.

Bir diğer yöntem boyutlandırıcı nesnenin add metodu ile direk olarak eklenen elemanlar arasına boşluk eklemek. Burada vbox.add -1, 10 satırı genişliği -1 yüksekliği 10 piksel bir boşluk ekliyor, yani dikey olarak bir sonra eklenecek elemanla araya 10 piksel boşluk ekliyor. 

    vbox.add hbox5, 0, Wx::ALIGN_RIGHT|Wx::RIGHT, 10

Bu satır hbox5 içindeki iki butonu yerleşime eklerken sağa yaslayarak yerleştiriyor. Burada 3 konu önemli, orantı bilgisi (proportion), yaslanma biti ve Wx::EXPAND. Proportion sıfır olmalıdır ki butonlar pencereyle beraber büyümeye kalkmasın ne kadarsa o kadar kalsın. Wx::EXPAND kullanmamalıyız, butonlar yalnızca kendilerine ayrılan alanı kaplasın. Son olarak da Wx::ALIGN_RIGHT bayrağını da kullanmalıyız ki butonlar pencerenin sağ tarafına yerleştirilsin. 

Çalıştıralım.




Wx::GridSizer

Wx::GridSizer kontrolleri iki boyutlu tablo şeklinde yerleştirir. Tablodaki her hücre eşit boyutlardadır. 

Wx:GridSizer.new(rows, cols, vgap, hgap)
 

Üretici metodda satır sayısı, sütun sayısı, hücreler arası dikeydeki boşluk (satırlar arası) ve hücreler arası yataydaki boşluk değerlerini argüman olarak veriyoruz. 

Örneğimizde bir hesap makinesinin görselini hazırlıyoruz.

calculator.rb

require "wx"

class Örnek < Wx::Frame
  def initialize(*args)
    super(*args)
    init_UI
  end
  def init_UI
    set_size [350, 300]
    set_title "Hesap Makinesi"
    centre

    menubar = Wx::MenuBar.new
    file_menu = Wx::Menu.new
    menubar.append file_menu, '&File'
    set_menu_bar menubar

    vbox = Wx::BoxSizer.new(Wx::VERTICAL)
    display = Wx::TextCtrl.new(self, style: Wx::TE_RIGHT)
    vbox.add display, 0, Wx::EXPAND|Wx::TOP|Wx::BOTTOM, 4
    gs = Wx::GridSizer.new(5, 4, 5, 5)

    gs.add Wx::Button.new(self, label: 'Cls'), 0, Wx::EXPAND
    gs.add Wx::Button.new(self, label: 'Bck'), 0, Wx::EXPAND
    gs.add Wx::StaticText.new, 0, Wx::EXPAND
    gs.add Wx::Button.new(self, label: 'Close'), 0, Wx::EXPAND
    gs.add Wx::Button.new(self, label: '7'), 0, Wx::EXPAND
    gs.add Wx::Button.new(self, label: '8'), 0, Wx::EXPAND
    gs.add Wx::Button.new(self, label: '9'), 0, Wx::EXPAND
    gs.add Wx::Button.new(self, label: '/'), 0, Wx::EXPAND
    gs.add Wx::Button.new(self, label: '4'), 0, Wx::EXPAND
    gs.add Wx::Button.new(self, label: '5'), 0, Wx::EXPAND
    gs.add Wx::Button.new(self, label: '6'), 0, Wx::EXPAND
    gs.add Wx::Button.new(self, label: '*'), 0, Wx::EXPAND
    gs.add Wx::Button.new(self, label: '1'), 0, Wx::EXPAND
    gs.add Wx::Button.new(self, label: '2'), 0, Wx::EXPAND
    gs.add Wx::Button.new(self, label: '3'), 0, Wx::EXPAND
    gs.add Wx::Button.new(self, label: '-'), 0, Wx::EXPAND
    gs.add Wx::Button.new(self, label: '0'), 0, Wx::EXPAND
    gs.add Wx::Button.new(self, label: '.'), 0, Wx::EXPAND
    gs.add Wx::Button.new(self, label: '='), 0, Wx::EXPAND
    gs.add Wx::Button.new(self, label: '+'), 0, Wx::EXPAND

    vbox.add gs, 1, Wx::EXPAND

    set_sizer vbox
  end
end

Wx::App.run {
  Örnek.new(nil).show
}


Bck ve Close butonları arasındaki grid hücresini nasıl boş bıraktığımıza dikkat edin , sadece boş bir Wx::StaticText nesnesi koyduk. 

Kontroller grid boyutlandırıcıya eklendikleri sırayla görüntüde yerlerini alıyorlar. Soldan sağa, yukarıdan aşağı yönde ilerleniyor. Satır bittikçe alt satırın başına geçiliyor.

 




Wx::FlexGridSizer

Bu boyutlandırıcı Wx::GridSizer'a çok benzer. Bu da kontrolleri 2 boyutlu bir tabloda yerleştirir. Ama hücre boyutlarına biraz esneklik getirir. FlexGridSizer'da aynı satırdaki tüm hücreler aynı yüksekliktedir ve aynı sütundaki tüm hücreler de aynı genişliktedir. Ancak satırların yükseklikleri ve sütunların genişlikleri değişebilir. 

Wx::FlexGridSizer.new(rows, cols, vgap, hgap)


Yeni nesne üretme metodu aynı argümanları alıyor. 

Geliştiriciler sıklıkla verileri göstermek ve değiştirmek amaçlı diyalog pencereleri hazırlarlar. Wx::FlexGridSizer boyutlandırıcı bu diyalogların yerleşimini hazırlarken çok işe yarar.  

review.rb

require "wx"

class Örnek < Wx::Frame
  def initialize(*args)
    super(*args)
    init_UI
  end
  def init_UI
    set_size [350, 250]
    set_title "Eleştiri"
    centre

    panel = Wx::Panel.new self

    hbox = Wx::BoxSizer.new Wx::HORIZONTAL

    fgs = Wx::FlexGridSizer.new 3, 2, 9, 25

    başlık = Wx::StaticText.new panel, label: "Başlık :"
    yazar = Wx::StaticText.new panel, label: "Yazar :"
    eleştiri = Wx::StaticText.new panel, label: "Eleştiri :"

    tc1 = Wx::TextCtrl.new panel
    tc2 = Wx::TextCtrl.new panel
    tc3 = Wx::TextCtrl.new panel, style: Wx::TE_MULTILINE

    fgs.add başlık
    fgs.add tc1, 1, Wx::EXPAND
    fgs.add yazar
    fgs.add tc2, 1, Wx::EXPAND
    fgs.add eleştiri, 1, Wx::EXPAND
    fgs.add tc3, 1, Wx::EXPAND

    fgs.add_growable_row 2
    fgs.add_growable_col 1

    hbox.add fgs, 1, Wx::ALL|Wx::EXPAND, 15
    panel.set_sizer hbox
  end
end

Wx::App.run {
  Örnek.new(nil).show
}


Yukarıdaki örnekte eleştiri giriş diyaloğunu FlexGridSizer ile oluşturduk 

    hbox = Wx::BoxSizer.new Wx::HORIZONTAL
....
    hbox.add fgs, 1, Wx::ALL|Wx::EXPAND, 15

Yatay boyutlandırıcıdan kenarlara 15 piksel boşluk bırakıyoruz. 

    fgs = Wx::FlexGridSizer.new 3, 2, 9, 25

3 satır , 2 sütundan oluşuyor. Satırlar arasında 9 piksel , sütunlar arasında 25 piksel boşluk var. 

    fgs.add başlık
....
    fgs.add tc3, 1, Wx::EXPAND

Kontrolleri hücrelere aynı GridSizer gibi sırayla ekliyoruz. 

    fgs.add_growable_row 2
    fgs.add_growable_col 1

3. satır (index=2) ve ikinci sütunu genişleyebilir olarak belirtiyoruz. Bunları yapmazsak kontroller birbirine ayak uydurur ama boyutlandırıcı genişlemediği için pencereyle beraber büyümezler. Ayrıca büyümesini istediğimiz kontrolleri boyutlandırıcıya eklerken Wx::EXPAND bayrağını eklemeyi unutmayın. 




Wx::GridBagSizer

GridBagSizer Wx kütüphanesinin en esnek boyutlandırıcısı. 

Bu boyutlandırıcı elemanların ayrıca pozisyonlanmasına imkan tanır. Elemanlar bir'den fazla satır veya sütuna da yayılabilirler. 

    Wx::GridBagSizer.new  vgap, hgap

Nesne oluşturucusu çok basittir. Argümanlar satırlar arası dikey boşluk ve sütunlar arası yatay boşluk değeri. Kontrolleri boyutlandırıcıya add metodu ile ekleriz. 

add window, pos, span = Wx::DEFAULT_SPAN, flag = 0, border = 0, userData = nil

window boyutlandırıcıya eklenecek olan widget, pos satır-sütun olarak pozisyon değeri (Wx::GBPosition nesnesi), span kaç satır , kaç sütun işgal edeceği (Wx::GBSpan nesnesi), bayrafklar ve kenar boşluğu. 




İsim değiştir diyalog örneği

İlk örneğimizde isim değiştirmek için bir diyalog penceresi çizelim. Sadece bir Wx::StaticText, bir Wx::TextCtrl ve iki Wx::Button widget var. 

rename.rb

require "wx"

class Örnek < Wx::Frame
  def initialize(*args)
    super(*args)
    init_UI
  end
  def init_UI
    set_size [350, 150]
    set_title "İsim Değiştir"
    centre

    panel = Wx::Panel.new self
    sizer = Wx::GridBagSizer.new 4, 4

    text = Wx::StaticText.new panel, label: "Yeni isim :"
    sizer.add text, Wx::GBPosition.new(0, 0), Wx::DEFAULT_SPAN,
            Wx::TOP|Wx::LEFT|Wx::BOTTOM, 5

    tc = Wx::TextCtrl.new panel
    sizer.add tc, Wx::GBPosition.new(1, 0), Wx::GBSpan.new(1, 4),
            Wx::EXPAND|Wx::LEFT|Wx::RIGHT, 5

    button_ok = Wx::Button.new panel, label: "Tamam", size: [90, 28]
    button_close = Wx::Button.new panel, label: "Kapat", size: [90, 28]
    sizer.add button_ok, Wx::GBPosition.new(3, 2)
    sizer.add button_close, Wx::GBPosition.new(3, 3), Wx::DEFAULT_SPAN,
            Wx::RIGHT|Wx::BOTTOM, 10

    sizer.add_growable_col 1
    sizer.add_growable_row 2
    panel.set_sizer sizer
  end
end

Wx::App.run {
  Örnek.new(nil).show
}

Pencereye büyük bir grid tablosu olarak bakmalıyız.

    text = Wx::StaticText.new panel, label: "Yeni isim :"
    sizer.add text, Wx::GBPosition.new(0, 0), Wx::DEFAULT_SPAN,
            Wx::TOP|Wx::LEFT|Wx::BOTTOM, 5

"Yeni isim :" yazısı sol üst köşeye yerleştiriliyor, pozisyonu (0. 0). Solunda , üstünde ve altında da biraz boşluk bırakıyoruz.

    tc = Wx::TextCtrl.new panel
    sizer.add tc, Wx::GBPosition.new(1, 0), Wx::GBSpan.new(1, 4),
            Wx::EXPAND|Wx::LEFT|Wx::RIGHT, 5

Wx::TextCtrl nesnesi ikinci satırın ilk sütununa yerleştiriliyor (1, 0). Yayılma olarak 1 satır ve 4 sütuna yayılıyor (1, 4). Ve iki yanında 5 piksel boşluk bırakıyoruz.

    sizer.add button_ok, Wx::GBPosition.new(3, 2)
    sizer.add button_close, Wx::GBPosition.new(3, 3), Wx::DEFAULT_SPAN,
            Wx::RIGHT|Wx::BOTTOM, 10

Butonlarımızı 4. satıra yerleştiriyoruz. 3. satırı boş bırakıyoruz TextCtrl ve butonlar arasında mesafe kalsınistiyoruz. "Tamam" butonunu 3. sütuna (3, 2) ve "Kapat" butonunu da 4. sütuna (3, 3) yerleştiriyoruz. Sadece "Kapat" butonuna sınır boşluğu veriliyor ama altında olan boşluk diğer butona da etki edecektir. 

    sizer.add_growable_col 1
    sizer.add_growable_row 2

Son yapacağımız şey , yerleşimin boyut değişimlerine tepkisi. 2. sütun ve 3. satırı genişleyebilir yaptık. Bu iki satırı yoruma atın da ne olacağını görün. 



Yeni sınıf diyaloğu örneği

Şimdiki örneğimizde JDeveloper'da bulunan yeni Java sınıf tanımlama diyaloğunu taklit edeceğiz. 

require "wx"

class Örnek < Wx::Frame
  def initialize(*args)
    super(*args)
    init_UI
  end
  def init_UI
    set_size [350, 450]
    set_title "Create Java Class"
    centre

    panel = Wx::Panel.new self
    sizer = Wx::GridBagSizer.new 8, 5

    text1 = Wx::StaticText.new panel, label: "Java Class"
    sizer.add text1, Wx::GBPosition.new(0, 0), Wx::DEFAULT_SPAN,
          Wx::TOP|Wx::LEFT|Wx::BOTTOM, 15

    icon = Wx::StaticBitmap.new panel, label: Wx::Bitmap.new('exec.jpg')
    sizer.add icon, Wx::GBPosition.new(0, 4), Wx::DEFAULT_SPAN,
          Wx::TOP|Wx::RIGHT|Wx::ALIGN_RIGHT, 5

    line = Wx::StaticLine.new panel
    sizer.add line, Wx::GBPosition.new(1, 0), Wx::GBSpan.new(1, 5),
          Wx::EXPAND|Wx::BOTTOM, 10

    text2 = Wx::StaticText.new panel, label: "Name"
    sizer.add text2, Wx::GBPosition.new(2, 0), Wx::DEFAULT_SPAN,
          Wx::LEFT, 10

    tc1 = Wx::TextCtrl.new panel
    sizer.add tc1, Wx::GBPosition.new(2, 1), Wx::GBSpan.new(1, 3),
          Wx::TOP|Wx::EXPAND

    text3 = Wx::StaticText.new panel, label: "Package"
    sizer.add text3, Wx::GBPosition.new(3, 0), Wx::DEFAULT_SPAN,
          Wx::LEFT|Wx::TOP, 10

    tc2 = Wx::TextCtrl.new panel
    sizer.add tc2, Wx::GBPosition.new(3, 1), Wx::GBSpan.new(1, 3),
          Wx::TOP|Wx::EXPAND, 5

    button1 = Wx::Button.new panel, label: "Browse..."
    sizer.add button1, Wx::GBPosition.new(3, 4), Wx::DEFAULT_SPAN,
          Wx::TOP|Wx::RIGHT, 5

    text4 = Wx::StaticText.new panel, label: "Extends"
    sizer.add text4, Wx::GBPosition.new(4, 0), Wx::DEFAULT_SPAN,
          Wx::TOP|Wx::LEFT, 10

    combo = Wx::ComboBox.new panel
    sizer.add combo, Wx::GBPosition.new(4, 1), Wx::GBSpan.new(1, 3),
          Wx::TOP|Wx::EXPAND, 5

    button2 = Wx::Button.new panel, label: "Browse..."
    sizer.add button2, Wx::GBPosition.new(4, 4), Wx::DEFAULT_SPAN,
          Wx::TOP|Wx::RIGHT, 5

    sb = Wx::StaticBox.new panel, label: "Optional Attributes"

    boxsizer = Wx::StaticBoxSizer.new sb, Wx::VERTICAL
    boxsizer.add Wx::CheckBox.new(panel, label: "Public"), 0,
          Wx::LEFT|Wx::TOP, 5
    boxsizer.add Wx::CheckBox.new(panel, label: "Generate Default Constructor"), 0,
          Wx::LEFT, 5
    boxsizer.add Wx::CheckBox.new(panel, label: "Generate Main Method"), 0,
          Wx::LEFT|Wx::BOTTOM, 5
    sizer.add boxsizer, Wx::GBPosition.new(5, 0), Wx::GBSpan.new(1, 5),
          Wx::EXPAND|Wx::TOP|Wx::LEFT|Wx::RIGHT , 10

    button3 = Wx::Button.new panel, label: 'Help'
    sizer.add button3, Wx::GBPosition.new(7, 0), Wx::DEFAULT_SPAN,
          Wx::LEFT, 10

    button4 = Wx::Button.new panel, label: "Ok"
    sizer.add button4, Wx::GBPosition.new(7, 3)

    button5 = Wx::Button.new panel, label: "Cancel"
    sizer.add button5, Wx::GBPosition.new(7, 4), Wx::GBSpan.new(1, 1),
          Wx::BOTTOM|Wx::RIGHT, 10

    sizer.add_growable_col 2
    sizer.add_growable_row 6

    panel.set_sizer sizer
    sizer.fit self
  end
end

Wx::App.run {
  Örnek.new(nil).show
}


Bu daha karmaşık bir yerleşim , hem GridBoxSizer hem de StaticBoxSizer kullanıyoruz. 

    line = Wx::StaticLine.new panel
    sizer.add line, Wx::GBPosition.new(1, 0), Wx::GBSpan.new(1, 5),
          Wx::EXPAND|Wx::BOTTOM, 10

Bu yerleşimde iki grup elemanı birbirinden ayıran çizgi. 2. satıra yatay olarak tüm satırı kaplayacak şekilde yerleştiriyoruz. 

    icon = Wx::StaticBitmap.new panel, label: Wx::Bitmap.new('exec.jpg')
    sizer.add icon, Wx::GBPosition.new(0, 4), Wx::DEFAULT_SPAN,
          Wx::TOP|Wx::RIGHT|Wx::ALIGN_RIGHT, 5

İlk satıra sağa yanaşmış olarak bir resimi StaticBitmap nesnesi olarak ekliyoruz.

    sb = Wx::StaticBox.new panel, label: "Optional Attributes"

    boxsizer = Wx::StaticBoxSizer.new sb, Wx::VERTICAL

StaticBox üzerinde bir etiket yazısı olan panel gibi düşünülebilir. Burada bir şey dikkatimi çekti , sb içine boxsizer'ı ekliyoruz ama daha sonra yerleşime kapsayıcı olan sb'yi değil bozsizer'ı ekliyoruz. Biraz araştırdım, aslında birinci satıra gerek olamadan sadece

boxsizer = Wx::StaticBoxSizer.new Wx::VERTICAL, panel, "Optional Attributes"

şeklinde yazarak boxsizer nesnesine zaten başlık ekleyebiliyoruz. Bu daha mantıklı ve kısa.


Çalıştı ama şu GridBagSizer#add metodunun argümanlarında bulunan Wx::GBPosition ve Wx::GBSpan nesnesi üretmelerine gıcık oldum, her seferinde bunları yazmak çok gıcık, araştırdım bir kısaltmasını da bulamadım. Oturdum kendime bir yardımcı kod dosyası hazırladı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

Bu kodu programlarıma dahil edersem pos ve span değerlerini array içinde verebiliriz. Kodumu bu yardımcı dosyamı kullanacak şekilde değiştirince birazcık sadeleşti.

require "wx"
require "./my_wx_helper"

class Örnek < Wx::Frame
  def initialize(*args)
    super(*args)
    init_UI
  end
  def init_UI
    set_size [350, 450]
    set_title "Create Java Class"
    centre

    panel = Wx::Panel.new self
    sizer = Wx::GridBagSizer.new 8, 5

    text1 = Wx::StaticText.new panel, label: "Java Class"
    sizer.add text1, [0, 0], [1, 1],
          Wx::TOP|Wx::LEFT|Wx::BOTTOM, 15

    icon = Wx::StaticBitmap.new panel, label: Wx::Bitmap.new('exec.jpg')
    sizer.add icon, [0, 4], [1, 1],
          Wx::TOP|Wx::RIGHT|Wx::ALIGN_RIGHT, 5

    line = Wx::StaticLine.new panel
    sizer.add line, [1, 0], [1, 5], Wx::EXPAND|Wx::BOTTOM, 10

    text2 = Wx::StaticText.new panel, label: "Name"
    sizer.add text2, [2, 0], [1, 1], Wx::LEFT, 10

    tc1 = Wx::TextCtrl.new panel
    sizer.add tc1, [2, 1], [1, 3], Wx::TOP|Wx::EXPAND

    text3 = Wx::StaticText.new panel, label: "Package"
    sizer.add text3, [3, 0], [1, 1], Wx::LEFT|Wx::TOP, 10

    tc2 = Wx::TextCtrl.new panel
    sizer.add tc2, [3, 1], [1, 3], Wx::TOP|Wx::EXPAND, 5

    button1 = Wx::Button.new panel, label: "Browse..."
    sizer.add button1, [3, 4], [1, 1], Wx::TOP|Wx::RIGHT, 5

    text4 = Wx::StaticText.new panel, label: "Extends"
    sizer.add text4, [4, 0], [1, 1], Wx::TOP|Wx::LEFT, 10

    combo = Wx::ComboBox.new panel
    sizer.add combo, [4, 1], [1, 3], Wx::TOP|Wx::EXPAND, 5

    button2 = Wx::Button.new panel, label: "Browse..."
    sizer.add button2, [4, 4], [1, 1], Wx::TOP|Wx::RIGHT, 5

    boxsizer = Wx::StaticBoxSizer.new Wx::VERTICAL, panel, "Optional Attributes"
    boxsizer.add Wx::CheckBox.new(panel, label: "Public"), 0,
          Wx::LEFT|Wx::TOP, 5
    boxsizer.add Wx::CheckBox.new(panel, label: "Generate Default Constructor"), 0,
          Wx::LEFT, 5
    boxsizer.add Wx::CheckBox.new(panel, label: "Generate Main Method"), 0,
          Wx::LEFT|Wx::BOTTOM, 5
    sizer.add boxsizer, [5, 0], [1, 5],
          Wx::EXPAND|Wx::TOP|Wx::LEFT|Wx::RIGHT , 10

    button3 = Wx::Button.new panel, label: 'Help'
    sizer.add button3, [7, 0], [1, 1], Wx::LEFT, 10

    button4 = Wx::Button.new panel, label: "Ok"
    sizer.add button4, [7, 3]

    button5 = Wx::Button.new panel, label: "Cancel"
    sizer.add button5, [7, 4], [1, 1], Wx::BOTTOM|Wx::RIGHT, 10

    sizer.add_growable_col 2
    sizer.add_growable_row 6

    panel.set_sizer sizer
    sizer.fit self
  end
end

Wx::App.run {
  Örnek.new(nil).show
}


Yerleşimler üzerine yazacaklarım bu kadar, sonraki sayfada olay işlemelere gireceğiz inşallah.

Şimdilik kalın sağlıcakla..






Hiç yorum yok:

Yorum Gönder