GoSuda

Creazione di un visualizzatore di immagini con l'aggiunta di un elenco di file da Go a Tk

By Yunjin Lee
views ...

Nel precedente post, abbiamo esaminato brevemente la libreria CGo-Free Tcl/Tk. Questa volta, utilizzeremo l'esempio precedente per creare un visualizzatore di immagini.

Piano del visualizzatore di immagini

  1. Il visualizzatore di immagini dell'ultima volta non aveva una funzione di eliminazione delle immagini, quindi più immagini venivano caricate, più la dimensione della finestra diventava insufficiente. Eliminiamo le Label non utilizzate.
  2. Se intendiamo elencare più immagini nel visualizzatore di immagini, creiamo una List.
  3. È consigliabile caricare più immagini contemporaneamente.
  4. Implementiamo anche la rimozione delle immagini che non verranno visualizzate dalla List.
  5. Creiamo una funzione per selezionare e visualizzare un'immagine specifica tra più immagini.

Libreria Tcl/Tk 9.0 modificata

La libreria esistente ha un'implementazione inadeguata di Listbox, rendendo difficile la visualizzazione di un elenco di immagini. Scarichiamo la libreria modificata. Se Git CLI non è installato, è possibile scaricare il tarball o il file zip.

1git clone https://github.com/gg582/tk9.0

Esaminiamo innanzitutto alcune delle funzionalità aggiunte.

Prima di esaminare le nuove funzioni, cerchiamo di comprendere brevemente la struttura delle funzioni esistenti attraverso la funzione Destroy alla riga 1017 di tk.go.

1func Destroy(options ...Opt) {
2	evalErr(fmt.Sprintf("destroy %s", collect(options...)))
3}

Questa funzione è implementata passando l'operazione in formato script Tcl a una funzione chiamata evalErr. Ciò significa che, per implementare la funzionalità desiderata, è sufficiente passare il comando nel formato dello script Tcl corrispondente.

Ad esempio, implementiamo un metodo per aggiungere elementi a una Listbox. Per prima cosa, per lo scripting Tcl, esaminiamo il comando insert tra quelli disponibili per Listbox nel manuale ufficiale.

Comando insert

La pagina di descrizione del comando insert mostra che insert inserisce gli elementi elencati in un indice specifico. Quindi, per implementare ciò,

1func (l *ListboxWidget) AddItem(index int, items string) {
2	evalErr(fmt.Sprintf("%s insert %d %s", l.fpath, index, items))
3}

è possibile scrivere un codice simile a questo.

Ora che abbiamo compreso il principio di implementazione generale, spiegheremo le funzionalità aggiuntive per Listbox.

List: Inserimento/Eliminazione

 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

Nel programma sopra, AddItem inserisce elementi distinti separati da spazi, in ordine a partire dall'indice 0. item1-item3 avranno rispettivamente gli indici 0, 1, 2. Eseguiamo l'esempio per capire come funziona l'eliminazione degli elementi.

List: Recupero degli elementi selezionati

Ora recuperiamo e verifichiamo gli elementi selezionati nella 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}

Il metodo Selected recupera gli indici di tutti gli elementi attualmente selezionati nella Listbox. Il metodo GetOne recupera il valore dell'elemento corrispondente a quell'indice. Il risultato è visibile nell'output della console. Si noti che il metodo simile Get recupera i valori di tutti gli elementi all'interno di un intervallo, accettando indici di inizio e fine.

Successivamente, cambiamo il colore della Listbox.

Prima, esaminiamo l'esempio seguente.

 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}

Risultato dell'applicazione del colore

Come scritto nel codice sopra, l'altezza è aumentata. Inoltre, si può notare che i colori sono stati applicati correttamente. Qui è stata specificata un'opzione per colorare solo un elemento specifico, quindi si può vedere che solo la prima riga ha un colore diverso.

Inoltre, sebbene non ci sia una grande differenza, utilizzando il metodo Relief è possibile modificare lo stile del bordo del widget tra flat, groove, raise, ridge, solid, sunken.

Esempio di visualizzatore di immagini

Ora, utilizzando i widget appresi in precedenza, creeremo un visualizzatore di immagini. Il programma di esempio è il seguente.

  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)) // Attiva la selezione multipla e i filtri.
 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    // Specificare il nome e il percorso del tema se si desidera utilizzarlo.
139    fileMenu := menubar.Menu()
140    extensions = make([]FileType,0,1)
141    extensions = append(extensions, FileType{ "Supported Images", []string {".png",".ico"}, "" } )
142    // Aggiungi png e ico ai filtri.
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

Risultato dell'esecuzione del visualizzatore di immagini

In questo esempio, per semplificare l'implementazione, tutti i widget immagine vengono creati in anticipo quando vengono caricati, e non viene controllata la presenza di file duplicati. È possibile migliorare i problemi menzionati in precedenza, e provare a cambiare il tema utilizzando il metodo DefaultTheme, che è commentato. Si prega di esercitarsi creando un nuovo programma che migliori questi aspetti.

Riepilogo

In questo articolo, abbiamo esaminato come funziona la chiamata dei comandi nella libreria Tcl/Tk del linguaggio Go, e abbiamo creato un visualizzatore di immagini con l'aggiunta di una Listbox.

  1. Metodo di chiamata dei comandi della libreria Tcl/Tk
  2. Come usare la Listbox
  3. Modifica delle proprietà del widget Listbox
  4. Creazione di un visualizzatore di immagini

In questo modo, si prega di provare a modificare altre librerie e a scrivere programmi completi con le funzionalità aggiunte.