GoSuda

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

By Yunjin Lee
views ...

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

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

  1. Прегледът на изображения от предишния път нямаше функция за изтриване на изображения, така че колкото повече изображения се зареждаха, толкова по-малък ставаше размерът на прозореца. Нека изтрием неизползваните Label-и.
  2. Ако ще изброяваме няколко изображения в прегледа на изображения, нека създадем списък.
  3. Добре е да заредите няколко изображения наведнъж.
  4. Нека също така да реализираме функция за премахване на изображения, които няма да се гледат, от списъка.
  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. Създаване на преглед на изображения

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