2025, Nov 13 19:00

How to Fill a LibreOffice Calc Form ComboBox from a Python Macro with ScriptForge and UNO

Learn the correct way to populate a LibreOffice Calc form ComboBox from a Python macro using ScriptForge and the UNO API insertItemText. Clear steps and code.

Populating a ComboBox in a LibreOffice Calc form from Python looks trivial until you try to call addItem and discover it doesn’t exist. If you are using ScriptForge to reach spreadsheet form controls, the right method is not obvious from the ScriptForge docs either. Here is a clear, working path to fill that list programmatically using python-uno.

Problem statement

You have a Calc document with multiple sheets that act as data tables, and a form on a sheet with a ComboBox meant to display those values. The control is reached through ScriptForge, and you want to push items into it from a Python macro.

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

The intuitive next step is to add entries one by one:

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

But addItem isn’t available on this object, so nothing gets inserted.

What’s really going on

The ScriptForge object here represents a spreadsheet form control, not a dialog control, and these use different interfaces. For spreadsheet form ComboBox, the underlying UNO model exposes a method named insertItemText that expects two arguments: the position and the text. It is discoverable with an UNO introspection tool such as MRI, while a plain dir() won’t reveal it because of UNO proxy behavior. ScriptForge’s own documentation for form controls does not show how to insert items, and tools like MRI do not introspect ScriptForge library objects themselves.

Solution: call the UNO method insertItemText

There are two practical ways to reach insertItemText from Python.

The first is to work directly with python-uno and operate on the control model:

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")

The second is to stay in the ScriptForge flow, then step into the underlying UNO world via XControlModel and call the same method there:

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")

Both approaches end up invoking the same UNO API on the control model and will successfully insert items at the specified positions.

Why this detail matters

Spreadsheet forms and dialog controls in LibreOffice do not share the same API surface. Assuming dialog-like methods exist on spreadsheet controls leads to dead ends and confusing failures. Knowing that the ComboBox model supports insertItemText with an index and a string saves time and points you directly to the correct UNO layer, whether you use ScriptForge as a convenience layer or not. When exploring UNO objects, tools designed for introspection provide accurate method discovery, while built-in techniques like dir() are not sufficient to see through UNO proxies.

Takeaways

If a ScriptForge control object doesn’t expose a helper for the operation you need, drop to the UNO model and use the documented method there. For a spreadsheet form ComboBox, use insertItemText(position, text). If you prefer to keep ScriptForge in your codebase, access the underlying model via XControlModel and call insertItemText from there. For further reading on ScriptForge form controls, consult the official help page: https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/sf_formcontrol.html. For inspecting UNO objects, MRI is a practical choice: https://github.com/hanya/MRI.