GoSuda

Implementering av en bildevisar med flerfilslisteboks i Go og Tcl/Tk 9.0

By Yunjin Lee views ...

Forrige innlegg så på CGo-Free Tcl/Tk-biblioteket i korte trekk. I dette innlegget skal vi bygge en bildevisning ved å videreutvikle eksemplet fra sist.

Plan for bildevisningen

  1. Bildevisningen fra forrige gang hadde ingen funksjon for å slette bilder, så vinduet ble for lite etter hvert som flere bilder ble lastet inn. La oss slette etiketter som ikke lenger brukes.
  2. Hvis bildevisningen skal liste flere bilder, bør vi lage en liste.
  3. Det er lurt å kunne laste inn flere bilder samtidig.
  4. Vi implementerer også funksjonen for å fjerne bilder fra listen når de ikke skal vises.
  5. La oss lage en funksjon der man kan velge og vise ett bestemt bilde blant flere.

Endret Tcl/Tk 9.0-bibliotek

Det opprinnelige biblioteket har en mangelfull implementasjon av Listbox, og det er vanskelig å vise en bildeliste med det. La oss laste ned det endrede biblioteket. Hvis Git CLI ikke er installert, kan du i stedet laste ned tarball- eller zip-filen.

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

La oss først se på noen av de nye funksjonene.

Før vi ser på de nye funksjonene, skal vi først undersøke hvordan de eksisterende funksjonene er bygget opp. Vi tar utgangspunkt i funksjonen Destroy i tk.go på linje 1017.

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

Denne funksjonen er implementert ved å sende handlingen som et Tcl-skript til funksjonen evalErr. Det betyr at for å implementere en ønsket funksjon er det tilstrekkelig å sende kommandoen i form av det tilsvarende Tcl-skriptet.

Som et eksempel implementerer vi en metode som legger til elementer i en listboks. Først undersøker vi insert, en av kommandoene for listbox, i den offisielle manualen.

insert-kommando

Av beskrivelsen av insert-kommandoen fremgår det at insert setter inn de oppførte elementene ved en bestemt indeks. For å implementere dette kan vi skrive for eksempel:

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

Nå som vi har forstått det grunnleggende prinsippet, skal vi forklare de ekstra funksjonene for Listbox.

Liste: innsetting/sletting

 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

I programmet over setter AddItem elementene som er atskilt med mellomrom inn fortløpende fra indeks 0. item1 til item3 får henholdsvis indeksene 0, 1 og 2. La oss kjøre eksemplet for å se hvordan sletting av elementer fungerer.

Liste: hente valgte elementer

Nå henter vi de valgte elementene fra Listbox og kontrollerer dem.

 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}

Metoden Selected henter indeksene til alle elementene som er valgt i Listbox. Metoden GetOne henter verdien til elementet med den gitte indeksen. Dette kan vi se av resultatet som skrives ut i konsollen. Merk at den tilsvarende metoden Get henter verdiene til alle elementene innenfor et område, gitt ved start- og sluttindeks.

Deretter skal vi endre fargene på listboksen.

La oss først se på eksemplet nedenfor.

 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}

Resultat av fargeinnstillinger

Som koden over viser, har høyden økt slik vi angav. Vi ser også at fargene er brukt korrekt. Her er det angitt et alternativ som gir bestemte elementer en annen farge, så det er bare den første linjen som har en annen farge.

Relief-metoden kan dessuten brukes til å endre stilen på kanten av en widget til flat, groove, raise, ridge, solid eller sunken. Forskjellen er ikke stor, men det er en mulighet.

Eksempel på bildevisning

La oss nå bruke widgetene vi har lært om til å lage en bildevisning. Eksempelprogrammet ser slik ut:

  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)) //다중 선택을 활성화하고 필터를 켭니다.
 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    //테마를 사용하고 싶을 때에는 테마 명과 경로를 지정해 줍니다.
139    fileMenu := menubar.Menu()
140    extensions = make([]FileType,0,1)
141    extensions = append(extensions, FileType{ "Supported Images", []string {".png",".ico"}, "" } )
142    //필터에 png와 ico를 넣어 줍니다.
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

Kjøring av bildevisningen

I dette eksemplet lages alle bildewidgetene på forhånd når bildene lastes inn, for å gjøre implementasjonen enkel, og det blir ikke kontrollert for duplikate filer. De nevnte problemene kan forbedres, og du kan også prøve å endre temaet ved hjelp av DefaultTheme-metoden som er satt som kommentar. Vi oppfordrer deg til å øve ved å lage et forbedret program med disse endringene.

Oppsummering

I denne artikkelen så vi på hvordan kommandokall i Tcl/Tk-biblioteket for Go fungerer, og vi laget en bildevisning med listboks.

  1. Metoden for kommandokall i Tcl/Tk-biblioteket
  2. Bruk av listboks
  3. Endring av egenskaper for listbox-widgeten
  4. Utvikling av bildevisning

Vi oppfordrer deg til å prøve den samme tilnærmingen på andre biblioteker og å lage et komplett program med de nye funksjonene.