External: Справочное руководство


1. Введение

External - это GUI библиотека для golang, которая для реализации интерфейса использует отдельную программу, GuiServer - см. здесь.

GuiServer написан на Harbour и GUI-библиотеке HwGUI. Я специально это оговариваю, поскольку в дальнейшем буду ссылаться на HwGUI при описании некоторых виджетов.

При старте External запускает GuiServer, если он еще не запущен, и присоединяется к нему. Связь связь эта может осуществляться одним из двух способов по вашему выбору.

  1. С помощью tcp/ip соединения. При этом используются два tcp/ip порта. GuiServer может работать как на том же компьютере, что и ваше приложение, так и на удаленном - в этом случае запустить его из приложения не удастся, так что он должен быть запущен заранее. По одному порту External отправляет команды GuiServer'у - создание окон, виджетов, всякие действия с ними и пр., по другому - принимает от него сообщения, поступающие при наступлении каких либо событий, нажатия кнопки, например.
  2. С помощью обычных файлов - используются два файла, логика взаимодействия та же, что и у двух tcp/ip портов в первом варианте.

2. Hello, World

Начнем, по традиции, с Hello, World. Вот пример простейшей программы, создающей окно с этой надписью:


package main

import egui "github.com/alkresin/external"

func main() {

    if egui.Init("") != 0 {
        return
    }
    pWindow := &egui.Widget{X: 100, Y: 100, W: 400, H: 140, Title: "My first GUI app"}
    egui.InitMainWindow(pWindow)

    pWindow.AddWidget(&egui.Widget{Type: "label",
        X: 20, Y: 60, W: 160, H: 24, Title: "Hello, World!" })

    pWindow.Activate()
    egui.Exit()
}

Функция Init() запускает GuiServer и присоединяется к нему. InitMainWindow() создает главное окно приложения с заданными параметрами. Метод AddWidget() — добавляет виджет типа label. Activate() — выводит окно на экран и переводит программу в режим ожидания.

Далее рассмотрим эти действия по порядку.


3. Инициализация

Как я уже говорил, первое, что следует сделать - это запустить GuiServer и присоединиться к нему. Это делает функция Init(sOpt string), которой передается строка параметров, разделенных символом конца строки ( "\n" ). Вот они (приведены значения по умолчанию):


    guiserver=guiserver.exe   //Имя исполняемого файла GuiServer
    type=1                    //Способ соединения, 1 - по tcp/ip, 2 - файловое соединение
    dir=                      //Каталог для файлов (при type=2), по умолчанию - временный каталог
    file=gs                   //Префикс имен файлов (при type=2)
    address=127.0.0.1         //Ip компьютера с GuiServer (при type=1)
    port=3101                 //Порт GuiServer (при type=1)
    log=0                     //Уровень журналирования (0...2)

Если вам надо изменить, например, номер порта и уровень журналирования, вы можете использовать такой вызов Init():

    egui.Init("port=4801\nlog=1")

Символ конца строки используется в качестве разделителя, чтобы было удобнее передать в качестве параметра содержимое ini файла:


    var sInit string
    b, err := ioutil.ReadFile("test.ini")
    if err != nil {
       sInit = ""
    } else {
       sInit = string(b)
    }

    if egui.Init(sInit) != 0 {
        return
    }
    // ...

Функция Init() возвращает 0 в случае успешного выполнения, 1 - если соединиться не удалось, и 2 - если протоколы связи вашей версии External и GuiServer отличаются.


4. Создание окон и виджетов

Итак, инициализация прошла успешно, теперь мы можем формировать интерфейс программы. В большинстве случаев начать следует с создания главного окна. Это делается посредством вызова функции InitMainWindow(pWindow), которой в качестве единственного параметра передается указатель на предварительно созданную структуру Widget, описывающую окно. Вот объявление этой структуры:


   type Widget struct {
      Parent   *Widget
      Type     string
      Name     string
      X        int
      Y        int
      W        int
      H        int
      Title    string
      Winstyle int32
      TColor   int32
      BColor   int32
      Tooltip  string
      Anchor   int32
      Font     *Font
      AProps   map[string]string
      aWidgets []*Widget
   }

Структура Widget используется для создания окон, диалогов и виджетов, конкретный тип объекта определяется полем Type; для главного окна это "main", для диалога - "dialog", для, например, кнопки, - "button". К описанию полей структуры мы вернемся чуть позже, а пока продолжим разговор о создании окна.

InitMainWindow(pWindow *Widget) создает окно, этот вызов приводит в конечном итоге к вызову на стороне GuiServer функции Windows API CreateWindowEx() или, если мы работаем под Unix/Linux, gtk_window_new().

Для того, чтобы окно появилось на экране, необходимо вызвать еще метод объекта Widget Activate(). GuiServer по получении соответствующей команды вызывает функцию Windows API ShowWindow() и начинает цикл обработки сообщений, в Unix/Linux делается вызов gtk_main(), что, по сути, то же самое. External после отправления команды на GuiServer тоже входит в цикл ожидания сообщений, (он принимает их, как вы помните, от GuiServer через второй порт), поэтому выполнение программы на этом приостанавливается. Следующие после вызова Activate() для главного окна строки программы (точнее, функции, в которой стоит Activate()) будут выполнены только после закрытия окна, обычно это завершение программы.

Для добавления виджетов используется метод объекта Widget AddWidget(pWidg *Widget). Добавить виджет можно в любой другой виджет, но практически нет какого-либо смысла добавлять, например, Edit в кнопку. Виджеты добавляются в окно (главное или диалог), на панель, на Tab. При добавлении в окно вызовы AddWidget() располагаются между InitMainWindow() и Activate(). При необходимости виджеты можно добавлять и в других частях программы при наступлении каких-то событий. Единственным параметром AddWidget() является указатель на соответствующую структуру Widget, содержащую описание нового виджета


4.1 Структура Widget - описание полей

Parent объект Widget, родительское окно/виджет
Type строка, определяющая тип виджета: "main", "dialog", "button", "label" и пр., полный список см. дальше
Name строка - идентификатор виджета
X, Y, W, H координаты верхнего левого угла окна/виджета, ширина и высота в пикселях
Title заголовок окна, надпись на кнопке, т.е., текст отображаемый на виджете
Winstyle число, стиль окна/виджета, принятый в Windows API
TColor, BColor число, цвет текста и фона, соответственно
Tooltip он и есть тултип - строчка текста, появляющаяся при наведении мышки на виджет
Anchor якорь, число, определяющее привязку виджета к краям окна при изменении размера окна, подробнее см. в Приложении
Font шрифт, объект структуры Font, подробнее см. дальше
AProps поле типа map, список дополнительных атрибутов окна/виджета, подробнее см. дальше;
aWidgets массив объектов Widget - тех, что включены в состав этого окна/виджета

4.2 Список виджетов

В таблице - список типов виджетов (поле Type структуры Widget), поддерживаемых к моменту написания этого руководства.

main главное окно
dialog диалог
label стандартный статический текст
edit стандартный виджет для ввода/редактирования текста
button стандартная кнопка
check стандартная check - кнопка
radio стандартная радио - кнопка
radiogr группа радио-кнопок
group прямоугольная рамка для выделения группы виджетов
combo стандартный комбобокс
bitmap картинка
line разделительная линия
panel панель (тулбар), на ней можно размещать другие виджеты
paneltop панель, прикрепленная к верхней части окна
panelbot панель, прикрепленная к нижней части окна (статусбар)
panelhead панель - заголовок окна
ownbtn нестандартная кнопка
splitter сплиттер - ну, вы знаете
updown стандартный виджет для редактирования числа с кнопками вверх/вниз
tree дерево
progress прогресс - бар
tab таб с вкладками
browse виджет для отображения таблицы данных
cedit виджет для редактирования текста с расширенными возможностями
link виджет - ссылка
monthcal стандартный календарик

4.3 AProps - дополнительные атрибуты

Поскольку структура Widget - одна для всех типов виджетов, а наборы свойств у виджетов - разные, то помимо свойств, общих для большинства виджетов (координаты, текст, цвета, ...), в структуру включена хэш-таблица (map) AProps, которая содержит свойства/атрибуты, которые вы хотите установить именно для этого виджета. Конечно, вы можете указывать там не всё, что угодно, а только те атрибуты, которые определены для виджетов этого типа. Ниже - список типов виджетов с соответствующими свойствами:

main Icon: C
dialog Icon: C, NoExitOnEsc: L, NoCloseAble: L
label Transpa: L
edit Picture: C
check Transpa: L
radio Transpa: L
combo AItems: AC
bitmap Transpa: L, TrColor: N, Image: C
line Vertical: L
panel HStyle: C
paneltop HStyle: C
panelbot HStyle: C, AParts: AC
panelhead HStyle: C, Xt: N, Yt: N, BtnClose: L, BtnMax: L, BtnMin: L
ownbtn Transpa: L, TrColor: N, Image: C, HStyles: AC, Xt: N, Yt: N
splitter Vertical: L, From: N, TO: N, ALeft: AC, ARight: AC, HStyle: C
updown From: N, TO: N
tree AImages: AC, EditLabel: L
progress Maxpos: N
browse Append: L, Autoedit: L, NoVScroll: L, NoBorder: L
cedit NoVScroll: L, NoBorder: L
link Link: C, ClrVisited: N, ClrLink: N, ClrOver: N
monthcal NoToday: L, NoTodayCirc: L, WeekNumb: L

Здесь перед двоеточием - имя атрибута, после - его тип:
- C - строка;
- N - число;
- L - логическое значение (boolean);
- AC - массив строк.

Поскольку AProps имеет тип map[string]string, мы можем значения всех атрибутов указывать только как строки. Поэтому числа берем в кавычки, логические значения указываем как "t" и "f", для массивов строк лучше всего использовать функцию ToString(xParam ...interface{}), например:


   AProps: map[string]string{"AItems": egui.ToString("first", "second", "third")}}
   AProps: map[string]string{"Transpa": "t"}}
   AProps: map[string]string{"HStyle": "st2", "BtnClose": "true", "Xt": "60"}}
     

Далее - список атрибутов с комментариями (в скобках - значения по умолчанию):

Icon
NoExitOnEsc Для диалога: не закрывать диалог при нажатии ESC (Нет)
NoCloseAble
Transpa Прозрачность (Нет)
TrColor Цвет прозрачного слоя
Picture
AItems Для combobox: массив элементов
Image
Vertical Для линии (line): вертикальная или горизонтальная (Нет)
HStyle Стиль - подробнее см. дальше
HStyles
AParts Для panelbot: массив с размерами (шириной) в пикселях частей панели
Xt, Yt x и y координаты для размещения текста
BtnClose Для panelhead: показать ли кнопку закрытия окна (Да)
BtnMax Для panelhead: показать ли кнопку максимизации окна (Да)
BtnMin Для panelhead: показать ли кнопку минимизации окна (Да)
From, TO
ALeft, ARight
AImages
EditLabel
Maxpos
Append Для browse: можно добавлять строчки (Нет)
Autoedit Для browse: можно редактировать ячейки (Нет)
NoVScroll Без вертикального скролла (Нет)
NoBorder Без окантовки (Нет)
Link Для link: url ссылки
ClrVisited Для link: цвет уже посещенной ссылки
ClrLink Для link: цвет ссылки
ClrOver Для link: цвет ссылки при наведении мыши
NoToday Для monthcal:
NoTodayCirc Для monthcal:
WeekNumb Для monthcal:

Как видите, набор атрибутов, которые можно указать в AProps, невелик. На самом деле список атрибутов виджетов HwGUI (и, соответственно, GuiServer) гораздо больше. External позволяет установить все эти атрибуты, не поддерживаемые через AProps, с помощью метода SetParam()


5. Font, Style

Для работы со шрифтами в External предусмотрена структура Font:


type Font struct {
	Family    string     // наименование шрифта (Arial, Serif, ...)
	Name      string     // идентификатор шрифта
	Height    int        // размер (высота) шрифта
	Bold      bool       // жирный
	Italic    bool       // наклонный
	Underline bool       // подчеркнутый
	Strikeout bool       // перечеркнутый
	Charset   int16      // 204 - русский
}

Поля этой структуры, думаю, в комментариях не нуждаются - это стандартные атрибуты шрифта. Поле Name, как и в структуре Widget, используется для идентификации шрифта в вашей программе: вы сможете найти ранее созданный экземпляр шрифта (указатель на соответствующую структуру Font) с помощью функции GetFont(sName string).

Для создания шрифта используется функция CreateFont(pFont *Font). Она возвращает указатель на структуру Font (ту же, что передается ей в качестве параметра), который можно затем использовать при объявлении структуры Widget с полем Font. Для изменения шрифта виджета - метод структуры Widget SetFont(pFont *Font):


    // Создаем шрифт с идентификатором "flbl"
    egui.CreateFont(&egui.Font{Name: "flbl", Family: "Georgia", Height: 16})
    // Создаем шрифт и указываем его как атрибут диалогового окна
	pFont := egui.CreateFont(&egui.Font{Family: "Georgia", Height: 16})
	pDlg := &egui.Widget{Name: "dlg", X: 300, Y: 200, W: 400, H: 260, Title: "Dialog Test", Font: pFont}
	egui.InitDialog(pDlg)

	pLbl1 := pDlg.AddWidget(&egui.Widget{Type: "label", X: 20, Y: 10, W: 160, H: 24, Title: "Identifier:"})
	// ...
	// Изменяем шрифт метки на созданный ранее с идентификатором "flbl"
	pLbl1.SetFont( egui.GetFont("flbl") )
     

Style (не путать с Winstyle) - это структура, описывающая вневний вид виджета. Она может использоваться для нестандартных виджетов, которые рисуются самим HwGUI: "panel", "paneltop", "panelbot", "panelhead", "ownbtn".


type Style struct {
	Name      string    // идентификатор стиля
	Orient    int16     // тип градиента, его направление
	Colors    []int32   // массив цветов для заполнения фона
	Corners   []int32   // массив с радиусами закругления углов, [верхний левый,
	                    //   верхний правый, нижний правый, нижний левый]
	BorderW   int8      // толщина рамки в пикселях, если не задана - рамка
                        //   рисоваться не будет
	BorderClr int32     // цвет рамки
	Bitmap    string    // картинка для заполнения фона
}

Главным образом Style используется для создания градиентного фона виджета. Поле Colors - массив цветов градиента, Orient - направление подробнее см. дальше.

Поле Name, как и в структурах Widget и Font, используется для идентификации стиля в вашей программе: вы сможете найти ранее созданный экземпляр стиля (указатель на соответствующую структуру Style) с помощью функции GetStyle(sName string).

Для создания стиля используется функция CreateStyle(pStyle *Style). Она возвращает указатель на структуру Style (ту же, что передается ей в качестве параметра), который можно затем использовать при объявлении структуры Widget в составе хэш-массива AProps. Ключом соответствующего элемента будет HStyle, а значением - идентификатор (Name) структуры Style.


6. Callback функции

Callback функции (функция обратного вызова) - одно из важнейших понятий в External, это основная часть вашего приложения. В главной функции (main()) вы обычно создаете главное окно, его меню, набор виджетов. После вызова Activate() выполнение программы приостанавливается, она переходит в режим ожидания сообщений от GuiServer, от GUI-элементов вашего окна, вашего интерфейса. Эти сообщения вызывают выполнение callback функций вашего приложения, тех функций, которые вы установили как callback. Это функции, указанные в объявлении пунктов меню (AddMenuItem()), переданные c помощью SetCallBackProc() для обработки того или иного события (нажатия кнопки, потери фокуса ввода, ...), установленные для вызова после закрытия стандартного диалога (MsgInfo(), SelectFile(), ...), ...

Спецификация callback функции имеет вид func([]string) string, т.е. она принимает в качестве параметра массив строк и возвращает строку. В функциях, которые предназначены для передачи на GuiServer информации о callback функции, используются для этого два параметра: fu func([]string) string и sCode string. Первый - та самая callback функция, второй - идентификатор этой функции (это может быть имя функции или любая другая уникальная строка). External строит хэш-массив map[string]func([]string) string и передает на GuiServer строковый идентификатор. GuiServer при наступлении соответствующего события этот идентификатор возвращает, External находит по нему нужную функцию в хэш-массиве и выполняет ее. Вот так это и работает. Идентификатор нужен для того, чтобы передавать его на GuiServer и обратно - как, например, имя (sName) структур Widget, Font и пр. Кроме функции и ее идентификатора может передаваться произвольное количество строковых параметров - они будут потом переданы обратно callback - функции.

Вот как это может выглядеть в программе:


     ...
     // Передается ссылка на объявленную в программе функцию fu1
     egui.AddMenuItem("Date", 0, fu1, "fu1" )
     ...
     // Анонимная Callback функция, "Bye...1" - параметр, который она получит в массиве
     egui.AddMenuItem("Set text to label", 0,
        func(p []string) string { egui.Widg("main.l1").SetText(p[1]); return "" },
         "fsett2", "Bye...1")
     ...
     // Callback функция fsett1, которая будет вызвана при нажатии pButton
     pButton.SetCallBackProc("onclick", fsett1, "fsett1", "first parameter")
     

При вызове callback функции из меню первым элементом в передаваемом обратно параметре-массиве всегда будет строка "menu", при вызове от какого-либо виджета - идентификатор этого виджета. Т.е., в приведенном выше примере в функции fu1(p []string) массив p будет содержать единственный элемент "menu", а в функции fsett1 - два элемента: идентификатор pButton (sName) и строка "first parameter".

Кроме функции, объявленной в вашем приложении, можно также использовать в качестве callback функции программный код, написанный на Harbour. Для этого вместо функции указываете nil, а вместо ее идентификатора - строку кода. В этом случае событие обрабатывается на GuiServer и в ваше приложение ничего не передаётся:


     ...
     // Вызов Harbour/HwGUI функции hwg_EndWindow(), которая закрывает главное окно
     egui.AddMenuItem("Exit", 0, nil, "hwg_EndWindow()")
     ...
     // В 1-ую часть нижней панели (panelbot) главного окна пишется текущая дата
     pButton.SetCallBackProc("onclick", nil, "hwg_WriteStatus(HWindow():GetMain(),1,Dtoc(Date()),.T.)")
     

В External есть набор функций, вызывающих стандартные диалоги - информационные, выбора файла и пр. При вызове этих функций можно, а в тех случаях, когда вам требуется результат от диалога, необходимо указать функцию - получатель сообщения о закрытии диалога, т.е., callback функцию. Возьмем, например, диалог выбора цвета:


func fsele_color(p []string) string {
    // Функция первоначально вызывается из главного меню
	if p[0] == "menu" {
		egui.SelectColor(0, fsele_color, "fsele_color", "mm1")
	} else if p[0] == "mm1" {
	    // Функция была вызвана после закрытия диалога и первым параметром передана метка "mm1"
	    // Второй параметр - выбранный цвет
		iColor, _ := strconv.Atoi(p[1])
		egui.Widg("main.l1").SetColor(int32(iColor), -1)
	}
	return ""
}

Здесь функции SelectColor(iColor int32, fu func([]string) string, sFunc string, sName string) переданы те же параметры fu и sCode (fsele_color, "fsele_color"), определяющие callback функцию и параметр sName ("mm1") - метка, идентифицирующая источник вызова callback функции - он передается ей первым в массиве строк - параметров. Вторым в данном случае передается значение выбранного цвета.

Если вызова callback функции при закрытии диалога не требуется, соответствующие параметры оставляйте пустыми:

        egui.MsgInfo("Some message", "Title", nil, "", "")
     

7. Widget - методы

Activate() bool Активирует главного окно или диалог
Close() bool Закрывает главное окно или диалог
AddWidget(pWidg *Widget) *Widget Добавляет виджет
SetText(sText string) Устанавливает текст виджета
SetImage(sImage string) Для виджета "bitmap" - изменить картинку, в качестве параметра передается путь и имя файла изображения
SetParam(sParam string, xParam interface{}) Устанавливает значение xParam атрибута sParam. Атрибуты sParam - это переменные объекта соответствующего виджета HwGUI.
GetText() string Возвращает текст виджета
SetColor(tColor int32, bColor int32) Устанавливает цвет текста и фона виджета
SetFont(pFont *Font) Устанавливает шрифт виджета
SetCallBackProc(sbName string,
  fu func([]string) string, sCode string,
  params ...string)
Устанавливает callback процедуру для виджета, sbName - идентификатор события, для которого устанавливается процедура, подробнее о callback функциях см. выше.
SetCallBackFunc(sbName string,
  fu func([]string) string, sCode string,
  params ...string)
Устанавливает callback функцию для виджета, sbName - идентификатор события, для которого устанавливается процедура, подробнее о callback функциях см. выше.
Move(iLeft, iTop, iWidth, iHeight int32) Перемещает виджет и/или изменяет его размер
Enable(bEnable bool) Enable или Disable виджет, в зависимости от параметра bEnable
Hide(bHide bool) Спрятать или показать виджет - в зависимости от параметра bHide

8. Создание меню

Главное меню программы создается между вызовами InitMainWindow() и Activate(), для этого используются функции Menu(sTitle string), EndMenu(), AddMenuItem(sName string, id int, fu func([]string) string, sCode string, params ...string), AddMenuSeparator(). Фигурные скобки после Menu() необязательны, они добавлены здесь для большей выразительности.


package main

import (
    "time"
    egui "github.com/alkresin/external"
)

func main() {

    if egui.Init("") != 0 {
        return
    }

    pWindow := &(egui.Widget{X: 100, Y: 100, W: 400, H: 280, Title: "GUI for Golang"})
    egui.InitMainWindow(pWindow)

    // Создание меню начинается с вызва функции Menu("")
    // с пустым заголовком
    egui.Menu("")
    {
        // Субменю тоже создается с помощью вызова Menu(),
        // но уже с текстом заголовка
        egui.Menu("File")
        {
            // Добавляем пункт меню
            // fu1() - callback функция, которая должна выполняться при
            // выборе этого пункта меню
            egui.AddMenuItem("Date", 0, fu1, "fu1" )
            // Добавляем разделитель
            egui.AddMenuSeparator()
            // Здесь в качестве callback-функции указывается Harbour-код,
            // который будет выполняться на GuiServer.
            // Здесь это функция, которая закрывает главно окно.
            egui.AddMenuItem("Exit", 0, nil, "hwg_EndWindow()")
        }
        egui.EndMenu()
        egui.Menu("Help")
        {
            egui.AddMenuItem("About", 0, nil,
                "hwg_MsgInfo(\"My Golang GUI application\"+chr(10)+chr(13)+hwg_version(),\"About\")")
        }
        egui.EndMenu()
    }
    egui.EndMenu()

    pWindow.Activate()
    egui.Exit()
}

func fu1([]string) string {

    egui.MsgInfo("Today is " + time.Now().Format("02.01.2006"), "Info", nil, "", "")
    return ""
}

9. Функции

Init(sOpt string) int Инициализация соединения с GuiServer, подробнее см. здесь
InitMainWindow(pWnd *Widget) bool Создает главное окно
InitDialog(pWnd *Widget) bool Создает диалоговое окно
BeginPacket() Начало пакетной передачи данных
EndPacket() Завершение пакетной передачи данных
WriteLog(sText string) Добавляет строку в файл egui.log
GetFont(sName string) *Font Ищет по имени в списке созданных в программе шрифтов, возвращает найденный указатель на структуру Font
GetStyle(sName string) *Style Ищет по имени в списке созданных в программе стилей, возвращает найденный указатель на структуру Style
Wnd(sName string) *Widget Ищет по имени в списке созданных в программе окон, возвращает найденный указатель на структуру Widget
Widg(sName string) *Widget Ищет по имени в списке созданных в программе виджетов, возвращает найденный указатель на структуру Widget
ToString(xParam ...interface{}) string Преобразует параметры в json-строку для отправки на GuiServer
OpenMainForm(sForm string) bool Открывает xml форму с описанием главного окна, предварительно подготовленную с помощью HwGUI Designer
OpenForm(sForm string) bool Открывает xml форму с описанием диалогового окна, предварительно подготовленную с помощью HwGUI Designer
OpenReport(sForm string) bool Открывает xml форму с описанием отчета, предварительно подготовленную с помощью HwGUI Designer
CreateFont(pFont *Font) *Font Создает шрифт на основе структуры Font
CreateStyle(pStyle *Style) *Style Создает стиль на основе структуры Style
CreateHighliter(sName string, sCommands string,
   sFuncs string, sSingleLineComm string,
   sMultiLineComm string, bCase bool) *Highlight
Создает Highlight структуру для подсветки синтаксиса в виджете редактирования cedit.
SetHighliter(pEdit *Widget, p *Highlight) Устанавливает структуру Highlight в виджет типа cedit.
SetHiliOpt(pEdit *Widget, iGroup int,
   pFont *Font, tColor int32, bColor int32)
Устанавливает опции подсветки синтаксиса для виджета типа cedit.
InitPrinter(pPrinter *Printer, sFunc string,
   fu func([]string) string, sMark string) *Printer
Инициализирует принтер - подробнее см. здесь.
EvalProc(s string) Передает на GuiServer для выполнения программный код на языке Harbour
EvalFunc(s string) []byte Передает на GuiServer для выполнения программный код на языке Harbour, возвращает результат
GetValues(pWnd *Widget, aNames []string) []string Возвращает массив строк - значений виджетов окна pWnd, перечисленных по идентификаторам в массиве aNames.
GetVersion(i int) string Возвращает версию GuiServer. Если i==0 - номер версии, i==1 - полную строку с номером версии, i==2 - версию GuiServer, HwGUI и Harbour
MsgInfo(sMessage string, sTitle string,
   fu func([]string) string, sFunc string, sName string)
Создает стандартный Info диалог. sMessage - текст сообщения, sTitle - заголовок окна;
fu, sFunc - callback функция и ее идентификатор, эта функция вызывается после закрытия диалога; sName - эта строка будет первой в массиве, передаваемом callback функции при ее вызове. Подробнее см. выше.
MsgStop(sMessage string, sTitle string,
   fu func([]string) string, sFunc string, sName string)
Создает стандартный Stop диалог. Параметры те же, что и в MsgInfo.
MsgYesNo(sMessage string, sTitle string,
   fu func([]string) string, sFunc string, sName string)
Создает стандартный YesNo диалог. Параметры те же, что и в MsgInfo. Возвращает true или false через callback функцию.
MsgGet(sMessage string,
   sTitle string, iStyle int32,
   fu func([]string) string, sFunc string, sName string)
Создает диалог для ввода строки. Параметры те же, что и в MsgInfo, iStyle - стиль виджета Edit. Возвращает введенную строку через callback функцию.
Choice(arr []string, sTitle string,
   fu func([]string) string, sFunc string, sName string)
Создает диалог для выбора из массива строк arr. Остальные параметры те же, что и в MsgInfo. Возвращает номер выбранной строки через callback функцию.
SelectFile(sPath string,
   fu func([]string) string, sFunc string,
   sName string)
Вызывает стандартный диалог выбора файла, sPath - начальный путь. Остальные параметры те же, что и в MsgInfo. Возвращает имя файла через callback функцию.
SelectFolder(fu func([]string) string,
   sFunc string, sName string)
Вызывает стандартный диалог выбора каталога. Параметры те же, что и в MsgInfo. Возвращает имя каталога через callback функцию.
SelectColor(iColor int32,
   fu func([]string) string, sFunc string, sName string)
Вызывает стандартный диалог выбора цвета, iColor - начальный цвет. Остальные параметры те же, что и в MsgInfo. Возвращает код цвета через callback функцию.
SelectFont(fu func([]string) string,
   sFunc string, sName string)
Вызывает стандартный диалог выбора шрифта. Параметры те же, что и в MsgInfo. Возвращает параметры выбранного шрифта через callback функцию.
InsertNode(pTree *Widget,
   sNodeName string, sNodeNew string,
   sTitle string, sNodeNext string,
   aImages []string, fu func([]string) string, sCode string)
Добавляет новый элемент в дерево - pTree.
SelectNode(pTree *Widget, sNodeName string) Делает текущим узел дерева, указывая его по имени sNodeName, заданному в InsertNode().
PBarStep(pPBar *Widget) Передает прогресс-бару команду сделать следующий шаг.
PBarSet(pPBar *Widget, iPos int) { Устанавливает прогресс-бар в положение iPos.
InitTray(sIcon string,
   sMenuName string, sTooltip string)
Устанавливает опции размещения иконки главного окна в tray (только для Windows).
ModifyTrayIcon(sIcon string) Изменяет иконку в tray.
RadioEnd(p *Widget, iSel int) Завершает объявление радиогруппы.
TabPage(pTab *Widget, sCaption string) Начинает объявление страницы виджета tab
TabPageEnd(pTab *Widget) Завершает объявление страницы виджета tab
BrwSetArray(pBrowse *Widget,
   arr *[][]string)
Устанавливает массив для отображения в виджет browse
BrwGetArray(pBrowse*Widget) [][]string Получает отредактированный массив от обратно от виджета browse.
BrwSetColumn(pBrowse *Widget, ic int,
   sHead string, iAlignHead int,
   iAlignData int, bEditable bool, iLength int)
Устанавливает опции колонки номер ic виджета browse:
iAlignHead - выравнивание заголовка, iAlignData - выравнивание ячейки, bEditable - возможность редактирования, iLength - длина.
BrwSetColumnEx(pBrowse *Widget, ic int,
   sParam string, xParam interface{})
Устанавливает дополнительные опции колонки номер ic виджета browse; sParam - название опции, xParam - значение.
BrwDelColumn(pBrowse *Widget, ic int) Удаляет колонку номер ic виджета browse
SetVar(sVarName string, sValue string) Создает на GuiServer Public переменную sVarName (если ее нет) и устанавливает ее значение sValue
GetVar(sVarName string) string Возвращает с GuiServer значение переменной sVarName
SetImagePath(sValue string) Передает на GuiServer путь по умолчанию для файлов изображений
SetPath(sValue string) Передает на GuiServer путь по умолчанию для чтения/записи файлов
SetDateFormat(sValue string) Передает на GuiServer желаемый формат вывода даты
Menu(sTitle string) Начинает объявление меню или субменю
MenuContext(sName string) Начинает объявление контекстного меню
ShowMenuContext(sName string,
   pWnd *Widget)
Показывает контекстное меню, sName - идентификатор меню, pWnd - окно, к которому оно относится.
EndMenu() Завершает объявление меню или субменю
AddMenuItem(sName string, id int,
   fu func([]string) string,
   sCode string, params ...string)
Добавляет пункт меню, sName - имя, id - числовой идентификатор, остальные параметры те же, что и в MsgInfo.
AddCheckMenuItem(sName string,
   id int,fu func([]string) string,
   sCode string, params ...string)
Добавляет пункт меню, который можно помечать. Параметры - те же, что в AddMenuItem().
AddMenuSeparator() Добавляет в меню линию-разделитель
MenuItemEnable(sWndName string,
   sMenuName string,
   iItem int, bValue bool)
Меняет доступность элемента меню - в зависимости от значения bValue. Здесь sWndName - идентификатор окна, если это главное меню или меню диалога, sMenuName - идентификатор меню, если это контекстное меню, iItem - id пункта меню.
MenuItemCheck(sWndName string,
   sMenuName string,
   iItem int, bValue bool)
Отмечает или снимает отметку с пункта меню - в зависимости от значения bValue. Параметры те же, что и в MenuItemEnable.

10. Печать

Первое, что надо сделать при при создании печатного документа - это создать структуру Printer, которая имеет следующий вид:


type Printer struct {
	Name       string      // Идентификатор принтера
	SPrinter   string      // Имя принтера
	BPreview   bool        // True, если нужно превью
	IFormType  int         // Тип бумаги, см. в Приложении, по умолчанию - DMPAPER_A4
	BLandscape bool        // True, если нужна альбомная ориентация
}

Здесь Name - идентификатор принтера, поле, аналогичное таким же идентификаторам в Widget, Font, Style. SPrinter - имя принтера в системе. Если SPrinter не указан, будет использоваться принтер по умолчанию; если его значение - "...", то появится стандартное диалоговое окно для выбора принтера.

Затем инициализируем принтер с помощью функции InitPrinter(), которой передаем созданную структуру.

     InitPrinter(pPrinter *Printer, sFunc string, fu func([]string) string, sMark string) *Printer
     

Параметры sFunc, fu, sMark (те же, что в функциях, вызывающих стандартные диалоги), используются в тех случаях, когда поле Sprinter структуры Printer равно "...", т.е., требуется стандартный диалог выбора принтера. Напомню, fu - функция, которая должна быть вызвана по завершении диалога, sFunc - ее идентификатор, sMark - первый элемент массива строк, который будет передан этой функции.

После инициализации принтера можно приступать к печати. Ниже - список методов структуры Printer, которые при этом используются:

AddFont(pFont *Font) *Font Добавляет шрифт
SetFont(pFont *Font) Устанавливает текущий шрифт для печати
Say(iTop, iLeft, iRight, iBottom int32, sText string, iOpt int32) Печатает текст sText в прямоугольной области с координатами iTop, iLeft, iRight, iBottom. iOpt - тип выравнивания ( DT_LEFT, DT_RIGHT, DT_CENTER )
Line(iTop, iLeft, iRight, iBottom int32) Рисует линию в заданных координатах
Box(iTop, iLeft, iRight, iBottom int32) Рисует прямоугольник в заданных координатах
StartPage() Начинает новую страницу печати, этот вызов обязателен.
EndPage() Завершает печать страницы, этот вызов обязателен.
End() Завершает печать, освобождает принтер.

Все координаты указаны в миллиметрах.

Вот пример печати одной простой страницы:


func fprint(p []string) string {
    // Функция первоначально вызывается из главного меню
	if p[0] == "menu" {
		egui.InitPrinter(&egui.Printer{SPrinter: "...", BPreview: true}, "fprint", fprint, "mm1")
	} else {
	    // Повторно она же вызывается после выбора принтера из стандартного диалога
		pPrinter := egui.PLastPrinter
		pFont := pPrinter.AddFont(&egui.Font{Family: "Times New Roman", Height: 10})
		pPrinter.StartPage()
		pPrinter.SetFont(pFont)
		pPrinter.Box(5, 5, 200, 282)
		pPrinter.Say(50, 10, 165, 26, "Printing first sample !", egui.DT_CENTER)
		pPrinter.Line(45, 30, 170, 30)
		pPrinter.Line(45, 5, 45, 30)
		pPrinter.Line(170, 5, 170, 30)
		pPrinter.Say(50, 120, 150, 132, "----------", egui.DT_CENTER)
		pPrinter.Box(50, 134, 160, 146)
		pPrinter.Say(50, 135, 160, 146, "End Of Report", egui.DT_CENTER)
		pPrinter.EndPage()
		pPrinter.End()
	}
	return ""
}

11. Заключение

Если что-то осталось неясным, какой-то информации не хватает, смотрите примеры в external/testdata, раздел по External в туториале etutor. Еще один источник информации - группа Guiserver на GoogleGroups.

В некоторых случаях вам придется обратиться к документации Harbour и HwGUI. Так, чтобы установить в качестве callback функции Harbour код, выполняемый на GuiServer, или выполнить код на GuiServer с помошью EvalProc(), EvalFunc(), желательно чуть-чуть знать и понимать язык Harbour и HwGUI. Точно так же, чтобы непосредственно установить какой-либо атрибут виджета с помощью SetParam() или BrwSetColumnEx(), надо знать , что это за атрибуты (подсказка: это переменные классов HwGUI).

Фактически, Harbour - встроенный скриптовый язык вашего приложения. Наличие такого инструмента может оказаться очень полезным.


A. Приложения

Anchor

Список возможных значений поля Anchor структуры Widget:

A_TOPLEFT = -1 // Anchors control to the top and left borders of the container and does not change the distance between the top and left borders. (Default)
A_TOPABS = 1 // Anchors control to top border of container and does not change the distance between the top border.
A_LEFTABS = 2 // Anchors control to left border of container and does not change the distance between the left border.
A_BOTTOMABS = 4 // Anchors control to bottom border of container and does not change the distance between the bottom border.
A_RIGHTABS = 8 // Anchors control to right border of container and does not change the distance between the right border.
A_TOPREL = 16 // Anchors control to top border of container and maintains relative distance between the top border.
A_LEFTREL = 32 // Anchors control to left border of container and maintains relative distance between the left border.
A_BOTTOMREL = 64 // Anchors control to bottom border of container and maintains relative distance between the bottom border.
A_RIGHTREL = 128 // Anchors control to right border of container and maintains relative distance between the right border.
A_HORFIX = 256 // Anchors center of control relative to left and right borders but remains fixed in size.
A_VERTFIX = 512 // Anchors center of control relative to top and bottom borders but remains fixed in size.

Эти значения можно комбинировать. Например, egui.A_LEFTABS+egui.A_RIGHTABS - такой виджет, привязанный к левому и правому краям, будет растягиваться в ширину при растягивании окна.


WinAPI стили

DT_LEFT Выравнивание влево
DT_CENTER Выравнивание вправо
DT_RIGHT Выравнивание по центру
ES_PASSWORD Ввод пароля (для Edit)
ES_MULTILINE Многострочный Edit
ES_READONLY Edit - только для чтения
WS_HSCROLL Горизонтальный скролл
WS_VSCROLL Вертикальный скролл
WND_NOTITLE
WND_NOSYSMENU
WND_NOSIZEBOX

Типы бумаги

DMPAPER_A3A3 297 x 420 mm
DMPAPER_A4A4 210 x 297 mm
DMPAPER_A5A5 148 x 210 mm
DMPAPER_A6A6 105 x 148 mm

Типы градиента в Style

1 вертикальный сверху вниз
2 вертикальный снизу вверх
3 горизонтальный слева направо
4 горизонтальный справа налево
5 диагональный справа вверх
6 диагональный слева вниз
7 диагональный справа вниз
8 диагональный слева вверх
9 радиальный градиент

Идентификаторы событий

Здесь приведен список идентификаторов событий, поддерживаемых к моменту написания этого руководства - тех идентификаторов, которые можно указать в SetCallBackProc() и SetCallBackFunc().

oninit
ondestroy
onclick
onsize
onpaint
onrclick
ondblclick
onenter
onposchanged



Комментариев:       ()       пред.    след.       Добавить комментарий
Длина комментария - не больше 4000 символов.
Ваше имя:

Адрес электронной почты:
(не предназначено к показу)
 
Введите текст с картинки: