Skapa en bildvisare med Tk och en filista i Go
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
- 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.
- Om vi ska lista flera bilder i bildvisaren, låt oss skapa en lista.
- Det är bäst att ladda flera bilder samtidigt.
- Implementera även möjligheten att ta bort bilder som inte ska visas från listan.
- 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.
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}
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
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.
- Metod för kommandokall i Tcl/Tk-biblioteket
- Hur man använder Listbox
- Ändra Listbox-widgetens egenskaper
- 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.