GoSuda

Een afbeeldingsviewer maken met een lijst van bestanden in Tk vanuit Go

By Yunjin Lee
views ...

In de vorige post hebben we kort gekeken naar de CGo-Free Tcl/Tk-bibliotheek. Deze keer zullen we een afbeeldingsviewer maken door de voorbeelden van de vorige keer toe te passen.

Afbeeldingsviewerplanning

  1. De afbeeldingsweergave van de vorige keer had geen functie voor het verwijderen van afbeeldingen, waardoor het venster te klein werd naarmate er meer afbeeldingen werden geladen. Laten we ongebruikte labels verwijderen.
  2. Als we meerdere afbeeldingen in de afbeeldingsweergave willen weergeven, laten we dan een lijst maken.
  3. Het is beter om meerdere afbeeldingen tegelijk te laden.
  4. Laten we ook de functie implementeren 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 onvoldoende 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 als tarball of zip-bestand downloaden.

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 hoe de bestaande functies zijn gestructureerd aan de hand van 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 de actie in Tcl-scriptformaat door te geven aan een functie genaamd evalErr. Dat betekent dat om de gewenste functionaliteit te implementeren, men alleen de opdracht in het corresponderende Tcl-scriptformaat hoeft door te geven.

Als voorbeeld zullen we een methode implementeren om een item aan een listbox toe te voegen. Laten we eerst de insert-opdracht bekijken, een van de beschikbare opdrachten voor listboxen, in de officiële handleiding voor Tcl-scripting.

insert-opdracht

De beschrijvingspagina van de insert-opdracht vermeldt dat insert items invoegt op een specifieke index. Om dit te implementeren, kunnen we de volgende code schrijven:

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

Nu we het algemene implementatieprincipe kennen, zal ik eerst de aanvullende functies voor Listbox 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, 2. Voer het voorbeeld uit om te zien hoe het verwijderen van items werkt.

Lijst: geselecteerde items 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 van alle momenteel geselecteerde items in de Listbox op. De GetOne-methode haalt de waarde van het item op dat overeenkomt met de betreffende index. Dit kan worden afgeleid uit de uitvoer op de console. Ter referentie haalt de vergelijkbare Get-methode de waarden van alle items binnen een bereik op, door de start- en eindindex te accepteren.

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 in de bovenstaande code geschreven, is de hoogte toegenomen. Bovendien is te zien dat de kleuren goed zijn toegepast. Hier is een optie ingesteld om de kleur van specifieke items te wijzigen, waardoor alleen de eerste regel een andere kleur heeft.

Bovendien, hoewel er geen groot verschil is, kan de Relief-methode worden gebruikt om de stijl van de widget-rand te wijzigen naar flat, groove, raise, ridge, solid of sunken.

Voorbeeld van een afbeeldingsviewer

Laten we nu een afbeeldingsviewer 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)) //Meerdere selecties activeren en filters inschakelen.
 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    //Geef de themanaam en het pad op als u een thema wilt gebruiken.
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 uitvoering van de afbeeldingsviewer

In dit voorbeeld, om de implementatie te vereenvoudigen, worden alle afbeeldingswidgets vooraf gemaakt bij het laden, en er wordt niet gecontroleerd op dubbele bestanden. U kunt de eerder genoemde problemen verbeteren, of u kunt proberen het thema te wijzigen met behulp van de uitgeschakelde DefaultTheme-methode. Oefen door een nieuw programma te maken dat deze aspecten verbetert.

Samenvatting

In dit artikel hebben we gekeken naar hoe de opdrachtaanroepen van de Tcl/Tk-bibliotheek van de Go-taal werken en hebben we een afbeeldingsviewer met een toegevoegde listbox gemaakt.

  1. De methode voor het aanroepen van opdrachten van de Tcl/Tk-bibliotheek
  2. Hoe de listbox te gebruiken
  3. Attributen van de listbox-widget wijzigen
  4. Afbeeldingsviewer maken

Op deze manier kunt u proberen andere bibliotheken te wijzigen en voltooide programma's te schrijven met de toegevoegde functies.