Création d'une visionneuse d'images avec liste de fichiers ajoutée de Go à Tk
Dans le précédent billet, nous avons brièvement examiné la bibliothèque Tcl/Tk CGo-Free. Dans cette session, nous allons créer une visionneuse d'images en appliquant l'exemple précédent.
Plan de la visionneuse d'images
- Le visualiseur d'images de la dernière fois manquait de fonctionnalité de suppression, ce qui signifiait que plus on chargeait d'images, plus la taille de la fenêtre était insuffisante. Supprimons les Labels inutilisés.
- Si nous voulons lister plusieurs images dans le visualiseur 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 télécharger un fichier tarball ou 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, nous allons comprendre la structure des fonctions existantes à travers 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 sous forme de script Tcl à la fonction evalErr. Cela signifie que pour implémenter la fonctionnalité souhaitée, il suffit de transmettre la commande dans le format de script Tcl correspondant.
Par exemple, implémentons une méthode pour ajouter un élément à une Listbox. Tout d'abord, pour le script Tcl, examinons la commande insert parmi les commandes disponibles pour la Listbox dans le manuel officiel.
La page de description de la commande insert indique qu'elle insère des éléments listés à un index spécifique. Pour l'implémenter, nous pouvons écrire le code suivant :
1func (l *ListboxWidget) AddItem(index int, items string) {
2 evalErr(fmt.Sprintf("%s insert %d %s", l.fpath, index, items))
3}
Maintenant que nous avons une compréhension générale du principe 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 différents, séparés par des espaces, à partir de l'index 0. Les éléments item1-item3 auront respectivement les index 0, 1, 2. Exécutez l'exemple pour comprendre comment fonctionne la suppression d'éléments.
Liste : Récupération des éléments sélectionnés
Maintenant, nous allons récupérer les éléments sélectionnés dans la Listbox et les vérifier.
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 à l'index donné. Le résultat affiché dans la console le confirmera. À noter que la méthode similaire Get prend les index de début et de fin pour récupérer toutes les valeurs des é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 différencier la couleur de certains éléments, ce qui fait que seule la première ligne a une couleur différente.
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écifiez 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 // Ajoutez 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 à créer un nouveau programme qui améliore ces aspects.
Résumé
Dans cet article, nous avons examiné comment fonctionnent les appels de commande de la bibliothèque Tcl/Tk de Go, et créé une visionneuse d'images avec l'ajout d'une Listbox.
- Méthode d'appel de commande de la bibliothèque Tcl/Tk
- Utilisation de la 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 d'écrire des programmes complets avec les fonctionnalités ajoutées.