Go: GUI

Вопросы написания собственного программного кода (на любых языках)

Модератор: Olej

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Go: GUI

Непрочитанное сообщение Olej » 13 май 2017, 22:58

Эта тема переползла вот отсюда: cборка приложений Go:
я с удовольствием поучавствую в ней, поделюсь своим скромным опытом работы в Go с пакетами, обеспечивающими доступ к Tcl/Tk. Наверняка в процессе обсуждения вскроются новые интересные вещи
Нам обещают рассказать очень любопытные вещи :lol:
И я очень надеюсь, что не только рассказать "на пальцах", а показать примеры работающего кода на Go.

Аватара пользователя
perseus
Писатель
Сообщения: 99
Зарегистрирован: 11 май 2017, 18:01
Откуда: Щёлково, Московская обл.
Контактная информация:

Re: GUI на Go

Непрочитанное сообщение perseus » 14 май 2017, 13:20

Поскольку у Go нет своих средств писать графический интерфейс пользователя (ГИП или GUI кому как привычнее), я решил использовать библиотеку Tk для этих целей (не забыть загрузить dev-пакеты с заголовочными файлами, они потребуются для сборки пакетов для go).
На github.com нашёл несколько пакетов для Go, которые позволяют пользоваться средствами Tcl/Tc. Например gothic или go-tk. :-) Там также имеются пакеты и для Qt и Gtk, кому что больше нравится.
Мне больше нравится Tcl/Tk, потому и выбрал эти библиотеки.
Ниже привожу код небольшой демонстрационной программки, в которой реализован ГИП посредством использоваиня пакета "github.com/edartuz/go-tk/gotk". Это был мой первый опыт, прошу не судить строго.
С установкой пакета пришлось помучиться, поскольку я ставил компилятор go не из репозитория, а своми руками с сайта golang.org, при установке пакета gotk компилятор go не мог найти некоторые заголовочные фалы( tcl.h tk.h X11 и др.), пришлось подсунуть их ему в директорию.

Код: Выделить всё

// Демонстрационная программка возможностей пакета "github.com/edartuz/go-tk/gotk"
// обеспечивающего доступ из программы написанной на Go к средствам Tcl/Tk
// Для её работы необходима установка в системе библиотек Tcl и Tk
// ===============================================================
// программа организована из двух потоков:
// main - главный поток в котором реализован GUI
// imit - второй вспомогательный поток, выполняющий всю основную работу приложения
// и обменивающийся командами Tcl с главным потокм посредством команды Tcl "thread::send"
// ---------------------------------------------------------------
// запускается imit кнопкой "Start" из GUI программы
// для остановки вспомогательного потока imit при нажатии кнопки "Stop" используется канал abort
// ===============================================================
// поскольку это демоверсия, imit совсем маленкиий...

package main

import (
	"fmt"
	"github.com/edartuz/go-tk/gotk"
	"log"
	"os"
	"strconv"
)

//переменные для хранения каналов сообщений о прерывании работы программы и передачи данных
var abort chan struct{}
var chng chan changes //канал для передачи в imit состояния тех.средств
var imitWork bool     // флаг работы imit
var treadId string    // идентификатор материнского потока

// структура для передачи в imit состояния тех.средств
type changes struct {
	kpdNumb, forKs1, forKs2, forKs3, forKs4 byte
}

func main() {
	//init Tcl and Tk
	if !gotk.Init(true) {
		os.Exit(0)
	}
	//загружаем пакет для работы с потоками
	gotk.Eval(`package require Thread`)

	// определяем идентификатор потока и записываем его в переменную
	// для дальнейшей передачи его в imit, чтобы он мог обмениваться командами с GUI
	gotk.Eval(`	set id [thread::names]
				puts "Mine thread id: $id"`)
	threadId := gotk.GetVar("id") // выводим значение идентификатора потока

	//set window geometry
	gotk.Tk.Wm(".", "geometry", "=550x150+1100+30")
	gotk.Tk.Wm(".", "title", "{Демонстрация GUI}")

	// кнопка старта работы имитатора
	start := gotk.Tk.New("button", ".start", //set type, id (empty string for automatic generation
		"text", "START", //set other parameters
		"fg", "white",
		"bg", "green",
		"width", 10,
		"justify", "right",
		"relief", "groove",
		"state", "normal").
		Pack("grid", ".", //pack in root window
			"column", 0,
			"row", 7,
		)
	stop := gotk.Tk.New("button", ".stop", //кнопка остановки работы имитатора
		"text", "STOP", //set other parameters
		"fg", "white",
		"bg", "red",
		"width", 10,
		"justify", "right",
		"relief", "groove",
		"state", "disabled").
		Pack("grid", ".", //pack in root window
			"column", 3,
			"row", 7,
		)
	///// Метка состояния связи с аппаратурой ВК //////////////////
	vk := gotk.Tk.New("label", ".vk",
		"text", "{Связь с ВК}",
		"width", 10,
		"bg", "red",
		"fg", "white")
	vk.Pack("grid", ".",
		"column", 1,
		"row", 7,
	)
	//// Отображение переменных тех.средств для checbuttons на имена каналов
	matr := map[string][]string{
		"ks1": {"on_udp1", "on_sa1", "on_ups1", "on_line1"},
		"ks2": {"on_udp2", "on_sa2", "on_ups2", "on_line2"},
		"ks3": {"on_udp3", "on_sa3", "on_ups3", "on_line3"},
		"ks4": {"on_udp4", "on_sa4", "on_ups4", "on_line4"},
	}
	/////////////// Команды для кнопок ////////////////////////
	start.Cmd("command", func() { //set callback function
		fmt.Println("======================= Start imit ==================================")
		start.CSet("bg", "red", "state", "disabled")
		stop.CSet("bg", "green", "state", "normal")
		abort = make(chan struct{}) //канал сообщения о прерывании работы программы
		chng = make(chan changes, 16)
		go imit(threadId, chng, abort)
		imitWork = true
	})
	stop.Cmd("command", func() { //set callback function
		fmt.Println("************************ Stop imit **********************************")
		start.CSet("bg", "green", "state", "normal")
		stop.CSet("bg", "red", "state", "disabled")
		vk.CSet("bg", "red")
		imitWork = false
		close(chng)
		close(abort)
		for key, lvals := range matr {
			switch key {
			case "ks1":
				if checkVals(lvals) == 4 {
					gotk.Eval(`.fr.chan1 config -text И`)
				} else {
					gotk.Eval(`.fr.chan1 config -text Н`)
				}
			case "ks2":
				if checkVals(lvals) == 4 {
					gotk.Eval(`.fr.chan2 config -text И`)
				} else {
					gotk.Eval(`.fr.chan2 config -text Н`)
				}
			case "ks3":
				if checkVals(lvals) == 4 {
					gotk.Eval(`.fr.chan3 config -text И`)
				} else {
					gotk.Eval(`.fr.chan3 config -text Н`)
				}
			case "ks4":
				if checkVals(lvals) == 4 {
					gotk.Eval(`.fr.chan4 config -text И`)
				} else {
					gotk.Eval(`.fr.chan4 config -text Н`)
				}
			}
		}
	})
	//////////// Checkbuttons ////////////////////////////
	// frame checkbuttons и заголовок
	gotk.Eval(`	frame .fr -borderwidth 5  
				grid  .fr -column 1 -row 0
				label .fr.channals -text КаналЫ 
				grid  .fr.channals -column 0 -row 0 
				label .fr.upds -text УПД 
				grid  .fr.upds -column 1 -row 0
				label .fr.sas -text ММ 
				grid  .fr.sas -column 2 -row 0
				label .fr.upss -text УПС 
				grid  .fr.upss -column 3 -row 0
				label .fr.lines -text ЛиниИ 
				grid  .fr.lines -column 4 -row 0`)
	///// УПД checkbuttons //////////////
	gotk.SetVar(matr["ks1"][0], 0)
	gotk.SetVar(matr["ks2"][0], 0)
	gotk.SetVar(matr["ks3"][0], 0)
	gotk.SetVar(matr["ks4"][0], 0)
	upd1 := `checkbutton .fr.upd1 -text УПД1 -variable ` + matr["ks1"][0]
	upd2 := `checkbutton .fr.upd2 -text УПД2 -variable ` + matr["ks2"][0]
	upd3 := `checkbutton .fr.upd3 -text УПД3 -variable ` + matr["ks3"][0]
	upd4 := `checkbutton .fr.upd4 -text УПД4 -variable ` + matr["ks4"][0]
	gotk.Eval(upd1)
	gotk.Eval(upd2)
	gotk.Eval(upd3)
	gotk.Eval(upd4)
	gotk.Eval(`grid .fr.upd1 -column 1 -row 1`)
	gotk.Eval(`grid .fr.upd2 -column 1 -row 2`)
	gotk.Eval(`grid .fr.upd3 -column 1 -row 3`)
	gotk.Eval(`grid .fr.upd4 -column 1 -row 4`)
	//// ММ checkbuttons ////////////////
	gotk.SetVar(matr["ks1"][1], 0)
	gotk.SetVar(matr["ks2"][1], 0)
	gotk.SetVar(matr["ks3"][1], 0)
	gotk.SetVar(matr["ks4"][1], 0)
	sa1 := `checkbutton .fr.sa1 -text ММ1 -variable ` + matr["ks1"][1]
	sa2 := `checkbutton .fr.sa2 -text ММ2 -variable ` + matr["ks2"][1]
	sa3 := `checkbutton .fr.sa3 -text ММ3 -variable ` + matr["ks3"][1]
	sa4 := `checkbutton .fr.sa4 -text ММ4 -variable ` + matr["ks4"][1]
	gotk.Eval(sa1)
	gotk.Eval(sa2)
	gotk.Eval(sa3)
	gotk.Eval(sa4)
	gotk.Eval(`grid .fr.sa1 -column 2 -row 1`)
	gotk.Eval(`grid .fr.sa2 -column 2 -row 2`)
	gotk.Eval(`grid .fr.sa3 -column 2 -row 3`)
	gotk.Eval(`grid .fr.sa4 -column 2 -row 4`)
	//// УПС checkbuttons ///////////////
	gotk.SetVar(matr["ks1"][2], 0)
	gotk.SetVar(matr["ks2"][2], 0)
	gotk.SetVar(matr["ks3"][2], 0)
	gotk.SetVar(matr["ks4"][2], 0)
	ups1 := `checkbutton .fr.ups1 -text УПС1 -variable ` + matr["ks1"][2]
	ups2 := `checkbutton .fr.ups2 -text УПС2 -variable ` + matr["ks2"][2]
	ups3 := `checkbutton .fr.ups3 -text УПС3 -variable ` + matr["ks3"][2]
	ups4 := `checkbutton .fr.ups4 -text УПС4 -variable ` + matr["ks4"][2]
	gotk.Eval(ups1)
	gotk.Eval(ups2)
	gotk.Eval(ups3)
	gotk.Eval(ups4)
	gotk.Eval(`grid .fr.ups1 -column 3 -row 1`)
	gotk.Eval(`grid .fr.ups2 -column 3 -row 2`)
	gotk.Eval(`grid .fr.ups3 -column 3 -row 3`)
	gotk.Eval(`grid .fr.ups4 -column 3 -row 4`)
	//// Линии связи checkbuttons //////
	gotk.SetVar(matr["ks1"][3], 0)
	gotk.SetVar(matr["ks2"][3], 0)
	gotk.SetVar(matr["ks3"][3], 0)
	gotk.SetVar(matr["ks4"][3], 0)
	line1 := `checkbutton .fr.line1 -text Линия1 -variable ` + matr["ks1"][3]
	line2 := `checkbutton .fr.line2 -text Линия2 -variable ` + matr["ks2"][3]
	line3 := `checkbutton .fr.line3 -text Линия3 -variable ` + matr["ks3"][3]
	line4 := `checkbutton .fr.line4 -text Линия4 -variable ` + matr["ks4"][3]
	gotk.Eval(line1)
	gotk.Eval(line2)
	gotk.Eval(line3)
	gotk.Eval(line4)
	gotk.Eval(`grid .fr.line1 -column 4 -row 1`)
	gotk.Eval(`grid .fr.line2 -column 4 -row 2`)
	gotk.Eval(`grid .fr.line3 -column 4 -row 3`)
	gotk.Eval(`grid .fr.line4 -column 4 -row 4`)
	//// Каналы связи checkbuttons //////
	chan1 := `label .fr.chan1 -text {Н} -bg red -fg white`
	chan2 := `label .fr.chan2 -text {Н} -bg red -fg white`
	chan3 := `label .fr.chan3 -text {Н} -bg red -fg white`
	chan4 := `label .fr.chan4 -text {Н} -bg red -fg white`
	gotk.Eval(chan1)
	gotk.Eval(chan2)
	gotk.Eval(chan3)
	gotk.Eval(chan4)
	gotk.Eval(`grid .fr.chan1 -column 0 -row 1`)
	gotk.Eval(`grid .fr.chan2 -column 0 -row 2`)
	gotk.Eval(`grid .fr.chan3 -column 0 -row 3`)
	gotk.Eval(`grid .fr.chan4 -column 0 -row 4`)
	//start main loop
	gotk.Tk.MainLoop()
}

// функция проверяет в канале значения всех переменных состояния тех.средств
// возвращает сумму значений этих переменных
func checkVals(list []string) (ksReady int) {
	var err error
	for v, name := range list {
		if v, err = strconv.Atoi(gotk.GetVar(name)); err != nil {
			log.Fatal("checkVals:", err)
		}
		ksReady += v
	}
	return ksReady
}

////////////////////////////////////////////////////////
////////////////  IMIT  вспомогательный поток //////////
////////////////////////////////////////////////////////
func imit(matherId string, ch chan changes, abrt chan struct{}) {
	log.Println("------------ Imit started --------------")

	// определить идентификаторы существующих потоков
	gotk.Eval(`puts "*** Existing threads: [thread::names]"`)

	// установить переменную с полученным значением идентификатора материнского потока
	gotk.SetVar("id", matherId)

	// отправить команду на изменение label .vk
	gotk.Eval(` thread::send $id [list .vk config -bg green]
				thread::send $id [list .fr.chan4 config -text К -bg green]
			`)
	log.Println("------------ Imit finished --------------")
}

Аватара пользователя
perseus
Писатель
Сообщения: 99
Зарегистрирован: 11 май 2017, 18:01
Откуда: Щёлково, Московская обл.
Контактная информация:

Re: GUI на Go

Непрочитанное сообщение perseus » 14 май 2017, 13:26

Ниже приводится снимок экрана с работающей демонстрационной программой
Вложения
e1.png

Аватара пользователя
perseus
Писатель
Сообщения: 99
Зарегистрирован: 11 май 2017, 18:01
Откуда: Щёлково, Московская обл.
Контактная информация:

Re: GUI на Go

Непрочитанное сообщение perseus » 14 май 2017, 13:34

заинтересованным советую поизучать примеры из пакетов gothic и gotk, выложенных на github.com
там очень доходчиво демонстрируются различные приёмы работы с Tcl/Tk из программы на Go
https://github.com/nsf/gothic
https://github.com/edartuz/go-tk

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: GUI на Go

Непрочитанное сообщение Olej » 14 май 2017, 13:38

perseus писал(а):заинтересованным советую поизучать примеры из пакетов gothic и gotk, выложенных на github.com
там очень доходчиво демонстрируются различные приёмы работы с Tcl/Tk из программы на Go
https://github.com/nsf/gothic
https://github.com/edartuz/go-tk
Очень интересно :!:
Спасибо.

Но есть ещё некоторые уточняющие вопросы.... :oops:

Аватара пользователя
perseus
Писатель
Сообщения: 99
Зарегистрирован: 11 май 2017, 18:01
Откуда: Щёлково, Московская обл.
Контактная информация:

Re: GUI на Go

Непрочитанное сообщение perseus » 14 май 2017, 13:40

Кстати о сборке приложений с ГИП - у меня они получаются динамической сборки и тянут за собой целый список библиотек. Ну я думаю Олег Иванович прояснит нам эту особенность сборки программ Go ;-)

Код: Выделить всё

maksim@ASUS ~/Progy/Go/src/imitator $ go version
go version go1.7 linux/386
maksim@ASUS ~/Progy/Go/src/imitator $ ls -l
итого 112
-rw-r--r-- 1 maksim maksim  7594 апр.  14 15:53 dumpIMIT
-rw-r--r-- 1 maksim maksim  7372 апр.  13 14:01 dumpSHS
-rw-r--r-- 1 maksim maksim 40032 мая    3 14:57 imit.go
-rw-r--r-- 1 maksim maksim 11019 мая   14 12:59 imitguiDemo.go
-rw-r--r-- 1 maksim maksim 13260 мая   14 12:09 imitgui.go
-rw-r--r-- 1 maksim maksim 24353 апр.  25 13:52 imitproto.go
drwx------ 2 maksim maksim  4096 апр.  28 14:15 params
maksim@ASUS ~/Progy/Go/src/imitator $ go build imitguiDemo.go
maksim@ASUS ~/Progy/Go/src/imitator $ ls -l
итого 1864
-rw-r--r-- 1 maksim maksim    7594 апр.  14 15:53 dumpIMIT
-rw-r--r-- 1 maksim maksim    7372 апр.  13 14:01 dumpSHS
-rw-r--r-- 1 maksim maksim   40032 мая    3 14:57 imit.go
-rwxr-xr-x 1 maksim maksim 1793800 мая   14 13:38 imitguiDemo
-rw-r--r-- 1 maksim maksim   11019 мая   14 12:59 imitguiDemo.go
-rw-r--r-- 1 maksim maksim   13260 мая   14 12:09 imitgui.go
-rw-r--r-- 1 maksim maksim   24353 апр.  25 13:52 imitproto.go
drwx------ 2 maksim maksim    4096 апр.  28 14:15 params
maksim@ASUS ~/Progy/Go/src/imitator $ file imitguiDemo
imitguiDemo: ELF 32-bit LSB  executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=0cdc74766354eb4b891e9411bd2856ef36c9cebb, not stripped
maksim@ASUS ~/Progy/Go/src/imitator $ ldd imitguiDemo
	linux-gate.so.1 =>  (0xb77be000)
	libtcl8.6.so => /usr/lib/i386-linux-gnu/libtcl8.6.so (0xb760a000)
	libtk8.6.so => /usr/lib/i386-linux-gnu/libtk8.6.so (0xb74c6000)
	libpthread.so.0 => /lib/i386-linux-gnu/libpthread.so.0 (0xb74a9000)
	libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb72fa000)
	libdl.so.2 => /lib/i386-linux-gnu/libdl.so.2 (0xb72f5000)
	libz.so.1 => /lib/i386-linux-gnu/libz.so.1 (0xb72db000)
	libm.so.6 => /lib/i386-linux-gnu/libm.so.6 (0xb7295000)
	libXft.so.2 => /usr/lib/i386-linux-gnu/libXft.so.2 (0xb727e000)
	libfontconfig.so.1 => /usr/lib/i386-linux-gnu/libfontconfig.so.1 (0xb7243000)
	libX11.so.6 => /usr/lib/i386-linux-gnu/libX11.so.6 (0xb710f000)
	libXss.so.1 => /usr/lib/i386-linux-gnu/libXss.so.1 (0xb710b000)
	/lib/ld-linux.so.2 (0xb77bf000)
	libfreetype.so.6 => /usr/lib/i386-linux-gnu/libfreetype.so.6 (0xb706b000)
	libXrender.so.1 => /usr/lib/i386-linux-gnu/libXrender.so.1 (0xb705f000)
	libexpat.so.1 => /lib/i386-linux-gnu/libexpat.so.1 (0xb7036000)
	libxcb.so.1 => /usr/lib/i386-linux-gnu/libxcb.so.1 (0xb7014000)
	libXext.so.6 => /usr/lib/i386-linux-gnu/libXext.so.6 (0xb7001000)
	libpng12.so.0 => /lib/i386-linux-gnu/libpng12.so.0 (0xb6fd9000)
	libXau.so.6 => /usr/lib/i386-linux-gnu/libXau.so.6 (0xb6fd4000)
	libXdmcp.so.6 => /usr/lib/i386-linux-gnu/libXdmcp.so.6 (0xb6fcd000)
maksim@ASUS ~/Progy/Go/src/imitator $ 

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: GUI на Go

Непрочитанное сообщение Olej » 14 май 2017, 13:44

perseus писал(а): Ниже привожу код небольшой демонстрационной программки, в которой реализован ГИП посредством использоваиня пакета "github.com/edartuz/go-tk/gotk". Это был мой первый опыт, прошу не судить строго.
Код программ (а также Makefile и всё что связано) прикладывайте, пожалуйста, прикреплёнными файлами, чтобы их можно было сразу загрузить (а не копировать с экрана с ошибками ;-) ) и использовать ... экспериментировать.
Потому что представлять для обсуждения нужно бы полный комплект файлов для повторения сборки и испытания приложения (Makefile, файды тестовых данных, ... возможно в 2 фразы инструкция сборки READ.ME ... текстовый файл протокола запусков *.hist - копии команд терминала - т.е. всё, что кто считает нужным представить к обсуждению).

Прикрепление файлов делается ниже окна редактирования сообщения: "Имя файла", "Добавить файл", "Комментарий к файлу" и т.д. - выбираете свой файл ("Обзор") и прикрепляете его к сообщению.
Прикреплять можно сколько угодно много файлов (относящиеся к проекту).
Можно прикреплять отдельные файлы группы поштучно ... можно все файлы группы сархивировать в .tgz и и прикреплять архив.

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: GUI на Go

Непрочитанное сообщение Olej » 14 май 2017, 13:49

perseus писал(а):Поскольку у Go нет своих средств писать графический интерфейс пользователя (ГИП или GUI кому как привычнее), я решил использовать библиотеку Tk для этих целей
Есть ещё очень интересный вариант, описываемый в Интернет: реализуется средствами пакетов Go WEB-интерфейс, куда код Go отрисовывает виджеты и откуда получает реакции пользователя (кнопки управления и т.д.).
Это реализуется исключительно средствами Go.
P.S. Если снова попадётся на глаза (уже несколько раз видел) - выложу ссылки.

Это очень даже стоит попробовать!

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: GUI на Go

Непрочитанное сообщение Olej » 14 май 2017, 13:53

perseus писал(а): Там также имеются пакеты и для Qt и Gtk, кому что больше нравится.
Это тоже очень!!! интересно.
Особенно ... как по мне (IMHO!) - GTK.
Потому что для более сложных GUI интерфейсов, насыщенных картинок, интерфейс Tk несколько бедноват и несколько старомоден ;-)
Tcl/Tk - очень хорошо, когда нужно быстро сделать графику ... но для детально проработанной графики он слабоват.

Аватара пользователя
perseus
Писатель
Сообщения: 99
Зарегистрирован: 11 май 2017, 18:01
Откуда: Щёлково, Московская обл.
Контактная информация:

Re: GUI на Go

Непрочитанное сообщение perseus » 14 май 2017, 13:54

Прошу прощения, вот прикреплённый файл imitguiDemo.go
Вложения
imitguiDemo.go
(10.76 КБ) 94 скачивания

Ответить

Вернуться в «Программирование»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 8 гостей