Créer un visualiseur d'images avec liste de fichiers de Go vers Tk
Dans le billet précédent, nous avons brièvement examiné la bibliothèque CGo-Free Tcl/Tk. Cette fois-ci, nous allons créer une visionneuse d'images en appliquant l'exemple précédent.
Plan de la visionneuse d'images
- L'afficheur d'images de la dernière fois ne disposait pas de fonction de suppression d'images, ce qui entraînait un manque d'espace dans la fenêtre à mesure que plusieurs images étaient chargées. Supprimons les étiquettes inutilisées.
- Si vous souhaitez lister plusieurs images dans l'afficheur d'images, créons une liste.
- Il est préférable de charger plusieurs images à la fois.
- Implémentons également la suppression des images indésirables de la liste.
- Créons une fonction permettant de sélectionner et de visualiser une image spécifique parmi plusieurs images.
Bibliothèque Tcl/Tk 9.0 modifiée
L'implémentation de Listbox dans la bibliothèque existante est insuffisante, ce qui rend difficile l'affichage d'une liste d'images. Téléchargeons la bibliothèque modifiée. Si Git CLI n'est pas installé, vous pouvez la télécharger sous forme de tarball ou de fichier zip.
1git clone https://github.com/gg582/tk9.0
Examinons d'abord quelques-unes des fonctionnalités ajoutées.
Avant d'examiner les nouvelles fonctions, voyons comment les fonctions existantes sont structurées en examinant la fonction Destroy à la ligne 1017 de tk.go.
1func Destroy(options ...Opt) {
2 evalErr(fmt.Sprintf("destroy %s", collect(options...)))
3}
Cette fonction est implémentée en transmettant l'opération au format script Tcl à la fonction evalErr. Cela signifie que pour implémenter la fonctionnalité souhaitée, il suffit de transmettre la commande au format script Tcl correspondant.
Par exemple, implémentons une méthode pour ajouter des éléments à une Listbox. Commençons par examiner l'instruction insert parmi les commandes disponibles pour listbox dans le manuel officiel pour le script Tcl.
La page de description de la commande insert indique qu'insert insère les éléments listés à un index spécifique. Nous pouvons donc écrire un code tel que
1func (l *ListboxWidget) AddItem(index int, items string) {
2 evalErr(fmt.Sprintf("%s insert %d %s", l.fpath, index, items))
3}
pour l'implémenter.
Maintenant que nous connaissons le principe général d'implémentation, je vais expliquer les fonctionnalités supplémentaires pour Listbox.
Liste : Insertion/Suppression
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
Dans le programme ci-dessus, AddItem insère des éléments distincts, séparés par des espaces, à partir de l'index 0 dans l'ordre. Les éléments item1-item3 auront respectivement les index 0, 1 et 2. Exécutez l'exemple pour comprendre comment fonctionne la suppression d'éléments.
Liste : Récupération des éléments sélectionnés
Nous allons maintenant récupérer et vérifier les éléments sélectionnés dans la 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}
La méthode Selected récupère les index de tous les éléments actuellement sélectionnés dans la Listbox. La méthode GetOne récupère la valeur de l'élément correspondant à cet index. Le résultat est visible dans la console. À titre de référence, la méthode similaire Get prend un index de début et de fin et récupère les valeurs de tous les éléments dans la plage.
Ensuite, nous allons changer la couleur de la Listbox.
Commençons par examiner l'exemple ci-dessous.
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}
Comme écrit dans le code ci-dessus, la hauteur a augmenté. De plus, on peut voir que les couleurs ont été bien appliquées. Ici, une option a été spécifiée pour colorer différemment certains éléments, on peut voir que seule la première ligne a des couleurs différentes.
De plus, bien qu'il n'y ait pas de grande différence, la méthode Relief permet de modifier le style de la bordure du widget parmi flat, groove, raise, ridge, solid, sunken.
Exemple de visionneuse d'images
Nous allons maintenant créer une visionneuse d'images en utilisant les widgets que nous avons appris. Le programme d'exemple est le suivant :
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)) // Active la sélection multiple et les filtres.
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 // Spécifie le nom et le chemin du thème si vous souhaitez l'utiliser.
139 fileMenu := menubar.Menu()
140 extensions = make([]FileType,0,1)
141 extensions = append(extensions, FileType{ "Supported Images", []string {".png",".ico"}, "" } )
142 // Ajoute png et ico aux filtres.
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
Dans cet exemple, pour simplifier l'implémentation, tous les widgets d'image sont créés à l'avance lors du chargement, et les fichiers en double ne sont pas vérifiés. Vous pouvez améliorer les problèmes mentionnés précédemment, ou essayer de changer le thème en utilisant la méthode DefaultTheme, qui est commentée. Veuillez vous entraîner en créant un nouveau programme qui améliore ces aspects.
Résumé
Dans cet article, nous avons appris comment les appels de commande de la bibliothèque Tcl/Tk de Go fonctionnent, et avons créé une visionneuse d'images avec une Listbox ajoutée.
- Méthode d'appel de commande de la bibliothèque Tcl/Tk
- Comment utiliser une Listbox
- Modification des propriétés du widget Listbox
- Création d'une visionneuse d'images
De cette manière, veuillez essayer de modifier d'autres bibliothèques et de créer des programmes complets avec les fonctionnalités ajoutées.