Взаимодействие макросов с элементами управления листа в Calc

Автор Tillevion, 25 декабря 2023, 18:28

0 Пользователи и 1 гость просматривают эту тему.

Tillevion

Подскажите, где найти хорошую инфу о том, как макросы могут взаимодействовать с элементами управления листа в Calc. Например, как передать макросу выбранное значение из поля даты после выбора? Или как макросу подставить нужное значение в поле даты? Как макросу его скрыть или отобразить? И возможно изменить какие-то иные параметры. Прикладываю файл-пример.

sokol92

Спасибо за вопрос!
Сейчас конец года у всех программистов, так что время отклика может быть увеличено.  :)
Владимир.

economist

Элементы управления (контролы) - это прежде всего юзер, человек. Он уже вырос на Excel. Что мы имеем концептуально?

Есть Microsoft Office с хорошим макрорекордером, с VBA и идеальным 100% покрытием компактным кодом VBA объектной модели всех MSO-приложений, особенно в Excel (для него создано 98% всех макросов, объем проиндексированного поисковиками кода огромен, ChatGPT "бьет копытом"). Сотни примеров большого делового ПО на MSO, особенно в банковской среде. 

Есть OpenOffice|LibreOffice с плохим макрорекордером, с API под несколько языков (StarBasic, VBA, Python, Java, С++ итд), со 100% покрытием этим API всей объектной модели, но очень "длинным" и сложным кодом, примеры которого крайне трудно найти, приходится вычитывать в старых книжках, рассылках и искать у себя. Кода в Сети мало и для ChatGPT его не хватило. Ощущение что кодинг макросов для OpenOffice|LibreOffice 20 лет назад был "зашкварен" для опытных программистов (или ими самими). Лишь единицы примеров большого делового ПО на свободных офисных платформах. 

Таким образом общее у MSO и OpenOffice|LibreOffice - три компонента:
1) реактивное программирование формулами/функциями, самое быстрое и часто недоиспользованное программистами
2) штатными методы обработки некоторых событий, с возможностью простой привязки к контролам
3) VBA и макрорекордер, как мостик между двумя мирами

Вот сочетая эти компоненты и можно лично для себя определить "лучший" способ взаимодействия юзера с вашим софтом.

Для себя я определил что самый продуктивный подход это:
- реактивное программирование формулами "по максимуму". Это то, что нужно учить и практиковать постоянно;
- отказ от диалогов в пользу "рисования" их в ячейках листа, + усл. форматирование, Проверка-Данные итд; 
- и лишь когда не хватает формул и псевдо-контролов на листе - лезу в макросы и API OpenOffice|LibreOffice.

Большим плюсом данной схемы является возможность юзеру самореализоваться (формулами и имитацией диалогов в листе), что дает гарантию востребованности им полученного ПО.

Программисты же обычно хуже юзеров знают формулы и функции Excel/Calc и крайне редко "рисуют" диалоги в ячейках, выбирая ошибочный и самый сложный (в OO/LO) путь программирования событий и больших диалогов макросами.

Используя VBA в OpenOffice|LibreOffice можно сильно упростить работу с ячейками, связав их с контролами. Для этого надо использовать простую нотацию из мира Excel:
Option VBASupport 1
...
[A1].value = 10 ' с A1 свяжите контрол - вот вам реактивное программирование
...
Руб. за сто, что Питоньяк
Любит водку и коньяк!
Потому что мне, без оных, -
Не понять его никак...

sokol92

#3
От теории к практике.

Прочитать про формы (Forms) и элементы управления (Controls) можно в замечательной книге А.Питоньяка AndrewBase.odt. Эта книга предназначена для "долгого" чтения читателей с разным уровнем подготовки.

Экспресс - ответы на Ваши вопросы ниже (см. также приложенный файл).

В комментариях приведены наименования сервисов или структур (например, TextEvent), по которым их можно найти в документации.

' Обработка события элемента управления "Текст изменен".
' Параметр имеет тип TextEvent.
Sub OnTextChanged(oEvent)
  Dim oControl As Object, oModel As Object, d As Date
 
  oControl=oEvent.Source     ' элемент управления UnoControlDateField
  oModel=oControl.Model      ' его модель UnoControlDateFieldModel
 
  d=CDateFromUnoDate(oModel.Date)  ' Получаем дату и преобразовываем в формат Basic
  Msgbox "Новое значение : " & d
End Sub

' Записываем дату в элемент управления.
Sub WriteToControl
  Dim oModel As Object
  
  oModel=ThisComponent.DrawPages(0).Forms(0).GetByName("Поле даты 1")
  oModel.Date=CDateToUnoDate(Date-1)    ' вчерашняя дата
End Sub

' Читаем дату из элемента управления.
Sub ReadFromControl
  Dim oModel As Object
  oModel=ThisComponent.DrawPages(0).Forms(0).GetByName("Поле даты 1")
  Msgbox "Значение элемента управления: " & CDateFromUnoDate(oModel.Date)
End Sub
Владимир.

Tillevion

Благодарю за советы.

Цитата: economist от 26 декабря 2023, 09:21Программисты же обычно хуже юзеров знают формулы и функции Excel/Calc и крайне редко "рисуют" диалоги в ячейках, выбирая ошибочный и самый сложный (в OO/LO) путь программирования событий и больших диалогов макросами.
Как раз из-за кривого макрорекордера я начинал с функций. Мои первые, вполне серьезные, работы сделаны полностью на функциях и элементах управления без единой строчки кода. Одна из них используется с 2010 года и до сих пор. Как раз ее я сейчас и переделываю. Функция - тот же макрос, но с весьма скудными возможностями, особенно в отношении оптимизации быстродействия.

Цитата: economist от 26 декабря 2023, 09:21Option VBASupport 1
...
[A1].value = 10 ' с A1 св
Благодарю за совет, это действительно возможное решение. Но не очень хочется загромождать лист лишними данными, если можно напрямую обратиться к элементу управления.

Tillevion

Цитата: sokol92 от 26 декабря 2023, 14:15' Обработка события элемента управления "Текст изменен".
' Параметр имеет тип TextEvent.
Sub OnTextChanged(oEvent)
  Dim oControl As Object, oModel As Object, d As Date
 
  oControl=oEvent.Source     ' элемент управления UnoControlDateField
  oModel=oControl.Model      ' его модель UnoControlDateFieldModel
 
  d=CDateFromUnoDate(oModel.Date)  ' Получаем дату и преобразовываем в формат Basic
  Msgbox "Новое значение : " & d
End Sub

' Записываем дату в элемент управления.
Sub WriteToControl
  Dim oModel As Object
  
  oModel=ThisComponent.DrawPages(0).Forms(0).GetByName("Поле даты 1")
  oModel.Date=CDateToUnoDate(Date-1)    ' вчерашняя дата
End Sub

' Читаем дату из элемента управления.
Sub ReadFromControl
  Dim oModel As Object
  oModel=ThisComponent.DrawPages(0).Forms(0).GetByName("Поле даты 1")
  Msgbox "Значение элемента управления: " & CDateFromUnoDate(oModel.Date)
End Sub
Благодарю за ответ! А можно добавить код функций CDateFromUnoDate и CDateToUnoDate?

mikekaganski

С уважением,
Михаил Каганский



Tillevion

Подскажите, а как в этом же примере с помощью макроса переместить поле даты по горизонтали и по вертикали, например на 1 см?

sokol92

Можно так.

Sub ChangeSize()
  Dim oDrawPage As Object, oShape as Object, i As Long, pos
  oDrawPage=ThisComponent.Sheets(0).DrawPage
 
  For i=0 To oDrawPage.Count-1
    oShape=oDrawPage(i)
    If HasUnoInterfaces(oShape, "com.sun.star.drawing.XControlShape") Then
      If oShape.Control.Name = "Поле даты 1" Then
        pos=oShape.Position
        pos.X=pos.X + 1000   ' добавили 1 см
        pos.Y=pos.Y + 1000
        oShape.Position=pos
        Exit For
      End If
    End If
  Next i
End Sub
Владимир.

economist

В комплектной LO либе Tools/ModuleControls есть готовые полезные макросы для поиска объектов Model Shape View, начинаются они со слов getControl...

Они втроём обеспечивают комфортный переход контекста клика/ввода пользователя в любые Поля (в т.ч. текстовые) и Эл. управления на изменения их и самого документа (и обратно), сокращая и упрощая код.
Руб. за сто, что Питоньяк
Любит водку и коньяк!
Потому что мне, без оных, -
Не понять его никак...