GoSuda

Kuvankatseluohjelman luominen Tk:lla Go:ssa tiedostoluettelon avulla

By Yunjin Lee
views ...

Edellisessä julkaisussa tarkastelimme lyhyesti CGo-Free Tcl/Tk -kirjastoa. Tällä kertaa luomme kuvankatseluohjelman soveltamalla edellisen kerran esimerkkiä.

Kuvankatseluohjelman suunnittelu

  1. Edellisen kerran kuvanäyttö ei sisältänyt kuvien poistotoimintoa, joten mitä enemmän kuvia ladattiin, sitä enemmän ikkunan koko ei riittänyt. Poistetaan käyttämättömät Labelit.
  2. Jos kuvankatseluohjelmassa on tarkoitus listata useita kuvia, luodaan lista.
  3. On suositeltavaa ladata useita kuvia kerralla.
  4. Toteutetaan myös toiminto, jolla kuvia, joita ei haluta nähdä, poistetaan listasta.
  5. Luodaan toiminto, jolla voidaan valita ja katsella tiettyä kuvaa useista kuvista.

Muokattu Tcl/Tk 9.0 -kirjasto

Olemassa olevassa kirjastossa Listboxin toteutus on puutteellinen, mikä tekee kuvien luetteloinnista vaikeaa. Ladataan muokattu kirjasto. Jos Git CLI ei ole asennettu, voit ladata sen tarball- tai zip-tiedostona.

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

Tarkastellaan ensin joitakin lisättyjä ominaisuuksia.

Ennen uusien funktioiden tarkastelua, käydään läpi olemassa olevien funktioiden rakenne tk.go-tiedoston rivin 1017 Destroy-funktion avulla.

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

Tämä funktio on toteutettu välittämällä toiminto Tcl-skriptimuodossa evalErr-funktiolle. Tämä tarkoittaa, että halutun toiminnon toteuttamiseksi riittää, että komento välitetään vastaavassa Tcl-skriptimuodossa.

Esimerkiksi toteutetaan metodi, joka lisää kohteen Listboxiin. Tarkastellaan ensin insert-komentoa, joka on käytettävissä listboxissa virallisessa käsikirjassa Tcl-skriptausta varten.

insert-komento

Insert-komennon kuvaussivun mukaan insert lisää luetellut kohteet tiettyyn indeksiin. Tämän toteuttamiseksi

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

voidaan kirjoittaa koodi, kuten yllä.

Nyt kun yleinen toteutusperiaate on selvillä, selitän ensin Listboxin lisätoiminnot.

Lista: Lisäys/Poisto

 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

Yllä olevassa ohjelmassa AddItem lisää välilyönneillä erotettuja eri kohteita peräkkäin alkaen indeksistä 0. Item1-item3 saavat peräkkäin indeksit 0, 1, 2. Suorita esimerkki ja selvitä, miten kohteen poisto toimii.

Lista: Valittujen kohteiden haku

Tarkastellaan nyt Listboxista valittuja kohteita.

 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-metodi hakee kaikkien Listboxissa tällä hetkellä valittujen kohteiden indeksit. GetOne-metodi hakee vastaavan indeksin kohteen arvon. Tulos näkyy konsolissa. Huomaa, että vastaava Get-metodi ottaa alku- ja loppuindeksit ja hakee kaikki kohteet kyseiseltä alueelta.

Seuraavaksi vaihdamme Listboxin väriä.

Tarkastellaan ensin alla olevaa esimerkkiä.

 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}

Värin soveltamisen tulos

Kuten yllä olevassa koodissa kirjoitettiin, korkeus kasvoi. Lisäksi voidaan nähdä, että värit on sovellettu hyvin. Tässä on määritetty asetus, jolla tietyn kohteen väriä muutetaan, ja vain ensimmäisen rivin väri on erilainen.

Lisäksi, vaikka suurta eroa ei ole, Relief-metodia käyttämällä voidaan muuttaa widgetin reunuksen tyyliä vaihtoehdoista flat, groove, raise, ridge, solid, sunken.

Kuvankatseluohjelman esimerkki

Luodaan nyt kuvankatseluohjelma käyttämällä edellä opittuja widgettejä. Esimerkkiohjelma on seuraava:

  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)) // Aktivoi monivalinnan ja kytkee suodattimet päälle.
 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    // Jos haluat käyttää teemaa, määritä teeman nimi ja polku.
139    fileMenu := menubar.Menu()
140    extensions = make([]FileType,0,1)
141    extensions = append(extensions, FileType{ "Supported Images", []string {".png",".ico"}, "" } )
142    // Lisää png ja ico suodattimeen.
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

Kuvankatseluohjelman suoritustulos

Tässä esimerkissä kaikkien kuvawidgetien lataaminen on yksinkertaistettu siten, että ne luodaan etukäteen, eikä tiedostojen duplikaatteja tarkisteta. Edellä mainittuja ongelmia voidaan parantaa, ja teemaa voidaan muuttaa käyttämällä kommentoituja DefaultTheme-metodeja. Yritä harjoitella luomalla uusi ohjelma, joka parantaa näitä osia.

Yhteenveto

Tässä artikkelissa tarkasteltiin Go-kielen Tcl/Tk-kirjaston komentokutsujen toimintatapaa ja luotiin kuvankatseluohjelma, johon oli lisätty Listbox.

  1. Tcl/Tk-kirjaston komentokutsutapa
  2. Listboxin käyttö
  3. Listbox-widgetin ominaisuuksien muuttaminen
  4. Kuvankatseluohjelman kirjoittaminen

Tällä tavoin voit haastaa itsesi muiden kirjastojen muokkaamiseen ja luoda valmiita ohjelmia lisätyillä toiminnoilla.