GoSuda

Oprettelse af en billedfremviser med en filliste i Tk fra Go

By Yunjin Lee
views ...

I det sidste indlæg så vi kort på CGo-Free Tcl/Tk-biblioteket. Denne gang vil vi anvende eksemplet fra sidst til at skabe en billedfremviser.

Plan for billedfremviser

  1. Den billedfremviser fra sidste gang havde ikke en funktion til at slette billeder, så når man indlæste flere billeder, blev vinduets størrelse utilstrækkelig. Lad os slette de ubrugte labels.
  2. Hvis billedfremviseren skal liste flere billeder, lad os oprette en liste.
  3. Det er bedst at indlæse flere billeder på én gang.
  4. Implementer også funktionen til at fjerne billeder, der ikke skal ses, fra listen.
  5. Lad os oprette en funktion til at vælge og vise et specifikt billede blandt flere billeder.

Modificeret Tcl/Tk 9.0-bibliotek

Den eksisterende bibliotek har en mangelfuld Listbox-implementering, hvilket gør det vanskeligt at vise en billedliste. Lad os downloade det modificerede bibliotek. Hvis Git CLI ikke er installeret, kan du også downloade det som en tarball eller zip-fil.

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

Lad os først se på nogle af de tilføjede funktioner.

Før vi ser på de nye funktioner, lad os kort forstå strukturen af de eksisterende funktioner ved at kigge på Destroy-funktionen på linje 1017 i tk.go.

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

Denne funktion er implementeret ved at overføre handlingen i Tcl-scriptformat til en funktion kaldet evalErr. Det betyder, at for at implementere den ønskede funktion, skal man blot overføre kommandoen i det tilsvarende Tcl-scriptformat.

Lad os som eksempel implementere en metode til at tilføje elementer til en listbox. Først, for Tcl-scripting, lad os se på kommandoen 'insert' blandt de kommandoer, der kan bruges med listbox i den officielle manual.

insert-kommando

Hvis man ser på 'insert'-kommandoens beskrivelsesside, indsætter 'insert' de anførte elementer ved et bestemt indeks. For at implementere dette kan man skrive kode som:

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

Nu hvor vi har en generel forståelse af implementeringsprincippet, vil jeg forklare de yderligere funktioner til Listbox.

Liste: Indsættelse/Sletning

 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 ovenstående program indsætter AddItem elementer, adskilt af mellemrum, i rækkefølge fra indeks 0. item1-item3 vil have henholdsvis indeks 0, 1 og 2. Kør eksemplet for at forstå, hvordan elementssletning fungerer.

Liste: Hentning af valgte elementer

Nu vil vi hente de valgte elementer fra Listbox og derefter verificere 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}

Selected-metoden henter indeksene for alle valgte elementer i den aktuelle Listbox. GetOne-metoden henter værdien af elementet, der svarer til det pågældende indeks. Dette kan ses ud fra resultatet, der udskrives til konsollen. Bemærk, at den lignende Get-metode tager et start- og slutindeks og henter værdierne for alle elementer inden for området.

Dernæst vil vi ændre farven på listboxen.

Lad os 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}

Farveapplikationsresultat

Som skrevet i koden ovenfor, er højden øget. Desuden kan det ses, at farverne er blevet anvendt korrekt. Da der er angivet en mulighed for at anvende forskellige farver kun på specifikke elementer, kan det ses, at kun den første linje har fået en anderledes farve.

Desuden, selvom forskellen ikke er stor, kan Relief-metoden bruges til at ændre widget-grænsens stil til flat, groove, raise, ridge, solid, eller sunken.

Eksempel på billedfremviser

Lad os nu bygge en billedfremviser ved hjælp af de widgets, vi lige har lært. Eksempelprogrammet er som følger:

  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)) //Aktiverer multiselection og tænder for filteret.
 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    //Angiv temaets navn og sti, hvis du ønsker at bruge et tema.
139    fileMenu := menubar.Menu()
140    extensions = make([]FileType,0,1)
141    extensions = append(extensions, FileType{ "Supported Images", []string {".png",".ico"}, "" } )
142    //Tilføj png og ico til filteret.
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

Resultat af billedfremviserens udførelse

I dette eksempel, for at forenkle implementeringen, oprettes alle billedwidgets på forhånd, når de indlæses, og duplikerede filer kontrolleres ikke. Du kan forbedre de nævnte problemer, og du kan også prøve at ændre temaet ved at bruge DefaultTheme-metoden, som er kommenteret ud. Prøv at øve dig ved at oprette et nyt program, der forbedrer disse aspekter.

Sammenfatning

I denne artikel undersøgte vi, hvordan kommandokald i Go-sprogets Tcl/Tk-bibliotek fungerer, og vi oprettede en billedfremviser med en tilføjet Listbox.

  1. Tcl/Tk-bibliotekets kommandokaldsmetode
  2. Sådan bruges Listbox
  3. Ændring af Listbox-widgetens egenskaber
  4. Oprettelse af en billedfremviser

På denne måde kan du også forsøge at modificere andre biblioteker og skrive færdige programmer med de tilføjede funktioner.