8 Mart 2025 Cumartesi

WxRuby3 ile Masaüstü Uygulama Geliştirmek 2

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

 Selam WxRuby3 GUI kütüphanesi denemelerimize olay işleme teknikleri ile devam ediyoruz. 


WxRuby'de Olaylar

Olaylar her GUI uygulamanın vazgeçilmez parçasıdır. Tüm GUI uygulamaları olay yönelimlidir. Bir uygulama çalıştığı müddetçe değişik olaylara tepki gösterir. Bir uygulamada olaylar genellikle kullanıcı tarafından oluşturulur. Ama başka şeyler de olay üretebilir, mesela internet bağlantısı, pencere yöneticisi veya zamanlama ile üretilen olaylar. Uygulamamızda run metodunu çalıştırdığımızda, uygulamamız olayların oluşmasını beklemeye başlar. 


Tanımlar

Olay (Event) genelde GUI Toolkit tarafından sağlanan uygulama seviyesi bilgilerin bir parçasıdır. Olay döngüsü (Event loop) bir programdaki olayları veya mesajları bekleyen ve gönderen bir programlama yapısıdır. Olay döngüsü sürekli olarak işlenecek bir olay olmasını bekler. Dağıtıcı (dispatcher) olayları olay işleyicilerine eşleyen bir işlemdir. Olay işleyiciler (event handler) oluşan olaylara tepki gösteren metodlardır. 

Olay nesnesi (event object) olayın gerçekleştiği nesnedir. Genellikle bir widget olur. Olay tipi (event type) ise gerçekleşen olayın kendisidir. Olay bağlayıcı (event binder) olay tipini olay işleyiciye bağlayan nesnedir. 



evt_move örneği

Bu örneğimizde Wx::MoveEvent olayına tepki veren bir uygulama yapacağız. Bu olay pencereyi başka bir pozisyona hareket ettirdiğimizde oluşur. Bu olay için bağlayıcı Wx::EVT_MOVE'dur.

simple_event.rb

require "wx"

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

    panel = Wx::Panel.new self
    Wx::StaticText.new panel, label: 'x:', pos: [10,10]
    Wx::StaticText.new panel, label: 'y:', pos: [10,30]

    @st1 = Wx::StaticText.new panel, label: '', pos: [30, 10]
    @st2 = Wx::StaticText.new panel, label: '', pos: [30, 30]

    evt_move :on_move
  end

  def on_move(e)
    x, y = e.get_position
    @st1.set_label x.to_s
    @st2.set_label y.to_s
  end
end

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


Örneğimiz pencerenin ekrandaki pozisyonunu gösteriyor, yani penceremizin sol-üst köşesinin ekranımızın sol-üst köşesine göre koordinatları. 

    evt_move :on_move

EventHandler sınıfından gelen evt_move metodu bir olay bağlayıcısı Wx::EVT_MOVE olayını kullanıcının tanımlayacağı on_move metoduna bağlar. evt_move metoduna istersek bir kod bloğunu argüman olarak vererek olay işlemesini orada da yapabiliriz.

    evt_move { |e|
      x, y = e.get_position
      @st1.set_label x.to_s
      @st2.set_label y.to_s
    }

gibi.

  def on_move(e)
    x, y = e.get_position
    @st1.set_label x.to_s
    @st2.set_label y.to_s
  end

on_move metoduna parametre olarak gelen e nesnesi gerçekleşen olayı ifade eden nesnedir. Örneğimize bakarsak Wx::MoveEvent nesnesi. Şu andaki pozisyonu olay nesnesinin get_position metodu ile okuruz. 


WxRuby olayları bağlamak

Bir olayı işlemenin 3 adımı vardır.

  • Olay tipini belirlemek. Dokümandan yararlanabiliriz.
  • Bir olay işleyici blok ya da metod hazırlamak
  • Bu bloğu ya da metodu EventHandler metodlarını kullanarak olaya bağlamak

Yukarıdaki örnekteki olayımız Wx::EVT_MOVE olayı ve bağlayıcı metodunun dökümanda tanımı şöyle:

  evt_move(meth = nil) {|event| ... } ⇒ Object

Bu yapı bize iki olasılık veriyor, ya bir metod ismi vererek olay gerçekleşince o metodun çağrılmasını sağlıyoruz, ya da bir kod bloğu içinde direk olarak hemen orada olayı değerlendiriyoruz. Metod ismi verirken sembol veya string değer kullanabiliriz. Böyle sabit yazı değerler için genelde sembol kullanılır, çünkü hafıza kullanımı daha az. Metod ya da bloğa geçen argüman ise Wx::MoveEvent olay nesnesinin kendisi, yani gerçekleşen olay bilgisi.




Olayı veto etmek

Bazen uygulamamızın bir olaya tepki vermesini engellemek isteriz, bu amaçla veto metodu kullanılır. 

event_veto.rb

require "wx"

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

    evt_close :on_close_window
  end

  def on_close_window(e)
    dial = Wx::MessageDialog.new nil, 'Çıkmak istediğinize emin misiniz?',
      'Lütfen Cevaplayın', Wx::YES_NO | Wx::NO_DEFAULT | Wx::ICON_QUESTION

    ret = dial.show_modal

    if ret == Wx::ID_YES
      destroy
    else
      e.veto
    end
  end
end

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


Örneğimizde Wx::CloseEvent olayını işliyoruz. Bu olay kullanıcı pencerenin çarpı butonuna tıklayıp kapatmaya kalkınca ya da Alt+F4 basınca ya da menüden çıkış seçeneği seçilince oluşur. Çoğu uygulamada kaydedilmemiş verilerin kaybedilmemesi için kapatma işlemi engellenerek mesaj gösterilir. 

    evt_close :on_close_window

CloseEvent olayını on_close_window metoduna bağlıyoruz. 

    dial = Wx::MessageDialog.new nil, 'Çıkmak istediğinize emin misiniz?',
      'Lütfen Cevaplayın', Wx::YES_NO | Wx::NO_DEFAULT | Wx::ICON_QUESTION

    ret = dial.show_modal

Kapatma olayını işlerken kullanıcıya bir diyalog mesajı gösteriyoruz. 

    if ret == Wx::ID_YES
      destroy
    else
      e.veto
    end

Diyalogda Evet butonuna tıklandıysa destroy metodu ile bulunulan Frame kapatılıyor. Burada destroy çağırmak zorundayız, eğer close metodunu kullanırsak olayı tekrar tetikler sonsuz döngüye gireriz. 



WxRuby olay yayılımı

2 tür olay vardır, temel olaylar ve komut olaylar. Bunların yayılımı farklı olur. Olay yayılımı elemandan ebeveynine , oradan da dedesine doğru olur. Temel olaylar yayılmazken, komut olaylar yayılır. Örneğin Wx::CloseEvent bir temel olay. Bir elemanda bu olay oluşursa ebeveyn elemanına yayılmaz. 

Default olarak olay işleyicisi tarafından işlenen bir olay yayılımını durdurur. Yayılıma devam etmek için skip metodu kullanılmalıdır. 

event_propagation.rb

require "wx"

class MyPanel < Wx::Panel
  def initialize(*args)
    super(*args)
    evt_left_down :on_button_clicked
  end

  def on_button_clicked(e)
    p 'olay panel sınıfına ulaştı'
    e.resume_propagation 1
    e.skip
  end
end

class MyButton < Wx::Button
  def initialize(*args)
    super(*args)
    evt_left_down :on_button_clicked
  end

  def on_button_clicked(e)
    p 'olay button sınıfına ulaştı'
    e.resume_propagation 1
    e.skip
  end
end

class Örnek < Wx::Frame
  def initialize(*args)
    super(*args)
    init_UI
  end
  def init_UI
    set_size [350, 250]
    set_title "Olay Yayılımı"
    centre

    mpnl = MyPanel.new self

    MyButton.new mpnl, label: 'Ok', pos: [15, 15]

    evt_left_down :on_button_clicked
  end

  def on_button_clicked(e)
    p 'olay frame sınıfına ulaştı'
    e.resume_propagation 1
    e.skip
  end
end

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

Öncelikle evt_left_down olay bağlayıcısını kullanıyoruz, çünkü hem panel hem frame hem de button bu olaya tepki verir. Ancak bu olay normalde yukarı doğru yayılmaz, bu yüzden her kontrolün olay işleyicisine e.resume_propagation 1 satırını ekledik ki bir yukarıya olay yayılabilir olsun. 

skip metodu ise olayın yayılmaya devam etmesini sağlıyor, o olmasa ilk önce button olayı işler ve yukarı yayılma dururdu çünkü olaya tepki verildi. Şimdi çalıştırıp butona tıklarsak hangi sırada olayın yayıldığını konsolda görebiliriz. 




Window ID'leri

WxWidgets kütüphanesinde görsel elemanlar (pencere, buton, yazı kutusu vs) genelde Wx::Window sınıfının alt sınıfları olduğu için window olarak da adlandırılıyor. Bu window'lara ait ID değerleri elemana ait olayların işlenmesinde kullanılır. Bir eleman ID'sini belirlemenin üç yolu vardır. 

  • Sistemin otomatik ID vermesi için bırakmak
  • Standart ID değerlerinden kullanmak
  • Kendi ID numaramızı vermek

    Wx::Button.new parent, -1
    Wx::Button.new parent, Wx::ID_ANY

ID değeri olarak -1 ya da Wx::ID_ANY vermek ID değerini WxRuby sistemine bırakmak demek oluyor. WxRuby kendi kafasına göre bunlara ayrı ayrı ID sayıları uyduracaktır. Otomatik verilen ID değerleri her zaman negatif olur, yani biz kendimiz ID veriyorsak mutlaka pozitif sayı vermeliyiz ki otomatiklerden birine kazara denk gelmesin. 

Genelde otomatik ID yöntemini program içinde pek değiştirmeyeceğimiz elemanlar için kullanırız, mesela StaticText nesneleri pencerede sabit bir şeyler yazmak için kullanılır. Ama otomatik de verilmiş olsa hala elemanın ID değerini get_id metodunu çağırarak öğrenebiliriz.

    p Wx::Button.new(parent, Wx::ID_ANY).get_id


default_ids.rb

require "wx"

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

    pnl = Wx::Panel.new self

    exit_button = Wx::Button.new pnl, Wx::ID_ANY, 'Exit', [10, 10]

    evt_button(exit_button.get_id) { close }

  end
end

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

Bu örnekte exit_button nesnesinin ID değerini bilmemize gerek yok, evt_button metoduna nesneyi tanıtırken get_id metodu ile ID değerini verebiliriz.

    evt_button(exit_button.get_id) { close }

Aslında WxRuby diğer Wx uyarlamalarından biraz daha avantajlı evt_button metoduna ille de ID vermek zorunda değiliz direk nesneyi de verebiliriz. 

    evt_button(exit_button) { close }

Bu satır da sağlıklı çalışır. 



WxRuby standart ID'ler

Standart ID'ler değişik platformlarda görsel ya da davranışsal avantajlar sağladığı için tercih edilmesi önerilir. 

Kayıtlı bazı standart ID'ler vardır, örneğin Wx::ID_SAVE veya Wx::ID_NEW

standart_ids.rb

require "wx"

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

    pnl = Wx::Panel.new self
    grid = Wx::GridSizer.new 3, 2, 0, 0

    grid.add Wx::Button.new(pnl, Wx::ID_CANCEL), 0, Wx::TOP | Wx::LEFT, 9
    grid.add Wx::Button.new(pnl, Wx::ID_DELETE), 0, Wx::TOP, 9
    grid.add Wx::Button.new(pnl, Wx::ID_SAVE), 0, Wx::LEFT, 9
    grid.add Wx::Button.new(pnl, Wx::ID_EXIT)
    grid.add Wx::Button.new(pnl, Wx::ID_STOP), 0, Wx::LEFT, 9
    grid.add Wx::Button.new(pnl, Wx::ID_NEW)

    evt_button(Wx::ID_EXIT) { close }

    pnl.set_sizer grid
  end
end

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

Örneğimizde standart ID kullanan butonlar var, bu butonlar etiketlerinde ne yazılacağını bildirmediğimiz halde sistemden etiketlerini otomatik alırlar, Linux sistemlerde butonların ikonları da olur. Bunların bir listesi WxWidgets dokümanında mevcut.

    evt_button(Wx::ID_EXIT) { close }

Wx::ID_EXIT ID değerine sahip butona tıklanınca uygulamanın kapatılmasını istiyoruz. Bu üzerinde Quit yazan buton. 




Kendi ID değerlerimiz

Son seçeneğimiz kendi verdiğimiz ID değerleri ile çalışmak. Kendi global ID değerlerimizi tanımlıyoruz.

custom_ids.rb

require "wx"

ID_MENU_NEW = Wx::Window.new_control_id
ID_MENU_OPEN = Wx::Window.new_control_id
ID_MENU_SAVE = Wx::Window.new_control_id

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

    create_menu_bar
    create_status_bar
  end
  def create_menu_bar
    mb = Wx::MenuBar.new

    f_menu = Wx::Menu.new
    f_menu.append ID_MENU_NEW, "Yeni"
    f_menu.append ID_MENU_OPEN, "Aç"
    f_menu.append ID_MENU_SAVE, "Kaydet"

    mb.append f_menu, "&Dosya"
    set_menu_bar mb

    evt_menu ID_MENU_NEW, :mesaj_göster    
    evt_menu ID_MENU_OPEN, :mesaj_göster    
    evt_menu ID_MENU_SAVE, :mesaj_göster    
  end
  def mesaj_göster(e)
    sb = get_status_bar

    eid = e.get_id

    if eid == ID_MENU_NEW
      msg = "Menü elemanı 'Yeni' seçildi"
    elsif eid == ID_MENU_OPEN
      msg = "Menü elemanı 'Aç' seçildi"
    elsif eid == ID_MENU_SAVE
      msg = "Menü elemanı 'Kaydet' seçildi"
    end

    sb.set_status_text msg
  end
end

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

Örnekte 3 elemanlı bir menü tasarlıyoruz ve menü elemanlarının ID'lerini kendimiz ürettik .

ID_MENU_NEW = Wx::Window.new_control_id
ID_MENU_OPEN = Wx::Window.new_control_id
ID_MENU_SAVE = Wx::Window.new_control_id

new_control_id metodu yeni bir benzersiz ID numarası üretir. 

    evt_menu ID_MENU_NEW, :mesaj_göster    
    evt_menu ID_MENU_OPEN, :mesaj_göster    
    evt_menu ID_MENU_SAVE, :mesaj_göster  

3 menü elemanını ID değerleri ile aynı olay işleyiciye ( mesaj_göster ) yönlendiriyoruz. 

    eid = e.get_id

    if eid == ID_MENU_NEW
      msg = "Menü elemanı 'Yeni' seçildi"
    elsif eid == ID_MENU_OPEN
      msg = "Menü elemanı 'Aç' seçildi"
    elsif eid == ID_MENU_SAVE
      msg = "Menü elemanı 'Kaydet' seçildi"
    end

Olay nesnesinden olayın gerçekleştiği menü elemanının ID değerini get_id metodu ile çekiyor ve hangi menünün tıklandığını anlıyoruz. Buna göre de durum çubuğuna bir mesaj yazdırıyoruz.



Wx::PaintEvent

Paint olayı bir window tekrar çizildiğinde oluşur. Pencere boyutu değiştirdiğimizde ya da maximize ettiğimizde paint olayı oluşur. Paint olayını kodla da oluşturabiliriz. Örneğin bir Wx::StaticText nesnesinde set_label metodunu çağırarak. Not pencereyi minimize ettiğimizde paint olayı oluşmaz (çünkü pencere küçülmez ekrandan yok olur).

paint_event.rb

require "wx"

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

    @count = 0
    evt_paint :on_paint
  end
  def on_paint(e)
    paint do |dc|
      @count += 1
      text = "Paint olayları sayısı: #{@count}"
      dc.draw_text text, 20, 20
      p text
    end
  end
end

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

Örneğimizde penceremiz için oluşan paint olaylarını sayıyoruz. Konsola olay oluştuğu anda yazı yazılırken pencere üzerine yazılan yazının ancak pencereyi minimize ve restore edince yazıldığını görüyoruz. Çünkü Windows sistemi ancak o zaman son hali çiziyor. Başka işletim sistemlerinde nasıl olacağını denemek lazım. Bir nokta da paint olayı pencere boyutunu büyütünce oluşuyor ama küçültürken oluşmuyor.

    evt_paint :on_paint

Penceremizin paint olayını on_paint metoduna bağlıyoruz. 

  def on_paint(e)
    paint do |dc|
      @count += 1
      text = "Paint olayları sayısı: #{@count}"
      dc.draw_text text, 20, 20
      p text
    end
  end

Burada paint do |dc| bloğu bir kalıp. Pencerede geçici bir DC çizim nesnesi tanımlayıp bunda çizim yaparak pencerede görünmesini sağlıyor. WxWidgets kullanan başka programlama dillerinde bu işlem daha farklı yapılıyor.




Wx::FocusEvent

Fokus uygulalamızda odaklanılan nesneyi gösterir. Klavyeden değer girilen eleman veya clipboard'dan yapıştırma yapılan eleman fokus olunan elemandır. Fokus ile ilişkili iki olay vardır. Wx::EVT_SET_FOCUS olayı elemana fokuslanıldığında oluşur. Wx::EVT_KILL_FOCUS olayı eleman fokus kaybettiğinde oluşur. Fokus ya mouse tıklamasıyla ya da tuş girişleri ile değişir (genellikle Tab veya Shift+Tab).

focus_event.rb

require "wx"

class MyWindow < Wx::Panel
  def initialize(parent)
    super(parent)

    @color = '#b3b3b3'

    evt_paint :on_paint
    evt_size :on_size
    evt_set_focus :on_set_focus
    evt_kill_focus :on_kill_focus
  end

  def on_paint(e)
    paint do |dc|
      dc.set_pen Wx::Pen.new(@color, 5)
      x, y = get_size
      dc.draw_rectangle 0, 0, x, y
    end
  end

  def on_size(e)
    refresh
  end

  def on_set_focus(e)
    @color = '#ff0000'
    refresh
  end

  def on_kill_focus(e)
    @color = '#b3b3b3'
    refresh
  end
end

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

    grid = Wx::GridSizer.new 2, 2, 10, 10
    grid.add MyWindow.new(self), 0, Wx::EXPAND|Wx::TOP|Wx::LEFT, 9
    grid.add MyWindow.new(self), 0, Wx::EXPAND|Wx::TOP|Wx::RIGHT, 9
    grid.add MyWindow.new(self), 0, Wx::EXPAND|Wx::BOTTOM|Wx::LEFT, 9
    grid.add MyWindow.new(self), 0, Wx::EXPAND|Wx::BOTTOM|Wx::RIGHT, 9

    set_sizer grid
  end
end

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

Örneğimizde 4 tane panel var fokus alan panelin etrafı kırmızı çiziliyor. 

    evt_set_focus :on_set_focus
    evt_kill_focus :on_kill_focus

Fokus olaylarını metodlara bağlıyoruz. 

  def on_paint(e)
    paint do |dc|
      dc.set_pen Wx::Pen.new(@color, 5)
      x, y = get_size
      dc.draw_rectangle 0, 0, x, y
    end
  end

Paint olayı gerçekleştiğinde panel için en son @color rengiyle 5 piksel genişlikte çizgiyle bir çerçeve çiziliyor. Yani paint olayında her panelin etrafına çerçeve çiziliyor, sadece rengini değiştirerek fokuslu olanı belirtiyoruz.

  def on_set_focus(e)
    @color = '#ff0000'
    refresh
  end

Fokus alan panelin @color değeri kırmızı renge karşı gelen '#ff0000' yapılıyor ve refresh metodu çağrılarak pencere görünümü yenileniyor, bu durum da paint olayını otomatik olarak tetikler.

  def on_kill_focus(e)
    @color = '#b3b3b3'
    refresh
  end

Bir panel fokus kaybedince onun @color değeri panelin arkaplan rengi olan '#b3b3b3' değeri yapılıyor ve refresh  metodu çağrılarak çerçevenin yeniden çizilmesi sağlanıyor. Böylece sanki çerçeve yokmuş gibi görünüyor. Pencerede paneller arasında bir yere tıklarsak tüm panellerde çerçeve yok olacaktır.




Wx::KeyEvent

Klavyemizden bir tuşa bastığımızda Wx::KeyEvent olayı oluşur. Bu olay o anda fokuslanılmış olan widget'a gönderilir. 3 değişik tuş olayı vardır 

  • Wx::EVT_KEY_DOWN
  • Wx::EVT_KEY_UP
  • Wx::EVT_CHAR
  • En yaygın kullanımlardan biri Esc tuşu basılınca pencereyi kapatmaktır.

    key_event.rb

    require "wx"

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

        evt_key_down :on_key_down
      end
      def on_key_down(e)
        key = e.get_key_code

        if key == Wx::K_ESCAPE
          ret = Wx::MessageDialog.new(self, "Cikmak istediginize emin misiniz?",
              "Soru", Wx::YES_NO | Wx::NO_DEFAULT).show_modal

          if ret == Wx::ID_YES
            close
          end
        end
      end
    end

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


    Burada yapılan işi yapan metod

      def on_key_down(e)
        key = e.get_key_code

        if key == Wx::K_ESCAPE
          ret = Wx::MessageDialog.new(self, "Cikmak istediginize emin misiniz?",
              "Soru", Wx::YES_NO | Wx::NO_DEFAULT).show_modal

          if ret == Wx::ID_YES
            close
          end
        end
      end

    get_key_code metodu ile basılan tuşun kodu alınıyor, bu kod Wx::K_ESCAPE tuşu mu bakılıyor. Tuşların listesi dokümanda mevcut. 

    Bu klavye olaylarında can sıkıcı bir şey, pencereye bir Wx::Panel nesnesi eklersek (ki bu yerleşim için lazım oluyor)), bu olaylar engelleniyor, panel tuşları sömürüyor. Bunun üstünden gelmek için evt_char_hook metodu ile tuş basılmasını işleyebiliriz.

      def init_UI
        set_size [350, 250]
        set_title "KeyEvent Olayı"
        centre

        pnl = Wx::Panel.new self

        evt_char_hook :on_key_down
      end





    WxRuby Diyaloglar

    Diyalog pencereleri modern bir GUI uygulamasının vazgeçilmez parçalarıdır. Bir diyalog bir'den fazla kişi arasında iletişim kurmak için yapılır. Bilgisayar uygulamasında ise diyalog uygulama ile iletişim kurmak için kullanılır. Diyalog veri girmek için, veriyi değiştirmek için, uygulama ayarlarını değiştirmek için vs. kullanılır. Diyaloglar uygulama ve kullanıcı arasında iletişim kurmak için önemlidir. 

    Mesaj kutuları, yazı fontu ya da renk seçme diyalogları gibi hazır diyalogları kullanacağımız gibi kendi diyaloglarımızı da tanımlayabiliriz. 



    Basit mesaj kutusu

    Mesaj kutusu ile kullanıcıya küçük bir bilgi verilir. Mesela CD'ye yazarken işlem bitince bir bilgilendirme diyalog penceresi otomatik olarak açılır. 

    message_box.rb

    require "wx"

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

        timer = Wx::Timer.new self
        timer.start_once 3000
        evt_timer(timer, :mesaj_göster)
     end
      def mesaj_göster
        Wx.message_box'İndirme Tamamlandı', 'Bilgi',
                Wx::OK | Wx::ICON_INFORMATION
      end
    end

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

    Uygulamamız 3 saniye sonra bir mesaj penceresi açıyor.

      def mesaj_göster
        Wx.message_box'İndirme Tamamlandı', 'Bilgi',
                Wx::OK | Wx::ICON_INFORMATION
      end

    Wx sınıfı message_box metodu bize bir mesaj kutusu açıyor. İlk argüman gösterilecek mesaj, ikinci ise diyalog penceresi etiketi. Sonra bayraklar geliyor, Wx::OK, Wx::YES, Wx::NO, Wx::CANCEL eklenebilen buton flagları, Wx::ICON_WARNING, Wx::ICON_ERROR,  Wx::ICON_INFORMATION ise ikon tipleri.


    Ön tanımlı diyaloglar

    Ön tanımlı diyaloglar yazı gösterme, girdi alma, dosya yükleme ve kaydetme gibi amaçlar için hazırlanmış diyaloglardır. 


    Wx::MessageDialog

    Mesaj diyalogları kullanıcıya mesaj göstermek için kullanılır. Yukarıdaki basit mesaj kutusundan daha esnektir. Diyalogda kullanılan butonları ya da ikonları değiştirebiliriz. 

    BayrakAnlamı
    Wx::OK OK-tamam butonunu göster
    Wx::CANCEL CANCEL- iptal butonunu göster
    Wx::YES_NO Yes,No - Evet,Haıyr butonunlarını göster
    Wx::YES_DEFAULT Evet butonu default
    Wx::NO_DEFAULT Hayır butonu default
    Wx::ICON_EXCLAMATION Alarm ikonu göster
    Wx::ICON_ERROR Hata ikonu göster
    Wx::ICON_HAND Hata ikonu göster
    Wx::ICON_INFORMATION Info ikonu göster
    Wx::ICON_QUESTION Soru ikonu göster


    Bu bayraklar Wx::MessageDialog sınıfı ile kullanılır. 

    message_dialogs.rb

    require "wx"

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

        panel = Wx::Panel.new self

        hbox = Wx::BoxSizer.new Wx::VERTICAL
        sizer = Wx::GridSizer.new 2, 2, 2, 2

        btn1 = Wx::Button.new panel, label: "Bilgi"
        btn2 = Wx::Button.new panel, label: "Hata"
        btn3 = Wx::Button.new panel, label: "Soru"
        btn4 = Wx::Button.new panel, label: "Alarm"

        sizer.add btn1; sizer.add btn2; sizer.add btn3; sizer.add btn4

        hbox.add sizer, 0, Wx::ALL, 15
        panel.set_sizer hbox

        evt_button btn1, :mesaj_göster_1
        evt_button btn2, :mesaj_göster_2
        evt_button btn3, :mesaj_göster_3
        evt_button btn4, :mesaj_göster_4
      end
      def mesaj_göster_1(e)
        dial = Wx::MessageDialog.new nil, 'İndirme Tamamlandı', 'Bilgilendirme', Wx::OK
        dial.show_modal
      end
      def mesaj_göster_2(e)
        dial = Wx::MessageDialog.new nil, 'İndirme Hatası', 'Hata!',
            Wx::OK | Wx::ICON_ERROR
        dial.show_modal
      end
      def mesaj_göster_3(e)
        dial = Wx::MessageDialog.new nil, 'Çıkmak istediğinize emin misiniz?',
            'Soru', Wx::YES_NO | Wx::NO_DEFAULT | Wx::ICON_QUESTION
        dial.show_modal
      end
      def mesaj_göster_4(e)
        dial = Wx::MessageDialog.new nil, 'İzin verilmeyen İşlem!', 'Dikkat!',
            Wx::OK | Wx::ICON_EXCLAMATION
        dial.show_modal
      end
    end

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


    Uygulamamızda 4 butonu bir grid sizer içine yerleştirdik. Bu butonlar 4 değişik diyalog penceresi açıyor. Bu pencereleri değişik bayraklarla biçimlendirdik.

      def mesaj_göster_2(e)
        dial = Wx::MessageDialog.new nil, 'İndirme Hatası', 'Hata!',
            Wx::OK | Wx::ICON_ERROR
        dial.show_modal
      end


    Mesaj diyaloğunun üretilmesi oldukça basit. Diyaloğun parent değerine nil girerek diyalog penceresinin üst seviye bir pencere olduğunu, başka bir pencerenin alt penceresi olmadığını bildiriyoruz. İki string argümandan ilki mesajı ikinci ise pencere etiketini belirtiyor. OK butonu ve bir hata ikonu olacağını bildiriyoruz. Son olarak da show_modal ile diyaloğu modal olarak gösteriyoruz (yani onu kapatmadan uygulamanın başka penceresine geçilemez).





    About diyalog penceresi

    Hemen her GUI uygulamasında bir about (hakkında) diyaloğu bulunur. Genellikle gösterilmesi Help menüsü altında bir menü ile sağlanır. Bu diyaloğun amacı kullanıcıya uygulama ve versiyonu hakkında bilgi vermektir. Bu günlerde bu diyaloglarda programın yazarı hakkında da bilgiler bulunabiliyor. Ayrıca uygulama lisansı hakkında da bilgiler içerir. Yapan firmanın ya da uygulamanın logoları da olabilir.

    Bir hakkında diyaloğu oluşturmak için iki nesne kullanırız, bir Wx::AboutDialogInfo nesnesi ve Wx sınıfının metodu olan  Wx.about_box metodu.

    about_dialog.rb

    require "wx"

    class Örnek < Wx::Frame
      def initialize(*args)
        super(*args)
        init_UI
      end
      def init_UI
        set_size [350, 250]
        set_title "Hakkında Diyaloğu"
        centre

        menubar = Wx::MenuBar.new
        help = Wx::Menu.new
        help.append Wx::ID_ABOUT, "&Hakkında"

        menubar.append help, "&Yardım"
        set_menu_bar menubar

        evt_menu Wx::ID_ABOUT, :on_about_box
      end
      def on_about_box(e)
        description = "WxWidgets Kullanan Ruby Uygulamam"
        licence = "Lisansımız yoktur."

        info = Wx::AboutDialogInfo.new
        info.icon = Wx::Icon.new "ujk2.png", Wx::BITMAP_TYPE_PNG
        info.name = "Benim Uygulamam"
        info.version = "1.0"
        info.description = description
        info.copyright = "(C) 2007 - 2024 UJK"
        info.web_site = "https://ujk-ujk.blogspot.com/"
        info.licence = licence
        info.add_developer "Ümit Kayacık"
        info.add_doc_writer "UJK"
        info.add_artist "Kendi sanatçı yanım"
        info.add_translator "O da ben"

        Wx.about_box info
      end
    end

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


    Uygulamamızda "Hakkında" menü elemanı var ve tıklanınca diyaloğumuz açılıyor. 

        description = "WxWidgets Kullanan Ruby Uygulamam"
        licence = "Lisansımız yoktur."

    Normalde açıklama ve lisans yazıları uzun yazılar olabilir, böyle durumlarda bunları kod içine koymaktansa ayrı bir dosya içinde yazmak daha doğru olur. Örneğin uygulamamızı başka dillere çevireceksek bu daha da gerekli olur. 

        info = Wx::AboutDialogInfo.new

    Öncelikle bir Wx::AboutDialogInfo nesnesi üretiyoruz. Başlangıçta içi boş. Üretim metodu parametre almıyor.

        info.icon = Wx::Icon.new "ujk2.png", Wx::BITMAP_TYPE_PNG
        info.name = "Benim Uygulamam"
        info.version = "1.0"
        info.description = description
        info.copyright = "(C) 2007 - 2024 UJK"
        info.web_site = "https://ujk-ujk.blogspot.com/"
        info.licence = licence
        info.add_developer "Ümit Kayacık"
        info.add_doc_writer "UJK"
        info.add_artist "Kendi sanatçı yanım"
        info.add_translator "O da ben"

    Daha sonra penceremizde gösterilecek bilgileri düzenliyoruz. 

        Wx.about_box info

    Wx sınıfının about_box metodu ile info nesnemizi yani hakkında penceremizi görünür hale getiriyoruz. 



    Kendi diyaloğumuzun tasarımı

    Şimdiki örneğimizde kendi diyaloğumuzu tasarlayacağız. Bir resim düzenleme uygulaması resmin renk derinliğini ayarlayabilir. Bu özelliği ifade edecek kendi diyaloğumuzu tasarlayalım.

    custom_dialog.rb

    require "wx"

    class DerinlikDeğiştirDiyalog < Wx::Dialog
      def initialize(*args)
        super(*args)
        init_UI
      end
      def init_UI
        set_size [250, 200]
        set_title "Renk Derinliği Değiştir"
        centre

        pnl = Wx::Panel.new self
        vbox = Wx::BoxSizer.new Wx::VERTICAL

        sbs = Wx::StaticBoxSizer.new Wx::VERTICAL, pnl, "Renkler"
        sbs.add Wx::RadioButton.new(pnl, label: "256 Renk",
                style: Wx::RB_GROUP)
        sbs.add Wx::RadioButton.new(pnl, label: "16 Renk")
        sbs.add Wx::RadioButton.new(pnl, label: "2 Renk")

        hbox1 = Wx::BoxSizer.new Wx::HORIZONTAL
        hbox1.add Wx::RadioButton.new(pnl, label: "Diğer")
        hbox1.add Wx::TextCtrl.new(pnl), 0, Wx::LEFT, 5
        sbs.add hbox1

        pnl.set_sizer sbs

        hbox2 = Wx::BoxSizer.new Wx::HORIZONTAL
        ok_button = Wx::Button.new self, label: 'Tamam'
        close_button = Wx::Button.new self, label: 'Kapat'
        hbox2.add ok_button
        hbox2.add close_button, 0, Wx::LEFT, 5

        vbox.add pnl, 1, Wx::ALL|Wx::EXPAND, 5
        vbox.add hbox2, 0, Wx::ALIGN_CENTER|Wx::TOP|Wx::BOTTOM, 10

        set_sizer vbox

        evt_button ok_button, :on_close
        evt_button close_button, :on_close
      end
      def on_close(e)
        destroy
      end
    end

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

        tb = create_tool_bar
        ctb = tb.add_tool Wx::ID_ANY, '', Wx::Bitmap.new('color.png')

        tb.realize

        evt_menu ctb, :on_change_depth
      end
      def on_change_depth(e)
        cd_dialog = DerinlikDeğiştirDiyalog.new nil,
            title: 'Renk Derinliği Değiştir'
        cd_dialog.show_modal
        cd_dialog.destroy
      end
    end

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

    Burada kendi tasarımımız bir diyalog oluşturduk

    class DerinlikDeğiştirDiyalog < Wx::Dialog
      def initialize(*args)
        super(*args)

    DerinlikDeğiştirDiyalog ismini verdiğimiz pencere sınıfımızı Wx::Dialog sınıfından kalıtımla oluşturduk. 

      def on_change_depth(e)
        cd_dialog = DerinlikDeğiştirDiyalog.new nil,
            title: 'Renk Derinliği Değiştir'
        cd_dialog.show_modal
        cd_dialog.destroy
      end

    Penceremizin bir oluşum nesnesini oluşturup show_modal metodunu çağırıyoruz. Pencereden çıkıldığında destroy metodunu çağırarak penceremizi yok ediyoruz. 






    Widget'lar

    Sıra geldi benim zımbırtılara. WxRuby'nin temel zımbırtılarını göreceğiz inşallah. Her widget için küçük kod örnekleri yapacağız. Widget'lar Wx uygulamasının temel yapı taşlarıdır. Wx kütüphanesinde buton, checkbox, listbox, slider gibi geniş bir widget stoğu var. 



    Wx::Button

    Wx::Button basit bir widget. Üzerinde bir etiket yazısı vardır ve tıklanınca bir hareketi tetikler.

    button_wid.rb

    require "wx"

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

        pnl = Wx::Panel.new self
        close_button = Wx::Button.new pnl, Wx::ID_ANY, 'Kapat', [20, 20]

        evt_button(close_button) { close }
      end
    end

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

    Örnekte penceremizde tıklandığında uygulamayı kapatan bir "Kapat" butonu var.

        close_button = Wx::Button.new pnl, Wx::ID_ANY, 'Kapat', [20, 20]

    Wx::Button sınıfı new metod yapısı

    initialize(parent, id, label = (''), pos = Wx::DEFAULT_POSITION,
      size = Wx::DEFAULT_SIZE, style = 0, validator = Wx::DEFAULT_VALIDATOR,
      name = Wx::BUTTON_NAME_STR) 

    parent ve id değerleri sıralı verilmek zorunda diğerleri mesela pos: [20, 20] gibi key parametre olarak verilebilir. Burada sıralamaya uyduğumuz için isimlendirmeye gerek yoktur. 

        evt_button(close_button) { close }

    Olay işleme metodu evt_button butonumuza tıklandığını algılıyor ve uygulamadan çıkılmasını sağlıyor.





















    Hiç yorum yok:

    Yorum Gönder