GoSuda

Skapa en bildvisare med Tk och en filista i Go

By Yunjin Lee
views ...

I det föregående inlägget gav vi en kort översikt över CGo-Free Tcl/Tk-biblioteket. Denna gång kommer vi att bygga en bildvisare genom att tillämpa exemplet från förra gången.

Plan för bildvisare

  1. Bildvisaren från förra gången saknade en funktion för bildborttagning, vilket ledde till att fönstrets storlek blev otillräcklig när flera bilder laddades. Låt oss ta bort oanvända Labels.
  2. Om vi ska lista flera bilder i bildvisaren, låt oss skapa en lista.
  3. Det är bäst att ladda flera bilder samtidigt.
  4. Implementera även möjligheten att ta bort bilder som inte ska visas från listan.
  5. Låt oss skapa en funktion för att välja och visa en specifik bild bland flera bilder.

Modifierat Tcl/Tk 9.0-bibliotek

Det befintliga biblioteket har bristfällig Listbox-implementering, vilket gör det svårt att visa en bildlista. Låt oss ladda ner det modifierade biblioteket. Om Git CLI inte är installerat kan du ladda ner det som en tarball eller zip-fil.

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

Låt oss först titta på några av de nya funktionerna som har lagts till.

Innan vi går igenom de nya funktionerna, låt oss kortfattat förstå strukturen för de befintliga funktionerna genom att titta på Destroy-funktionen på rad 1017 i tk.go.

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

Denna funktion är implementerad genom att överföra operationen i Tcl-skriptformat till funktionen evalErr. Detta innebär att för att implementera önskad funktion behöver man bara överföra kommandot i motsvarande Tcl-skriptformat.

Som ett exempel, låt oss implementera en metod för att lägga till ett objekt i en Listbox. Först, för Tcl-skriptning, låt oss titta på kommandot insert bland de kommandon som kan användas för Listbox från den officiella manualen.

insert-kommando

Enligt beskrivningssidan för insert-kommandot infogar insert listade objekt vid en specifik index. För att implementera detta kan vi skriva kod som liknar följande:

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

Nu när vi har en grov förståelse för implementeringsprincipen, låt mig först förklara de ytterligare funktionerna för Listbox.

Lista: Infoga/ta bort

 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 ovan lägger AddItem till olika objekt, åtskilda av mellanslag, sekventiellt från index 0. item1-item3 kommer att ha index 0, 1, 2 i ordning. Kör exemplet för att se hur borttagning av objekt fungerar.

Lista: Hämta valda objekt

Låt oss nu hämta och kontrollera de valda objekten från Listbox.

 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 hämtar index för alla valda objekt i den aktuella Listbox. GetOne-metoden hämtar värdet för objektet som motsvarar det angivna indexet. Resultatet kan ses i konsolen. Observera att den liknande metoden Get tar start- och slutindex och hämtar värdena för alla objekt inom intervallet.

Nästa steg är att ändra färgen på Listbox.

Låt oss först titta på exemplet nedan.

 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 färganvändning

Som skrivet i koden ovan har höjden ökat. Dessutom kan man se att färgerna har applicerats väl. Här har ett alternativ angetts för att ändra färg endast för specifika objekt, så endast den första raden har en annan färg.

Dessutom, även om skillnaden inte är stor, kan man med Relief-metoden ändra stil på widgetens kant till flat, groove, raise, ridge, solid eller sunken.

Exempel på bildvisare

Låt oss nu skapa en bildvisare med hjälp av de widgets vi just har lärt oss. Exempelprogrammet är följande:

  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)) // Aktiverar flerval och filter.
 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    // Om du vill använda ett tema, ange tema namn och sökväg.
139    fileMenu := menubar.Menu()
140    extensions = make([]FileType,0,1)
141    extensions = append(extensions, FileType{ "Supported Images", []string {".png",".ico"}, "" } )
142    // Lägger till png och ico i filtret.
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 av bildvisaren

I detta exempel, för att förenkla implementeringen, skapas alla bildwidgets i förväg när de laddas, och dubbletter av filer kontrolleras inte. Du kan förbättra de problem som nämns ovan, eller försöka ändra tema med hjälp av DefaultTheme-metoden, som är utkommenterad. Försök att skapa ett nytt program som förbättrar dessa aspekter som en övning.

Sammanfattning

I den här artikeln har vi undersökt hur kommandokall i Go-språkets Tcl/Tk-bibliotek fungerar, och vi har skapat en bildvisare med en tillagd Listbox.

  1. Metod för kommandokall i Tcl/Tk-biblioteket
  2. Hur man använder Listbox
  3. Ändra Listbox-widgetens egenskaper
  4. Skriva en bildvisare

På detta sätt, försök att utmana dig själv att modifiera andra bibliotek och skapa kompletta program med de tillagda funktionerna.