2025, Nov 19 15:02

Заполнение ComboBox формы LibreOffice Calc из Python через UNO

Пошаговое решение, как заполнить ComboBox формы на листе LibreOffice Calc из Python: ScriptForge и вызов UNO insertItemText через XControlModel. Примеры.

Заполнить выпадающий список (ComboBox) в форме LibreOffice Calc из Python кажется простым делом — пока не пытаешься вызвать addItem и не выясняешь, что такого метода нет. Если вы используете ScriptForge для доступа к элементам формы на листе, подходящий способ тоже неочевиден по документации ScriptForge. Ниже — понятный, рабочий путь, как программно наполнить этот список через python-uno.

Постановка задачи

У вас есть документ Calc с несколькими листами, используемыми как таблицы данных, и форма на одном из листов с ComboBox, который должен показывать эти значения. Доступ к элементу управления осуществляется через ScriptForge, и вы хотите добавлять в него пункты из Python‑макроса.

sf_doc = CreateScriptService('SFDocuments.Document')
form_scope = sf_doc.Forms(sheet_alias, 'Formulaire')
classes_cb = form_scope.Controls(ctrl_classes)

Логичный следующий шаг — добавлять элементы по одному:

classes_cb.addItem("class1")
classes_cb.addItem("class2")

Но у этого объекта нет метода addItem, поэтому ничего не вставляется.

Что происходит на самом деле

В данном случае объект ScriptForge представляет элемент управления формы на листе, а не элемент диалога, и у них разные интерфейсы. Для ComboBox в форме таблицы нижележащая модель UNO предоставляет метод insertItemText, который принимает два аргумента: позицию и текст. Его можно найти с помощью инструмента для интроспекции UNO, например MRI, тогда как обычный dir() его не покажет из‑за особенностей прокси в UNO. Собственная документация ScriptForge по элементам формы не описывает вставку элементов, а такие инструменты, как MRI, не интроспектируют объекты самой библиотеки ScriptForge.

Решение: вызвать метод UNO insertItemText

Существуют два практичных способа добраться до insertItemText из Python.

Первый — работать напрямую через python‑uno и обращаться к модели элемента управления:

sheet_ref = XSCRIPTCONTEXT.getDocument().getSheets().getByIndex(0)
form_ref = sheet_ref.getDrawPage().getForms().getByName("Formulaire")
ctrl_combo = form_ref.getByName("ComboBoxClasses")
ctrl_combo.insertItemText(0, "History")

Второй — остаться в «потоке» ScriptForge, затем перейти к нижележащей части UNO через XControlModel и вызвать тот же метод там:

from scriptforge import CreateScriptService

doc_api = CreateScriptService('SFDocuments.Document')
ui_form = doc_api.Forms('Sheet1', 'Formulaire')
sf_combo = ui_form.Controls('ComboBoxClasses')
uno_combo = sf_combo.XControlModel
uno_combo.insertItemText(1, "Science")

Оба подхода в итоге вызывают один и тот же API UNO на модели элемента управления и успешно вставляют элементы в указанные позиции.

Почему это важно

Элементы форм на листе и диалоговые контролы в LibreOffice не имеют общего API. Ожидание «диалоговых» методов на табличных элементах приводит в тупик и к непонятным сбоям. Понимание, что модель ComboBox поддерживает insertItemText с индексом и строкой, экономит время и сразу выводит на нужный уровень UNO — используете ли вы ScriptForge как удобную обёртку или нет. При изучении объектов UNO лучше пользоваться инструментами для интроспекции: они корректно показывают методы, тогда как встроенные приёмы вроде dir() не позволяют заглянуть сквозь прокси UNO.

Выводы

Если объект элемента управления ScriptForge не предлагает удобного метода для нужного действия, переходите на модель UNO и используйте документированный способ там. Для ComboBox в форме листа применяйте insertItemText(position, text). Если хотите оставить ScriptForge в кодовой базе, доберитесь до базовой модели через XControlModel и вызывайте insertItemText оттуда. Дополнительно о контролах форм в ScriptForge — на официальной странице справки: https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/sf_formcontrol.html. Для изучения объектов UNO удобен инструмент MRI: https://github.com/hanya/MRI.