GoSuda

Crearea unui vizualizator de imagini cu o listă de fișiere adăugată din Go în Tk

By Yunjin Lee
views ...

În postarea anterioară, am prezentat pe scurt biblioteca CGo-Free Tcl/Tk. De data aceasta, vom construi un vizualizator de imagini aplicând exemplul anterior.

Planul vizualizatorului de imagini

  1. Vizualizatorul de imagini anterior nu avea o funcție de ștergere a imaginilor, astfel că, pe măsură ce erau încărcate mai multe imagini, dimensiunea ferestrei devenea insuficientă. Să ștergem etichetele neutilizate.
  2. Dacă intenționăm să listăm mai multe imagini în vizualizatorul de imagini, să creăm o listă.
  3. Este de preferat să încărcăm mai multe imagini simultan.
  4. Să implementăm și funcționalitatea de eliminare a imaginilor nedorite din listă.
  5. Să creăm o funcție pentru a selecta și vizualiza o anumită imagine dintr-o selecție de imagini multiple.

Biblioteca Tcl/Tk 9.0 modificată

Implementarea Listbox-ului în biblioteca existentă este deficitară, ceea ce face dificilă afișarea unei liste de imagini. Să descărcăm biblioteca modificată. Dacă Git CLI nu este instalat, puteți descărca și ca fișier tarball sau zip.

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

Să examinăm mai întâi câteva dintre funcțiile adăugate.

Înainte de a examina noile funcții, să înțelegem structura generală a funcțiilor existente prin intermediul funcției Destroy de la linia 1017 din tk.go.

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

Această funcție este implementată prin transmiterea unei operații sub formă de script Tcl către funcția evalErr. Aceasta înseamnă că, pentru a implementa funcționalitatea dorită, este suficient să transmiteți comanda în formatul scriptului Tcl corespunzător.

Ca exemplu, să implementăm o metodă pentru a adăuga un element la o casetă de listă. Mai întâi, pentru scriptarea Tcl, să examinăm comanda insert disponibilă pentru listbox în manualul oficial.

Comanda insert

Pagina de descriere a comenzii insert arată că insert inserează elemente listate la un anumit index. Prin urmare, pentru a implementa acest lucru,

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

se poate scrie un cod similar.

Acum că am înțeles principiul general de implementare, voi explica mai întâi funcționalitățile suplimentare pentru Listbox.

Listă: Inserare/Ștergere

 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

În programul de mai sus, AddItem inserează elemente diferite, separate prin spații, începând cu indexul 0.item1-item3 vor avea indicii 0, 1, 2, respectiv. Rulați exemplul pentru a înțelege cum funcționează ștergerea elementelor.

Listă: Obținerea elementelor selectate

Acum, să obținem și să verificăm elementele selectate din 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}

Metoda Selected preia indicii tuturor elementelor selectate în prezent în Listbox. Metoda GetOne preia valoarea elementului corespunzător indicelui respectiv. Acest lucru poate fi observat din rezultatul afișat în consolă. Ca referință, metoda similară Get preia indicii de început și de sfârșit și preia toate valorile elementelor din interval.

Apoi, vom schimba culoarea casetei de listă.

Mai întâi, să examinăm exemplul de mai jos.

 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}

Rezultatul aplicării culorilor

Așa cum este scris în codul de mai sus, înălțimea a fost mărită. De asemenea, se poate observa că culorile au fost aplicate corect. Aici, este specificată o opțiune pentru a aplica culori diferite doar anumitor elemente, deci se observă că doar prima linie are o culoare diferită.

De asemenea, deși nu este o diferență mare, utilizarea metodei Relief permite modificarea stilului bordurii widget-ului între flat, groove, raise, ridge, solid, sunken.

Exemplu de vizualizator de imagini

Acum, să creăm un vizualizator de imagini folosind widget-urile pe care le-am învățat mai devreme. Programul exemplu este următorul:

  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)) // Activează selecția multiplă și filtrele.
 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    // Specificați numele temei și calea atunci când doriți să utilizați o temă.
139    fileMenu := menubar.Menu()
140    extensions = make([]FileType,0,1)
141    extensions = append(extensions, FileType{ "Supported Images", []string {".png",".ico"}, "" } )
142    // Adaugă png și ico la filtru.
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

Rezultatul rulării vizualizatorului de imagini

În acest exemplu, pentru a simplifica implementarea, toate widget-urile de imagine sunt create în prealabil la încărcare și nu se verifică fișierele duplicate. Puteți îmbunătăți problemele menționate anterior sau puteți schimba tema utilizând metoda DefaultTheme, care este comentată. Vă rugăm să exersați creând un nou program care îmbunătățește aceste aspecte.

Rezumat

În acest articol, am explorat modul în care funcționează apelurile de comandă ale bibliotecii Go Tcl/Tk și am creat un vizualizator de imagini cu un Listbox adăugat.

  1. Metoda de apelare a comenzilor din biblioteca Tcl/Tk
  2. Cum se utilizează Listbox
  3. Modificarea proprietăților widget-ului Listbox
  4. Crearea unui vizualizator de imagini

În mod similar, vă încurajăm să încercați să modificați alte biblioteci și să scrieți programe complete cu funcționalitățile adăugate.