Een afbeeldingsviewer maken met een lijst van bestanden in Tk vanuit Go
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
- 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.
- Als we meerdere afbeeldingen in de afbeeldingsweergave willen weergeven, laten we dan een lijst maken.
- Het is beter om meerdere afbeeldingen tegelijk te laden.
- Laten we ook de functie implementeren om afbeeldingen die niet bekeken zullen worden uit de lijst te verwijderen.
- 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.
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}

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

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.
- De methode voor het aanroepen van opdrachten van de Tcl/Tk-bibliotheek
- Hoe de listbox te gebruiken
- Attributen van de listbox-widget wijzigen
- Afbeeldingsviewer maken
Op deze manier kunt u proberen andere bibliotheken te wijzigen en voltooide programma's te schrijven met de toegevoegde functies.