GoSuda

Изграждане на програма за преглед на изображения с добавен файлов списък в Go с Tk

By Yunjin Lee
views ...

В предишната публикация разгледахме накратко библиотеката CGo-Free Tcl/Tk. Този път ще използваме примера от предишния урок, за да създадем програма за преглед на изображения.

Планиране на програма за преглед на изображения

  1. Прегледът на изображения от миналия път нямаше функция за изтриване на изображения, така че колкото повече изображения се зареждаха, толкова по-малък ставаше размерът на прозореца. Нека изтрием неизползваните Label-и.
  2. Ако ще изброяваме няколко изображения в прегледа на изображения, нека създадем List.
  3. Препоръчително е да зареждате няколко изображения едновременно.
  4. Нека също така имплементираме премахване на изображения, които няма да се преглеждат, от List-а.
  5. Нека създадем функция за избор и преглед на конкретно изображение от множество изображения.

Модифицирана библиотека Tcl/Tk 9.0

Съществуващата библиотека има недостатъчно реализация на Listbox, което затруднява показването на списък с изображения. Нека изтеглим модифицираната библиотека. Ако Git CLI не е инсталиран, можете да изтеглите tarball или zip файл.

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

Първо, нека разгледаме някои от добавените функции.

Преди да разгледаме новите функции, нека накратко разберем структурата на съществуващите функции чрез функцията Destroy на ред 1017 в tk.go.

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

Тази функция е имплементирана чрез предаване на операцията във формат на Tcl скрипт към функцията evalErr. Това означава, че за да се имплементира желаната функционалност, е необходимо само да се предаде командата във формат на съответния Tcl скрипт.

Например, нека имплементираме метод за добавяне на елементи към Listbox. Първо, за Tcl скриптиране, нека разгледаме командата insert сред командите, налични за Listbox в официалното ръководство.

Команда insert

Страницата с описание на командата insert показва, че insert вмъква изброени елементи в определен индекс. Следователно, за да се имплементира това, може да се напише следният код:

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

Сега, след като разбираме общия принцип на имплементация, ще обясня допълнителните функции за Listbox.

Списък: Вмъкване/Изтриване

 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

В горната програма AddItem добавя различни елементи, разделени с интервали, последователно от индекс 0. item1-item3 ще имат индекси 0, 1, 2 съответно. Изпълнете примера, за да разберете как работи изтриването на елементи.

Списък: Извличане на избрани елементи

Сега ще извлечем и проверим избраните елементи от 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 извлича индексите на всички елементи, избрани в текущия Listbox. Методът GetOne извлича стойността на елемента, съответстващ на дадения индекс. Резултатът може да бъде видян в конзолата. Забележете, че подобният метод Get приема начален и краен индекс и извлича стойностите на всички елементи в диапазона.

Следващата стъпка е да променим цвета на Listbox.

Първо, нека разгледаме примера по-долу.

 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}

Резултат от прилагане на цвят

Както е написано в горния код, височината е увеличена. Също така, вижда се, че цветовете са приложени добре. Тук е зададена опция за различен цвят само за конкретен елемент, така че само първият ред е оцветен по различен начин.

Освен това, макар и без голяма разлика, методът Relief може да се използва за промяна на стила на рамката на Widget между flat, groove, raise, ridge, solid, sunken.

Пример за програма за преглед на изображения

Сега ще създадем програма за преглед на изображения, използвайки Widget-ите, които научихме по-рано. Примерната програма е следната:

  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)) //Активира множество избори и включва филтри.
 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    //За да използвате тема, задайте името на темата и пътя.
139    fileMenu := menubar.Menu()
140    extensions = make([]FileType,0,1)
141    extensions = append(extensions, FileType{ "Supported Images", []string {".png",".ico"}, "" } )
142    //Добавете png и ico към филтъра.
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

Резултат от изпълнение на програма за преглед на изображения

В този пример, за да се опрости имплементацията, всички Widget-и за изображения се зареждат предварително и не се проверяват за дублиращи се файлове. Можете да подобрите гореспоменатите проблеми или да опитате да промените темата, използвайки коментираната част от метода DefaultTheme. Моля, упражнете се, като създадете нова програма, която подобрява тези аспекти.

Обобщение

В тази статия разгледахме как работи извикването на команди в библиотеката Tcl/Tk на езика Go и създадохме програма за преглед на изображения с добавен Listbox.

  1. Метод за извикване на команди в библиотеката Tcl/Tk
  2. Как да използвате Listbox
  3. Промяна на свойствата на Listbox Widget
  4. Създаване на програма за преглед на изображения

По този начин, моля, опитайте да модифицирате други библиотеки и да напишете завършени програми с добавените функции.