Сегодня мы рассмотрим использование диалоговых окон при редактировании данных в LibreOffice Base (OpenOffice Base). Как мы выяснили в предыдущих сообщениях, Форма LibreOffice Base (OpenOffice Base) — это фактически экземпляр текстового редактора LibreOffice (OpenOffice) Writer. Для организации оконного интерфейса внутри Формы используется Диалоги — которые удобно создаются во встроенным визуальном интерфейсе, но не имеют поддержки для связи с таблицами базы данных. Эту связь будем организовывать макросами OO Basic.
Начнем по-порядку. Создадим две таблицы в базе данных:
products
— id (целое, первичный ключ)
— name (строка)
orders
— id (целое, первичный ключ)
— productId (целое)
— count (целое)
— date (тип данных Дата)
Создадим форму orders, добавим в форму элемент Form с именем orders. А также Table Control с источником данных orders. Как это сделать рассматривалось в Части 2 серии сообщений.
При задании свойств колонки date обратите, пожалуйста, внимание на отмеченные на рисунке стрелками свойства, которые позволяют отображать данные в нужном формате и использовать выпадающий календарь для выбора конкретной даты.
Теперь прямо в таблице можно добавлять и изменять данные. До определенного момента это удобно, похоже на привычную работу клиента с табличным процессором. Но в какой-то момент начинаются проблемы, также характерные для работы с табличными процессорами. Данные можно изменить случайно, даже не заметив этого. А заметив невозможно откатить все как было. Места для новых колонок мало, и может образоваться неприятная горизонтальная прокрутка. Заголовки колонок также имеют ограничение по размеру (иначе не поместятся по горизонтали), и это не позволяет дать подробное описание данных.
В качестве полумеры можно рядом с таблицей разместить обычные поля для ввода данных (Text Control, Numeric Control и т.д.). В качестве источника данных задать соответствующие поля таблицы orders и все будет работать. При навигации по набору данных будут меняться данные в полях ввода. При изменении данных в полях ввода будут меняться данные в таблице базы данных. Но выглядеть это решение будет не очень красиво.
Поэтому реализуем такой функционал при помощи Диалогов. У Диалогов есть одно существенное ограничение. Поля ввода Диалогов не связаны с таблицей базы данных. Поэтому заполнение полей ввода Диалога из таблицы базы данных, и сохранение полей ввода в таблицу базы данных нужно будет делать макросом OO Basic. Впрочем, это и хорошо, т.к. позволяет рассмотреть возможности программирования OO Basic (до этого в моих сообщениях была описана работа только со средой, но все это было подготовкой к сегодняшнему сообщению).
Чтобы вызвать на экран редактор Диалогов, необходимо выбрать в меню Tools->Macros->Organize Macros->LibreOffice Basic->Organizer->Dialog->New|Edit|Delete. Хотелось бы иметь более быстрый способ добраться до этого редактора. После чего откроется редактор диалога (увы, не самый удобный), в котором мы создадим поля с именами полей таблицы базы данных. Как Вы помните Диалоги не связываются автоматически с таблицами базы данных поэтому мы напишем макрос, который сделает это. И в качестве соглашения об именовании определим имена полей ввода и полей таблицы базы данных одинаковыми.
Редактор с готовой формой будет выглядеть примерно так:
Далее, добавим в Диалог две кнопки. Имена кнопкам дадим произвольные, но начинающиеся с подчеркивания, чтобы отличить их от полей базы данных. Каждой кнопке в палитре свойств можно задать действие. Зададим одой кнопке действие OK — она закроет Диалог с подтверждением действия. А второй — Cancel — она закроет диалог без подтверждения действия.
Закроем редактор Диалогов, и вернемся в редактор Формы. Создадим кнопку, вызывающую диалог и назначим ей процедуру-обработчик Order_Edit, в которой будем заполнять Диалог из таблицы базы данных FromBaseToDialog(oForm, oDialog), и сохранять данные из Диалога таблицу базы данных FromDialogToBase(oDialog, oForm).
Предполагается, что Диалог был сохранен в библиотеке Standard под именем dialogOrder. Естественно, Вы можете выбрать другие имена. Имена контролов, начинающиеся с подчеркивания пропускаются и не обрабатываются. Также не обрабатываются имена, начинающиеся с Label, которые используются для текстовых заголовков полей.
Вызов oDialog.Execute() = 1 отображает Диалог внутри окна Формы и приостанавливает работу макроса до нажатия кнопки OK или Cancel. При нажатии на кнопку OK выполнится равенство возвращаемого значения единице.
Начнем по-порядку. Создадим две таблицы в базе данных:
products
— id (целое, первичный ключ)
— name (строка)
orders
— id (целое, первичный ключ)
— productId (целое)
— count (целое)
— date (тип данных Дата)
Создадим форму orders, добавим в форму элемент Form с именем orders. А также Table Control с источником данных orders. Как это сделать рассматривалось в Части 2 серии сообщений.
При задании свойств колонки date обратите, пожалуйста, внимание на отмеченные на рисунке стрелками свойства, которые позволяют отображать данные в нужном формате и использовать выпадающий календарь для выбора конкретной даты.
Рисунок

Теперь прямо в таблице можно добавлять и изменять данные. До определенного момента это удобно, похоже на привычную работу клиента с табличным процессором. Но в какой-то момент начинаются проблемы, также характерные для работы с табличными процессорами. Данные можно изменить случайно, даже не заметив этого. А заметив невозможно откатить все как было. Места для новых колонок мало, и может образоваться неприятная горизонтальная прокрутка. Заголовки колонок также имеют ограничение по размеру (иначе не поместятся по горизонтали), и это не позволяет дать подробное описание данных.
В качестве полумеры можно рядом с таблицей разместить обычные поля для ввода данных (Text Control, Numeric Control и т.д.). В качестве источника данных задать соответствующие поля таблицы orders и все будет работать. При навигации по набору данных будут меняться данные в полях ввода. При изменении данных в полях ввода будут меняться данные в таблице базы данных. Но выглядеть это решение будет не очень красиво.
Поэтому реализуем такой функционал при помощи Диалогов. У Диалогов есть одно существенное ограничение. Поля ввода Диалогов не связаны с таблицей базы данных. Поэтому заполнение полей ввода Диалога из таблицы базы данных, и сохранение полей ввода в таблицу базы данных нужно будет делать макросом OO Basic. Впрочем, это и хорошо, т.к. позволяет рассмотреть возможности программирования OO Basic (до этого в моих сообщениях была описана работа только со средой, но все это было подготовкой к сегодняшнему сообщению).
Чтобы вызвать на экран редактор Диалогов, необходимо выбрать в меню Tools->Macros->Organize Macros->LibreOffice Basic->Organizer->Dialog->New|Edit|Delete. Хотелось бы иметь более быстрый способ добраться до этого редактора. После чего откроется редактор диалога (увы, не самый удобный), в котором мы создадим поля с именами полей таблицы базы данных. Как Вы помните Диалоги не связываются автоматически с таблицами базы данных поэтому мы напишем макрос, который сделает это. И в качестве соглашения об именовании определим имена полей ввода и полей таблицы базы данных одинаковыми.
Редактор с готовой формой будет выглядеть примерно так:
Рисунок

Далее, добавим в Диалог две кнопки. Имена кнопкам дадим произвольные, но начинающиеся с подчеркивания, чтобы отличить их от полей базы данных. Каждой кнопке в палитре свойств можно задать действие. Зададим одой кнопке действие OK — она закроет Диалог с подтверждением действия. А второй — Cancel — она закроет диалог без подтверждения действия.
Закроем редактор Диалогов, и вернемся в редактор Формы. Создадим кнопку, вызывающую диалог и назначим ей процедуру-обработчик Order_Edit, в которой будем заполнять Диалог из таблицы базы данных FromBaseToDialog(oForm, oDialog), и сохранять данные из Диалога таблицу базы данных FromDialogToBase(oDialog, oForm).
Sub Order_Edit(Event)
Dim oDialog As Object
Dim orders As Object
orders = Thiscomponent.DrawPage.Forms.GetByName("orders")
DialogLibraries.LoadLibrary("Standard")
oDialog = CreateUnoDialog(DialogLibraries.Standard.dialogOrder)
FromBaseToDialog(orders, oDialog)
If oDialog.Execute() = 1 Then
FromDialogToBase(oDialog, orders)
orders.UpdateRow()
End If
End Sub
Sub FromBaseToDialog(oForm, oDialog)
Dim I
Dim sName As String
For I = 0 To Ubound(oDialog.Model.ElementNames)
sName = oDialog.Model.ElementNames(I)
If Mid(sName, 1, 1) <> "_" And Mid(sName, 1, 5) <> "Label" Then
ODialog.GetControl(sName).SetText(oForm.Columns.GetByName(sName).String)
End If
Next I
End Sub
Sub FromDialogToBase(oDialog, oForm)
Dim I
Dim sName As String
For I = 0 To Ubound(oDialog.Model.ElementNames)
sName = oDialog.Model.ElementNames(I)
If Mid(sName, 1, 1) <> "_" And Mid(sName, 1, 5) <> "Label" Then
oForm.Columns.GetByName(sName).UpdateString(Trim(oDialog.GetControl(sName).GetText()))
End If
Next I
End Sub
Предполагается, что Диалог был сохранен в библиотеке Standard под именем dialogOrder. Естественно, Вы можете выбрать другие имена. Имена контролов, начинающиеся с подчеркивания пропускаются и не обрабатываются. Также не обрабатываются имена, начинающиеся с Label, которые используются для текстовых заголовков полей.
Вызов oDialog.Execute() = 1 отображает Диалог внутри окна Формы и приостанавливает работу макроса до нажатия кнопки OK или Cancel. При нажатии на кнопку OK выполнится равенство возвращаемого значения единице.