GoSuda

Go'da Tk ile Dosya Listesi Eklenmiş Görüntüleyici Oluşturma

By Yunjin Lee
views ...

Geçen gönderimizde CGo-Free Tcl/Tk kütüphanesine kısaca göz atmıştık. Bu sefer, önceki örneği uygulayarak bir görüntüleyici oluşturmaya çalışacağız.

Görüntüleyici Planı

  1. Önceki görüntü gösterici, görüntü silme işlevine sahip değildi, bu da birden fazla görüntü yüklendikçe pencere boyutunun yetersiz kalmasına neden oluyordu. Kullanılmayan etiketleri silelim.
  2. Görüntü göstericiye birden fazla görüntü listelenecekse, bir liste oluşturalım.
  3. Bir seferde birden fazla görüntü yüklemek daha iyidir.
  4. Görüntülenmeyecek görüntüleri listeden çıkarma işlevini de uygulayalım.
  5. Çoklu görüntüler arasından belirli bir görüntüyü seçerek görüntüleme işlevi oluşturalım.

Değiştirilmiş Tcl/Tk 9.0 Kütüphanesi

Mevcut kütüphanede Listbox uygulaması yetersiz olduğu için görüntü listesini göstermek zordur. Değiştirilmiş kütüphaneyi indirelim. Git CLI yüklü değilse, tarball veya zip dosyası olarak da indirebilirsiniz.

1git clone https://github.com/gg582/tk9.0

Öncelikle eklenen bazı işlevlere göz atalım.

Yeni işlevleri incelemeden önce, mevcut işlevlerin nasıl çalıştığını tk.go dosyasının 1017. satırındaki Destroy işlevi aracılığıyla yapısını kısaca anlayalım.

1func Destroy(options ...Opt) {
2	evalErr(fmt.Sprintf("destroy %s", collect(options...)))
3}

Bu işlev, evalErr adlı bir işlev aracılığıyla Tcl betik formatında bir işlem iletilerek uygulanmıştır. Bu, istenen işlevi uygulamak için ilgili Tcl betik formatında bir komut iletmenin yeterli olduğu anlamına gelir.

Örnek olarak, bir listbox'a öğe ekleme yöntemini uygulayalım. Öncelikle Tcl betikleme için resmi kılavuzdan listbox'ta kullanılabilecek komutlardan insert komutuna bakalım.

insert komutu

insert komutunun açıklama sayfasına göre, insert belirli bir dizine listelenen öğeleri ekler. O zaman bunu uygulamak için

1func (l *ListboxWidget) AddItem(index int, items string) {
2	evalErr(fmt.Sprintf("%s insert %d %s", l.fpath, index, items))
3}

gibi bir kod yazabiliriz.

Şimdi genel uygulama prensibini anladığımıza göre, Listbox için ek işlevleri açıklayacağım.

Liste: Ekleme/Silme

 1package main
 2import . "modernc.org/tk9.0"
 3
 4func main() {
 5    length := 3
 6    l := Listbox()
 7    l.AddItem(0, "item1 item2 item3")
 8    b1 := TButton(Txt("Delete Multiple Items, index (0-1)"), Command( func(){
 9        if length >= 2 {
10            l.DeleteItems(0,1)
11            length-=2
12        }
13    }))
14    b2 := TButton(Txt("Delete One Item, index (0)"), Command( func () {
15        if length > 0 {
16            l.DeleteOne(0) 
17            length-=1
18        }
19    }))
20    Pack(TExit(),l,b1,b2)
21    App.Wait()
22}
23

Yukarıdaki programda AddItem, boşluklarla ayrılmış farklı öğeleri 0. indeksten başlayarak sırayla ekler. item1-item3 sırasıyla 0, 1, 2 indekslerine sahip olacaktır. Öğe silme işleminin nasıl çalıştığını görmek için örneği çalıştıralım.

Liste: Seçili Öğeleri Alın

Şimdi Listbox'tan seçilen öğeleri alıp kontrol edelim.

 1package main
 2
 3import . "modernc.org/tk9.0"
 4
 5func main() {
 6    l := Listbox()
 7    l.SelectMode("multiple")
 8    l.AddItem(0, "item1 item2 item3")
 9    btn := TButton(Txt("Print Selected"), Command( func() {
10        sel := l.Selected()
11        for _, i := range sel {
12            println(l.GetOne(i))
13        }
14    }))
15
16    Pack(TExit(), l, btn)
17    App.Wait()
18}

Selected metodu, Listbox'ta seçilen tüm öğelerin indekslerini getirir. GetOne metodu, ilgili indekse karşılık gelen öğenin değerini getirir. Konsolda gösterilen sonuçtan anlaşılabilir. Benzer bir metod olan Get metodu, başlangıç ve bitiş indekslerini alarak aralıktaki tüm öğelerin değerlerini getirir.

Şimdi Listbox'ın renklerini değiştirmeye çalışalım.

Öncelikle aşağıdaki örneğe göz atalım.

 1package main
 2
 3import . "modernc.org/tk9.0"
 4
 5func main() {
 6    l := Listbox()
 7    l.Background("blue")
 8    l.Foreground("yellow")
 9    l.SelectBackground("black")
10    l.SelectForeground("white")
11    l.Height(20)
12    l.Width(6)
13    l.AddItem(0, "item1 item2 item3")
14    l.ItemForeground(0,"red")
15    l.ItemBackground(0,"green")
16    l.ItemSelectBackground(0,"white")
17    l.ItemSelectForeground(0,"black")
18    l.Relief("ridged")
19    Pack(TExit(),l)
20    App.Wait()
21}

Renk uygulama sonucu

Yukarıdaki kodda belirtildiği gibi, yükseklik arttı. Ayrıca, renklerin iyi uygulandığı görülebilir. Burada belirli bir öğeye farklı renk uygulama seçeneği belirtildiği için sadece ilk satırın renginin farklı uygulandığı anlaşılmaktadır.

Ayrıca, büyük bir fark olmasa da, Relief metodu kullanılarak flat, groove, raise, ridge, solid, sunken gibi widget kenarlık stilini değiştirmek mümkündür.

Görüntüleyici Örneği

Şimdiye kadar öğrendiğimiz widget'ları kullanarak bir görüntüleyici oluşturalım. Örnek program aşağıdaki gibidir:

  1package main
  2
  3import (
  4    "fmt"
  5    "log"
  6    "os"
  7    "runtime"
  8    "strings"
  9    "path"
 10
 11    . "modernc.org/tk9.0"
 12)
 13
 14var pbuttons []*TButtonWidget
 15var extensions []FileType
 16var pbutton *TButtonWidget = nil
 17var listbox, listbox2 *ListboxWidget
 18var cur *LabelWidget = nil
 19var imagesLoaded []*LabelWidget
 20func PhotoName(fileName string) string {
 21        fileName = path.Base(fileName)
 22        return fileName[:len(fileName)-len(path.Ext(fileName))]
 23}
 24
 25func handleFileOpen() {
 26    res := GetOpenFile(Multiple(true),Filetypes(extensions)) //Çoklu seçimi etkinleştirir ve filtreleri açar.
 27    s := make([]string,0,1000)
 28    for _, itm := range res {
 29        if itm != "" {
 30            tmp := strings.Split(itm," ")
 31            s = append(s,tmp...)
 32        }
 33    }
 34
 35    for _, photo := range s {
 36        formatCheck := strings.Split(photo, ".")
 37        format := formatCheck[len(formatCheck)-1]
 38
 39        if (strings.Compare(format, "png") == 0) || (strings.Compare(format, "ico") == 0) {
 40            picFile, err := os.Open(photo)
 41            if err != nil {
 42                log.Println("Error while opening photo, error is: ", err)
 43            }
 44
 45            pictureRawData := make([]byte, 10000*10000)
 46            picFile.Read(pictureRawData)
 47
 48            imageLabel := Label(Image(NewPhoto(Data(pictureRawData))))
 49                        imagesLoaded = append(imagesLoaded,imageLabel)
 50            var deleteTestButton *TButtonWidget
 51            deleteTestButton = TButton(
 52                Txt("Unshow Image"),
 53            Command(func() {
 54                GridForget(imageLabel.Window)
 55                GridForget(deleteTestButton.Window)
 56            }))
 57
 58            pbuttons = append(pbuttons,deleteTestButton)
 59
 60                        listbox.AddItem(len(imagesLoaded)-1,PhotoName(photo))
 61                        listbox2.AddItem(len(imagesLoaded)-1,PhotoName(photo))
 62            picFile.Close()
 63        }
 64    }
 65}
 66
 67func DeleteSelected () {
 68    s:=listbox.Selected()
 69    if len(s) == 0 {
 70        return
 71        }
 72    for _, i := range s {
 73        listbox.DeleteOne(i)
 74        listbox2.DeleteOne(i)
 75        if len(imagesLoaded)-1>i {
 76            continue
 77        }
 78        if cur == imagesLoaded[i] {
 79            pbutton = nil
 80            cur = nil
 81        }
 82        Destroy(imagesLoaded[i])
 83        Destroy(pbuttons[i])
 84                imagesLoaded = append(imagesLoaded[:i],imagesLoaded[i+1:]...)
 85        pbuttons = append(pbuttons[:i], pbuttons[i+1:]...)
 86    }
 87}
 88
 89func SelectImage() {
 90        s:=listbox2.Selected()
 91        if len(s) == 0 {
 92                return
 93        }
 94
 95    if len(imagesLoaded) -1 < s[0] {
 96        return
 97    }
 98    if imagesLoaded[s[0]] == nil {
 99        return
100    }
101    if cur != nil {
102            GridForget(cur.Window)
103    }
104    if pbutton != nil {
105        GridForget(pbutton.Window)
106    }
107
108        Grid(imagesLoaded[s[0]], Row(0), Column(2))
109    Grid(pbuttons[s[0]], Row(0), Column(3))
110    cur = imagesLoaded[s[0]]
111    pbutton = pbuttons[s[0]]
112}
113
114func SelectIndex(index int) {
115
116    if len(imagesLoaded) -1 <index {
117        return
118    }
119    if imagesLoaded[index] == nil {
120        return
121    }
122    if cur != nil {
123            GridForget(cur.Window)
124    }
125    if pbutton != nil {
126        GridForget(pbutton.Window)
127    }
128
129        Grid(imagesLoaded[index], Row(0), Column(2))
130    Grid(pbuttons[index], Row(0), Column(3))
131    cur = imagesLoaded[index]
132    pbutton = pbuttons[index]
133}
134
135func main() {
136    menubar := Menu()
137    //DefaultTheme("awdark","themes/awthemes-10.4.0")
138    //Temayı kullanmak istiyorsanız, tema adını ve yolunu belirtin.
139    fileMenu := menubar.Menu()
140    extensions = make([]FileType,0,1)
141    extensions = append(extensions, FileType{ "Supported Images", []string {".png",".ico"}, "" } )
142    //Filtreye png ve ico ekler.
143    fileMenu.AddCommand(Lbl("Open..."), Underline(0), Accelerator("Ctrl+O"), Command(func () {
144        handleFileOpen()
145        SelectIndex(len(imagesLoaded)-1)
146    } ))
147    Bind(App, "<Control-o>", Command(func() { fileMenu.Invoke(0) }))
148    fileMenu.AddCommand(Lbl("Exit"), Underline(1), Accelerator("Ctrl+Q"), ExitHandler())
149    Bind(App, "<Control-q>", Command(func() { fileMenu.Invoke(1) }))
150    menubar.AddCascade(Lbl("File"), Underline(0), Mnu(fileMenu))
151        imagesLoaded = make([]*LabelWidget, 0, 10000)
152    pbuttons = make([]*TButtonWidget,0,10000)
153    var scrollx, scroll, scroll2, scrollx2 *TScrollbarWidget
154        listbox = Listbox(Yscrollcommand(func(e *Event) { e.ScrollSet(scroll)}) , Xscrollcommand( func(e *Event) { e.ScrollSet(scrollx)}))
155        listbox2 = Listbox(Yscrollcommand(func(e *Event) { e.ScrollSet(scroll2)}), Xscrollcommand(func(e *Event) { e.ScrollSet(scrollx2)}))
156        listbox.SelectMode("multiple")
157        listbox2 = Listbox()
158        listbox.Background("white")
159        listbox.SelectBackground("blue")
160        listbox.SelectForeground("yellow")
161        listbox2.Background("grey")
162        listbox2.SelectBackground("green")
163    listbox2.SelectForeground("blue")
164    listbox2.SelectBackground("brown")
165        listbox.Height(5)
166        listbox.Width(4)
167        listbox2.Height(5)
168        listbox2.Width(4)
169        delBtn := Button(Txt("Delete"), Command(func () { DeleteSelected() }))
170        selBtn := Button(Txt("Select"), Command(func () { SelectImage() }))
171        scroll = TScrollbar(Command(func(e *Event) { e.Yview(listbox) }))
172        scrollx = TScrollbar(Orient("horizontal"),Command(func(e *Event) { e.Xview(listbox) }))
173    scroll2 = TScrollbar(Command(func(e *Event) { e.Yview(listbox2) }))
174        scrollx2 = TScrollbar(Orient("horizontal"),Command(func(e *Event) { e.Xview(listbox2) }))
175        Grid(listbox,Row(1),Column(0), Sticky("nes"))
176        Grid(scroll,Row(1),Column(1), Sticky("nes"))
177    Grid(scrollx,Row(2),Column(0),  Sticky("nes"))
178        Grid(delBtn,Row(3),Column(0), Sticky("nes"))
179        Grid(listbox2,Row(1),Column(2), Sticky("nes"))
180        Grid(scroll2,Row(1),Column(3), Sticky("nes"))
181    Grid(scrollx2,Row(2),Column(2), Sticky("nes"))
182        Grid(selBtn,Row(3),Column(2), Sticky("nes"))
183    App.WmTitle(fmt.Sprintf("%s on %s", App.WmTitle(""), runtime.GOOS))
184    App.Configure(Mnu(menubar), Width("80c"), Height("60c")).Wait()
185}
186

Görüntüleyici çalıştırma sonucu

Bu örnekte, uygulamanın basitliğini korumak için tüm görüntü widget'ları önceden yüklenir ve yinelenen dosyalar kontrol edilmez. Daha önce bahsettiğim sorunları düzeltebilir veya yorum satırı haline getirilmiş DefaultTheme metodunu kullanarak temayı değiştirmeyi deneyebilirsiniz. Bu tür iyileştirmelerle yeni bir program oluşturarak pratik yapmanız tavsiye edilir.

Özet

Bu yazıda, Go dilinin Tcl/Tk kütüphanesinin komut çağrılarının nasıl çalıştığını öğrendik ve Listbox eklenmiş bir görüntüleyici oluşturduk.

  1. Tcl/Tk kütüphanesinin komut çağırma yöntemi
  2. Listbox kullanım yöntemleri
  3. Listbox widget özelliklerinin değiştirilmesi
  4. Görüntüleyici oluşturma

Bu şekilde diğer kütüphanelerin modifikasyonlarına da meydan okuyun ve eklediğiniz özelliklerle tamamlanmış programlar yazmaya çalışın.