11. Sekmeli Panel (TabbedPanel) ve Ağaç Görünümü (TreeView)

Kivy’de sekmeler, diğer GUI’lerde olduğu gibi bir pencerede birden fazla sayfa görünümünü sunmak için kullanılır. Kivy’de Sekmeli Panel (TabbedPanel) olarak isimlendirilir. Oluşturulduğunda size ön tanımlı olarak Default sekmesini sunacaktır.

11.1. Kod ile Sekmeli Panel Oluşturulması

Her zaman olduğu gibi, öncelikle kod ile nasıl sekmeli panel oluşturacağımızı göreceğiz. Sözü fazla uzatmadan hemen örnek kodumuzu verelim, programımızı Liste 11.1‘deki gibi yazalım.

Liste 11.1 main.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# -*- coding: utf-8 -*-

from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.tabbedpanel import TabbedPanel, TabbedPanelHeader
from kivy.lang import Builder

class sekmeliPanel(App):

    def build(self):
        sekmeli_panel = TabbedPanel()
        
        sekmeli_panel.default_tab.text="İlk Sekme"
        
        sekmeli_panel.default_tab.content=Label(text="Sekmeli Panel'in İlk sayfası")
        
        for i, isim in enumerate(('Dilek', 'Fatih', 'Melike')):
            sekme=TabbedPanelHeader(text='Sekme %d' % (i+1))
            sekme.content=Label(text="Bu sekmenin sahibi: %s" % isim)
            sekmeli_panel.add_widget(sekme)
        
        return sekmeli_panel
        
sekmeliPanel().run()       

Şimdi burada olup biteni anlamaya çalışalım. Bir sekmeli panel TabbedPanel() parçacığı ile oluşturulur. Bir sekmeli panle oluşur oluşmaz ön tanımlı olarak default panel ile oluştur ve bu ön tanımlı sekme sekme parçacığının özelliklerine default_tab ın text ve content özelliklerini kullarak yapabilirsiniz. Aslında bunu default_tab_text ve default_tab_content ile de yapmanız mümkün ancak ben öncekini tercih ediyorum. Bunlardan ilki sekme başlığını ikincisi sekmenin içeriğini belirtir. Programımızda ön tanımlı sekmenin başlığını İlk Sekme içeriğini ise bir etiketten oluşturduk (etiket metinini açıklamaya gerek yok sanırım). Eğer ön tanımlı sekmeyi istemiyorsanız, sekmeli paneli oluştururken do_default_tab parametresinin değerini False yapmalısınız. Diğer bir deyişye, ön tanımlı sekmesi olmayan bir sekmeli paneli şu şekilde tanımlayabilirdik:

sekmeli_panel = TabbedPanel(do_default_tab=False)

Sekmeli Panele yeni sekmeler eklemek için, öncelikle bu sekmeyi hazırlamanız gerekir. Bunu sekme parçacığı TabbedPanelHeader() kullanarak yaparız. Bu parçacığın text özelliği sekmenin başlığını gösterir. İçeriğini ise, content özelliği ile oluşturabilirsiniz. content özelliğine istediğiniz bir pencere düzeni atayabilirsiniz. Burada basit olsun diye sadece bir etiket atadık.

Programımız önce ön tanımlı sekme oluşturuyor. Daha sonra bir sekme başlıkları “Sekme <sayi>” ve sekme içeriklerindeki etiketlerin metinleri “Bu sekmenin sahibi: <isim>” olacak şekilde yeni sekme parçacıkları oluşturup bunları Sekmeli Panele ekliyor. Programımız çalıştığında Şekil 11.1‘deki gibi olacaktır.

_images/sekme1.png

Şekil 11.1 Dört sekmeli panel

Şimdi biraz olaylara bakalım. İlk olarak ön tanımlı sekmeye geçiş yapıldığında oluşan olayı bir işeleve bağlayalım:

sekmeli_panel.default_tab.bind(on_release = self.sekmeDegistirildi)

Bu satırı return den hemen önce yazabilirsiniz. sekmeDegistirildi() işlevini de şu şekilde yazalım:

def sekmeDegistirildi(self,sekme):
    popup = Popup(title='Sekme Değiştirildi',
                  content=Label(text= "Sekme Başlığı: "+sekme.text),
                  size_hint=(None, None), size=(200, 200))
    popup.open()

Bu işlevi yazdıktan sonra programınızın başına aşağıdaki saırı yazarak Popup perçacaığını içermelisiniz:

from kivy.uix.popup import Popup

Şimdi programınızı çalışrırın ve bir sekmeye geçtikten sonra tekrar ön tanımlı sekmeye geçiş yapın. Popup penceres açılacaktır. İsterseniz tüm sekmelere geçiş yaptığınızda bu popup penceresini görüntülemek için for döngü bloğunu btirmeden önce aşağıdaki satırı ekleyebilirsiniz:

sekme.bind(on_release = self.sekmeDegistirildi)

11.2. kv Dili ile Sekmeli Panel Oluşturulması

Şimdi kv dili ile nasıl sekme oluşturabileceğimize bakalım. Sekmeli panleimizde hiçbir işlev yapmadan sadece oluşturalım. İlk olarak programımızı Liste 11.2‘deki gibi yazalım.

Liste 11.2 main.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# -*- coding: utf-8 -*-

from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.tabbedpanel import TabbedPanel, TabbedPanelHeader
from kivy.lang import Builder
from kivy.uix.popup import Popup

class sekmeliPanel(App):

    def build(self):
        pass
    
sekmeliPanel().run()       

kv dosyasını da Liste 11.3‘deki gibi yazalım.

Liste 11.3 sekmelipanel.kv
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
TabbedPanel:
    do_default_tab: False

    TabbedPanelItem:
        text: 'İlk Sekme'
        Label:
            text: 'Burası ilk sekme'
            
    TabbedPanelItem:
        text: 'İknci Sekme'
        BoxLayout:
            Label:
                text: 'İkinci sekme'
            Button:
                text: 'İşlevsiz Düğme'

    TabbedPanelItem:
        text: 'Üçüncü Sekme'
        Image:
            source: "kiwi.jpg"
            allow_stretch: True
            keep_ratio: False
            

Burada gördüğünüz gibi ikinci sekemede bir etiket ve bir işlevsiz düğme bulunmaktadır. Son sekemde ise sadece bir resim bulunuyour. main.py programını çalıştıracak olursak, Şekil 11.2‘deki gibi olacaktır.

_images/sekme2.png

Şekil 11.2 Dört sekmeli panel

11.3. Ağaç Görünümü (TreeView)

Aslında ağaç görünümüne daha önceden tanış olduk. Dosya açma diyaloğunda () kullandığımız FileChooserListView modülünde ağaç görünümü kullanılmaktadır. Bir ağaç görünümü şu şekildedir:

Kök
 |
 +--Ebeveyn 1
 |   |
 |   +--Çocuk 1 1
 |   |
 |   +--Çocuk 1 2
 |     |
 |     +--Çocuk 1 2 1
 |     |
 |     +--Çocuk 1 2 2
 |
 +--Ebeveyn 2
     |
     +--Çocuk 2 1
     |
     +--Çocuk 2 2

Burada her ebeveynin kendi çocuğu vardır. Şimdi böyle bir yapıyı nasıl oluşturacağımıza bakalım. Önce program ile nasıl yapılacağına bakacağız. Liste 11.4‘deki programı inceleyin

Liste 11.4 main.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# -*- coding: utf-8 -*-

from kivy.app import App

from kivy.uix.treeview import TreeView, TreeViewLabel

class agacGorunumu(App):

    def build(self):
        agac_koku = TreeView()
        ebeveyn1=agac_koku.add_node(TreeViewLabel(text='Ebeveyn 1'))
        
        cocuk11=agac_koku.add_node(TreeViewLabel(text='Çocuk 1 1'), ebeveyn1)
        cocuk12=agac_koku.add_node(TreeViewLabel(text='Çocuk 1 2'), ebeveyn1)
        
        cocuk121=agac_koku.add_node(TreeViewLabel(text='Çocuk 1 2 1'), cocuk12)
        cocuk122=agac_koku.add_node(TreeViewLabel(text='Çocuk 1 2 2'), cocuk12)
        
        ebeveyn2=agac_koku.add_node(TreeViewLabel(text='Ebeveyn 2'))
        cocuk21=agac_koku.add_node(TreeViewLabel(text='Çocuk 2 1'), ebeveyn2)
        cocuk22=agac_koku.add_node(TreeViewLabel(text='Çocuk 2 2'), ebeveyn2)

        
        return agac_koku
        
agacGorunumu().run()

Bir ağaç kökü TreeView() nesnesi ile oluşturulur. Daha sonra ebeveynler ve çocuklar bu ağaç köküne add_node ile eklenir. Eklenen her elemana düğüm (node) diyoruz. Tüm ebeveynler ve çocuklar ağaç köküne eklenir, yani beklendiği gibi, çocuklar önceki ebeveynlerine değil, doğrudan ağaç köküne eklenir, ancak hangi ebeyene ekleneceği, add_node() işevinin ikinci argümanı olarak belirtilir. Eğer argüman berlirtilemz ise, doğrudan köke eklenir. Programımızı çalıştırdığımızda Şekil 11.3‘deki gibi bir görüntü elde ederiz.

_images/agac1.png

Şekil 11.3 Ağaç görünümü

Elimizdeki veriseti ile bir ağaç kökünü Liste 11.5‘deki gibi doldurabiliriz:

Liste 11.5 main.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# -*- coding: utf-8 -*-

from kivy.app import App

from kivy.uix.treeview import TreeView, TreeViewLabel
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button

class agacGorunumu(App):

    def build(self):
        duzen=BoxLayout(orientation='vertical')
        
        self.agac_koku = TreeView(hide_root=True)
        
        kuruyemisler=[('Sert Kabuklular',('Ceviz', 'Fındık', 'Badem')), 
                      ('Meyve Kuruları',('Dut', 'Vişne', 'Kayısı', 'İncir'))]
        
        for ky in kuruyemisler:
            eb=self.agac_koku.add_node(TreeViewLabel(text=ky[0]))
            for k in ky[1]:
                self.agac_koku.add_node(TreeViewLabel(text=k),eb)
        
        duzen.add_widget(self.agac_koku)
        
        return duzen
        
        
agacGorunumu().run()

Bu programda ağaç kökünü hide_root ile gizlediğimize dikkat ediniz.

Peki seçilen elemana ya da tüm elemanlara nasıl ulaşacağız? Düğümler üzerinde iterasyonu iterate_all_nodes() ile yapabiliriz. Liste 11.5‘deki programdaki elemanlara ulaşmak için önce düzenimize bir düğme ekleyelim. Aşağıdaki kodu return den hemen önce yazın:

dgm=Button(text='Elemanları Yaz', size_hint_y=0.2)
dgm.bind(on_press=self.elemanlari_yaz)
duzen.add_widget(dgm)

Daha sonra düğmeye tıklandığında çağrılacak olan işlevi yazalım:

def elemanlari_yaz(self, *args):
    for eb in self.agac_koku.iterate_all_nodes():
        print eb.level, eb.text

Düğmeye tıkladığımızda ekrana elemanların konumları ve elemanlar yazılacaktır.

Eğer seçili olan elemana ulaşmak istiyorsanız selected_node() özelliğini kullanabilirsiniz. Aşağıdaki satırı elemanlari_yaz() işlevinin sonuna ekleyin ve düğmeye tıklayın:

if self.agac_koku.selected_node:
    print "Seçili Eleman", self.agac_koku.selected_node.text

Eğer önceden bir düğümü açılı yapmak istiyorsanız select_node özelliğini kullanabilirsiniz. Örneğin