Skapa en bildvisare med Tk och filförteckning i Go
I det förra inlägget gav vi en kort översikt över CGo-Free Tcl/Tk-biblioteket. Den här gången kommer vi att använda det förra exemplet för att skapa en bildvisare.
Plan för bildvisare
- Bildvisaren från förra gången saknade en funktion för att ta bort bilder, vilket gjorde att fönstret blev för litet när man laddade in flera bilder. Låt oss ta bort de oanvända etiketterna.
- Om bildvisaren ska lista flera bilder, låt oss skapa en lista.
- Det är bäst att ladda flera bilder samtidigt.
- Låt oss också implementera 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.
Modifierat Tcl/Tk 9.0-bibliotek
Det befintliga biblioteket har en bristfällig implementering av Listbox, 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 tillagda funktionerna.
Innan vi går igenom de nya funktionerna, låt oss kort förstå strukturen hos 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 skicka operationen i Tcl-skriptformat till funktionen evalErr. Det betyder att för att implementera önskad funktionalitet behöver man bara skicka kommandot i motsvarande Tcl-skriptformat.
Låt oss som exempel implementera en metod för att lägga till objekt i en Listbox. Först, för Tcl-skriptning, låt oss titta på insert bland de kommandon som är tillgängliga för listbox i den officiella manualen.
Om man tittar på beskrivningssidan för insert-kommandot, infogar insert listade objekt vid ett specifikt index. Då kan vi skriva följande kod för att implementera detta:
1func (l *ListboxWidget) AddItem(index int, items string) {
2 evalErr(fmt.Sprintf("%s insert %d %s", l.fpath, index, items))
3}
och så vidare.
Nu när vi har en allmän förståelse för implementeringsprincipen, kommer jag att 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, avgränsade med mellanslag, från index 0 i ordning. 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
Nu ska vi hämta och kontrollera de valda objekten i 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 vid det angivna indexet. Resultatet kan ses i konsolutskriften. Observera att den liknande metoden Get tar start- och slutindex och hämtar alla objekt inom intervallet.
Därefter ska vi ändra färgerna 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 det skrevs i koden ovan har höjden ökats. Dessutom kan man se att färgerna har applicerats korrekt. Eftersom ett alternativ är specificerat för att ändra färgen endast för ett specifikt objekt, kan man se att endast den första raden har en annan färg.
Även om det inte är en stor skillnad, kan Relief-metoden användas för att ändra kantstilen på widgeten till flat, groove, raise, ridge, solid eller sunken.
Exempel på bildvisare
Låt oss nu skapa en bildvisare med hjälp av de widgetar vi just lärt oss. Exempelprogrammet är som följer:
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)) //Aktivera flerval och slå på filtret.
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 temanamn 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ägg 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, förbereds alla bild-widgets i förväg när de laddas in, och dubbla filer kontrolleras inte. Du kan förbättra de problem som nämndes tidigare, och du kan också försöka ändra temat med DefaultTheme-metoden, som är utkommenterad. Försök att öva genom att skapa ett nytt program som förbättrar dessa aspekter.
Sammanfattning
I den här artikeln har vi undersökt hur Go-språkets Tcl/Tk-bibliotek anropar kommandon och skapat en bildvisare med en Listbox.
- Tcl/Tk-bibliotekets kommandoanropsmetod
- 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.