GoSuda

Het creëren van een Image Viewer met een bestandslijst van Go naar Tk

By Yunjin Lee
views ...

In de vorige post hebben we een korte blik geworpen op de CGo-Free Tcl/Tk-bibliotheek. Deze keer zullen we een image viewer maken door de vorige voorbeelden toe te passen.

Plan voor de image viewer

  1. De image displayer van de vorige keer had geen functie om afbeeldingen te verwijderen, dus hoe meer afbeeldingen werden geladen, hoe kleiner het venster werd. Laten we de ongebruikte labels verwijderen.
  2. Als we meerdere afbeeldingen in de image displayer willen weergeven, laten we dan een lijst maken.
  3. Het is beter om meerdere afbeeldingen tegelijk te laden.
  4. Implementeer ook de mogelijkheid om afbeeldingen die niet bekeken zullen worden uit de lijst te verwijderen.
  5. Laten we een functie maken om een specifieke afbeelding uit meerdere afbeeldingen te selecteren en te bekijken.

Gewijzigde Tcl/Tk 9.0-bibliotheek

De bestaande bibliotheek heeft een onvolledige Listbox-implementatie, waardoor het moeilijk is om een lijst met afbeeldingen weer te geven. Laten we de gewijzigde bibliotheek downloaden. Als Git CLI niet is geïnstalleerd, kunt u deze ook downloaden als een tarball of zip-bestand.

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

Laten we eerst enkele van de toegevoegde functies bekijken.

Voordat we de nieuwe functies bekijken, zullen we eerst een eenvoudig begrip krijgen van de structuur van de bestaande functies via de Destroy-functie op regel 1017 van tk.go.

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

Deze functie is geïmplementeerd door een bewerking in Tcl-scriptformaat door te geven aan de evalErr-functie. Dit betekent dat om de gewenste functionaliteit te implementeren, commando's eenvoudigweg in het corresponderende Tcl-scriptformaat moeten worden doorgegeven.

Laten we bijvoorbeeld een methode implementeren om items aan een Listbox toe te voegen. Laten we eerst, voor Tcl-scripting, de insert opdracht bekijken die beschikbaar is voor listboxen in de officiële handleiding.

insert-opdracht

De beschrijvingspagina van de insert opdracht toont dat insert items invoegt in een gespecificeerde index. Dan kunnen we de volgende code schrijven om dit te implementeren:

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

en dergelijke code.

Nu we het algemene implementatieprincipe begrijpen, zal ik de extra functies voor Listboxen uitleggen.

Lijst: Invoegen/Verwijderen

 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

In het bovenstaande programma voegt AddItem verschillende items, gescheiden door spaties, sequentieel in vanaf index 0. Item1-item3 krijgen respectievelijk de indexen 0, 1 en 2. Voer het voorbeeld uit om te zien hoe itemverwijdering werkt.

Lijst: Geselecteerd item ophalen

Laten we nu de geselecteerde items uit de Listbox ophalen en controleren.

 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}

De Selected-methode haalt de indexen op van alle momenteel geselecteerde items in de Listbox. De GetOne-methode haalt de waarde op van het item dat overeenkomt met de opgegeven index. Dit kan worden gezien aan de hand van de uitvoer op de console. Ter referentie: de vergelijkbare Get-methode accepteert start- en eindindexen en haalt alle itemwaarden binnen dat bereik op.

Vervolgens zullen we de kleur van de Listbox wijzigen.

Laten we eerst het onderstaande voorbeeld bekijken.

 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}

Resultaat van kleurtoepassing

Zoals geschreven in de bovenstaande code, is de hoogte toegenomen. Bovendien is te zien dat de kleuren goed zijn toegepast. Aangezien een optie om de kleur van specifieke items te wijzigen is gespecificeerd, is te zien dat alleen de eerste regel een afwijkende kleur heeft.

Bovendien, hoewel er geen groot verschil is, kan de stijl van de widget-randen worden gewijzigd met de Relief-methode, uit flat, groove, raise, ridge, solid, sunken.

Voorbeeld van een image viewer

Laten we nu een image viewer maken met behulp van de widgets die we zojuist hebben geleerd. Het voorbeeldprogramma is als volgt:

  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)) //Meervoudige selectie inschakelen en filter aanzetten.
 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    //Als u een thema wilt gebruiken, specificeert u de themanaam en het pad.
139    fileMenu := menubar.Menu()
140    extensions = make([]FileType,0,1)
141    extensions = append(extensions, FileType{ "Supported Images", []string {".png",".ico"}, "" } )
142    //Voeg png en ico toe aan het filter.
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

Resultaat van de image viewer

In dit voorbeeld, om de implementatie te vereenvoudigen, worden alle image widgets vooraf gemaakt wanneer ze worden geladen, en dubbele bestanden worden niet gecontroleerd. U kunt de eerder genoemde problemen verbeteren, en u kunt proberen het thema te wijzigen met behulp van de DefaultTheme-methode, die is uitgeschreven. We raden u aan te oefenen door een nieuw programma te maken dat deze aspecten verbetert.

Samenvatting

In dit artikel hebben we onderzocht hoe de commando-aanroepen van de Tcl/Tk-bibliotheek in Go werken, en we hebben een image viewer gemaakt met een toegevoegde Listbox.

  1. De methode voor commando-aanroepen van de Tcl/Tk-bibliotheek
  2. Hoe de Listbox te gebruiken
  3. De eigenschappen van de Listbox-widget wijzigen
  4. Een image viewer maken

Probeer op dezelfde manier andere bibliotheken aan te passen en schrijf een compleet programma met de toegevoegde functionaliteit.