Macro Combobox prevent editing but allow selection?

Using python macro to create a dialog with a combobox. Would it be possible to block a combobox for typing, but stay active to choose an item in the dropdown list?
I tried this

cbb_test.setEditable(False)

and that

add_widget(‘combobox’, ‘ComboBox’, MARGIN, MARGIN + LBL_HEIGHT + SEP, WIDTH - MARGIN * 2, CBB_HEIGHT, {‘StringItemList’: choices, ‘Text’: default, ‘Dropdown’: True, ‘ReadOnly’: True})

but both cases block the combobox preventing the selection of an item

import uno
from com.sun.star.awt import MessageBoxButtons as MSG_BUTTONS
from com.sun.star.awt.PosSize import POS, SIZE, POSSIZE
from com.sun.star.awt.PushButtonType import OK, CANCEL
from com.sun.star.util.MeasureUnit import TWIP

def create_instance(name, with_context=False):
    ctx = XSCRIPTCONTEXT.getComponentContext()
    sm = ctx.ServiceManager

    if with_context:
        instance = sm.createInstanceWithContext(name, ctx)
    else:
        instance = sm.createInstance(name)
    return instance


def msg(message, title='LibreOffice', buttons=MSG_BUTTONS.BUTTONS_OK, type_msg='INFOBOX'):
    toolkit = create_instance('com.sun.star.awt.Toolkit')
    parent = toolkit.getDesktopWindow()
    mb = toolkit.createMessageBox(parent, type_msg, buttons, title, str(message)+'\n\n')
    return mb.execute()


def dialog_choice(message, title='', choices=[], default='', x=None, y=None):
    #https://api.libreoffice.org/docs/idl/ref/servicecom_1_1sun_1_1star_1_1awt_1_1UnoControlComboBoxModel.html
    #https://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1awt_1_1XTextComponent.html

    WIDTH = 520
    MARGIN = 8
    BUTTON_WIDTH = 100
    BUTTON_HEIGHT = 26
    SEP = 8
    LBL_HEIGHT = 16
    CBB_HEIGHT = 26
    HEIGHT = MARGIN * 2 + LBL_HEIGHT + SEP + CBB_HEIGHT + SEP + BUTTON_HEIGHT

    dialog = create_instance('com.sun.star.awt.UnoControlDialog', True)
    dialog_model = create_instance('com.sun.star.awt.UnoControlDialogModel', True)
    dialog.setModel(dialog_model)
    dialog.setVisible(False)
    dialog.setTitle(title)
    dialog.setPosSize(0, 0, WIDTH, HEIGHT, SIZE)

    def add_widget(name, type, x_, y_, width_, height_, props):
        model = dialog_model.createInstance(f'''com.sun.star.awt.UnoControl{type}Model''')
        dialog_model.insertByName(name, model)
        control = dialog.getControl(name)
        control.setPosSize(x_, y_, width_, height_, POSSIZE)

        for key, value in props.items():
            setattr(model, key, value)

    label_width = WIDTH - BUTTON_WIDTH - SEP - MARGIN * 2

    add_widget('label', 'FixedText', MARGIN, MARGIN, label_width, 
            LBL_HEIGHT, {'Label': str(message), 'NoLabel': True})
    
    add_widget('combobox', 'ComboBox', MARGIN, MARGIN + LBL_HEIGHT + SEP, WIDTH - MARGIN * 2, 
            CBB_HEIGHT, {'StringItemList': choices, 'Text': default, 'Dropdown': True})
    
    add_widget('btn_ok', 'Button', WIDTH - BUTTON_WIDTH - MARGIN, HEIGHT - MARGIN - BUTTON_HEIGHT, 
            BUTTON_WIDTH, BUTTON_HEIGHT, {'PushButtonType': OK, 'DefaultButton': True})
    
    add_widget('btn_cancel', 'Button', WIDTH - BUTTON_WIDTH - MARGIN * 2 - SEP - BUTTON_WIDTH, 
            HEIGHT - MARGIN - BUTTON_HEIGHT, BUTTON_WIDTH, BUTTON_HEIGHT, {'PushButtonType': CANCEL})


    frame = create_instance('com.sun.star.frame.Desktop', True).getCurrentFrame()
    window = frame.getContainerWindow() if frame else None
    dialog.createPeer(create_instance('com.sun.star.awt.Toolkit', True), window)

    if x is not None and y is not None:
        ps = dialog.convertSizeToPixel(uno.createUnoStruct('com.sun.star.awt.Size', x, y), TWIP)
        _x, _y = ps.Width, ps.Height

    elif window:
        ps = window.getPosSize()
        _x = ps.Width / 2 - WIDTH / 2
        _y = ps.Height / 2 - HEIGHT / 2

    dialog.setPosSize(_x, _y, 0, 0, POS)

    cbb_test = dialog.getControl('combobox')
    cbb_test.setFocus()

    #cbb_test.setEditable(False)

    if dialog.execute():
        value = cbb_test.getText()
    else:
        value = ''


    dialog.dispose()

    return value

def test():
    choices = ['Option 1', 'Option 2', 'Option 3']
    default = choices[0]

    result = dialog_choice('Choose an option:', 'Title', choices, default)

    if result != '':
        msg(result)
    return

Don’t you use a list box for any reason?

1 Like

In this case of only one listbox in the dialog, I can use the listbox, but if there were several widgets in the dialog, the combobox would take up less space. So I wanted to know if it’s possible to have a read-only combobox, but selectable like in other frameworks.

Same example using listbox:

import uno
from com.sun.star.awt import MessageBoxButtons as MSG_BUTTONS
from com.sun.star.awt.PosSize import POS, SIZE, POSSIZE
from com.sun.star.awt.PushButtonType import OK, CANCEL
from com.sun.star.util.MeasureUnit import TWIP

def create_instance(name, with_context=False):
    ctx = XSCRIPTCONTEXT.getComponentContext()
    sm = ctx.ServiceManager

    if with_context:
        instance = sm.createInstanceWithContext(name, ctx)
    else:
        instance = sm.createInstance(name)
    return instance


def msg(message, title='LibreOffice', buttons=MSG_BUTTONS.BUTTONS_OK, type_msg='INFOBOX'):
    toolkit = create_instance('com.sun.star.awt.Toolkit')
    parent = toolkit.getDesktopWindow()
    mb = toolkit.createMessageBox(parent, type_msg, buttons, title, str(message)+'\n\n')
    return mb.execute()


def dialog_choice(message, title='', choices=[], default='', x=None, y=None):
    WIDTH = 500
    MARGIN = 8
    BUTTON_WIDTH = 100
    BUTTON_HEIGHT = 26
    SEP = 8
    LABEL_HEIGHT = 16
    LSTB_HEIGHT = 198
    HEIGHT = MARGIN * 2 + LABEL_HEIGHT + SEP + LSTB_HEIGHT + SEP + BUTTON_HEIGHT


    dialog = create_instance('com.sun.star.awt.UnoControlDialog', True)
    dialog_model = create_instance('com.sun.star.awt.UnoControlDialogModel', True)
    dialog.setModel(dialog_model)
    dialog.setVisible(False)
    dialog.setTitle(title)
    dialog.setPosSize(0, 0, WIDTH, HEIGHT, SIZE)

    def add_widget(name, type, x_, y_, width_, height_, props):
        model = dialog_model.createInstance(f'''com.sun.star.awt.UnoControl{type}Model''')
        dialog_model.insertByName(name, model)
        control = dialog.getControl(name)
        control.setPosSize(x_, y_, width_, height_, POSSIZE)

        for key, value in props.items():
            setattr(model, key, value)

    label_width = WIDTH - BUTTON_WIDTH - SEP - MARGIN * 2

    add_widget('label', 'FixedText', MARGIN, MARGIN, label_width, LABEL_HEIGHT, 
        {'Label': str(message), 'NoLabel': True})
    
    add_widget('listbox', 'ListBox', MARGIN, MARGIN + LABEL_HEIGHT + SEP, 
            WIDTH - MARGIN * 2, LSTB_HEIGHT, {'StringItemList': choices, 'SelectedItems': [choices.index(default)]})
    
    add_widget('btn_ok', 'Button', WIDTH - BUTTON_WIDTH - MARGIN, HEIGHT - MARGIN - BUTTON_HEIGHT, 
            BUTTON_WIDTH, BUTTON_HEIGHT, {'PushButtonType': OK, 'DefaultButton': True})
    
    add_widget('btn_cancel', 'Button', WIDTH - BUTTON_WIDTH - MARGIN * 2 - SEP - BUTTON_WIDTH, 
            HEIGHT - MARGIN - BUTTON_HEIGHT, BUTTON_WIDTH, BUTTON_HEIGHT, {'PushButtonType': CANCEL})


    frame = create_instance('com.sun.star.frame.Desktop', True).getCurrentFrame()
    window = frame.getContainerWindow() if frame else None
    dialog.createPeer(create_instance('com.sun.star.awt.Toolkit', True), window)

    if x is not None and y is not None:
        ps = dialog.convertSizeToPixel(uno.createUnoStruct('com.sun.star.awt.Size', x, y), TWIP)
        _x, _y = ps.Width, ps.Height

    elif window:
        ps = window.getPosSize()
        _x = ps.Width / 2 - WIDTH / 2
        _y = ps.Height / 2 - HEIGHT / 2

    dialog.setPosSize(_x, _y, 0, 0, POS)

    listbox = dialog.getControl('listbox')
    listbox.setFocus()
    
    if dialog.execute():
        value = listbox.getSelectedItem()
        index = listbox.getSelectedItemPos()
    else:
        value = ''
        index = -1

    dialog.dispose()

    return value, index

def test():
    choices = ['Option 1', 'Option 2', 'Option 3']
    default = choices[0]

    result, index = dialog_choice('Choose an option:', 'Title', choices, default)

    if result != '':
        msg(f'You chose {result} at index {index}.')
    return

There is a difference in terminology between Microsoft Office Forms and LibreOfiice Forms (Dialogs). You need a Listbox with model’s Dropdown property set to True (see also colleague’s @KamilLanda answer).

1 Like

It really was a terminology problem, I corrected the listbox code to Dropdown = True , and it worked as I needed it to.

Thank you all for your help

corrected code:

import uno
from com.sun.star.awt import MessageBoxButtons as MSG_BUTTONS
from com.sun.star.awt.PosSize import POS, SIZE, POSSIZE
from com.sun.star.awt.PushButtonType import OK, CANCEL
from com.sun.star.util.MeasureUnit import TWIP

def create_instance(name, with_context=False):
    ctx = XSCRIPTCONTEXT.getComponentContext()
    sm = ctx.ServiceManager

    if with_context:
        instance = sm.createInstanceWithContext(name, ctx)
    else:
        instance = sm.createInstance(name)
    return instance


def msg(message, title='LibreOffice', buttons=MSG_BUTTONS.BUTTONS_OK, type_msg='INFOBOX'):
    toolkit = create_instance('com.sun.star.awt.Toolkit')
    parent = toolkit.getDesktopWindow()
    mb = toolkit.createMessageBox(parent, type_msg, buttons, title, str(message)+'\n\n')
    return mb.execute()


def dialog_choice(message, title='', choices=[], default='', x=None, y=None):
    WIDTH = 500
    MARGIN = 8
    BUTTON_WIDTH = 100
    BUTTON_HEIGHT = 26
    SEP = 8
    LABEL_HEIGHT = 16
    LSTB_HEIGHT = 26
    HEIGHT = MARGIN * 2 + LABEL_HEIGHT + SEP + LSTB_HEIGHT + SEP + BUTTON_HEIGHT


    dialog = create_instance('com.sun.star.awt.UnoControlDialog', True)
    dialog_model = create_instance('com.sun.star.awt.UnoControlDialogModel', True)
    dialog.setModel(dialog_model)
    dialog.setVisible(False)
    dialog.setTitle(title)
    dialog.setPosSize(0, 0, WIDTH, HEIGHT, SIZE)

    def add_widget(name, type, x_, y_, width_, height_, props):
        model = dialog_model.createInstance(f'''com.sun.star.awt.UnoControl{type}Model''')
        dialog_model.insertByName(name, model)
        control = dialog.getControl(name)
        control.setPosSize(x_, y_, width_, height_, POSSIZE)

        for key, value in props.items():
            setattr(model, key, value)

    label_width = WIDTH - BUTTON_WIDTH - SEP - MARGIN * 2

    add_widget('label', 'FixedText', MARGIN, MARGIN, label_width, LABEL_HEIGHT, 
        {'Label': str(message), 'NoLabel': True})
    
    add_widget('listbox', 'ListBox', MARGIN, MARGIN + LABEL_HEIGHT + SEP, 
            WIDTH - MARGIN * 2, LSTB_HEIGHT, {'StringItemList': choices, 'SelectedItems': [choices.index(default)], 'Dropdown' : True})
    
    add_widget('btn_ok', 'Button', WIDTH - BUTTON_WIDTH - MARGIN, HEIGHT - MARGIN - BUTTON_HEIGHT, 
            BUTTON_WIDTH, BUTTON_HEIGHT, {'PushButtonType': OK, 'DefaultButton': True})
    
    add_widget('btn_cancel', 'Button', WIDTH - BUTTON_WIDTH - MARGIN * 2 - SEP - BUTTON_WIDTH, 
            HEIGHT - MARGIN - BUTTON_HEIGHT, BUTTON_WIDTH, BUTTON_HEIGHT, {'PushButtonType': CANCEL})


    frame = create_instance('com.sun.star.frame.Desktop', True).getCurrentFrame()
    window = frame.getContainerWindow() if frame else None
    dialog.createPeer(create_instance('com.sun.star.awt.Toolkit', True), window)

    if x is not None and y is not None:
        ps = dialog.convertSizeToPixel(uno.createUnoStruct('com.sun.star.awt.Size', x, y), TWIP)
        _x, _y = ps.Width, ps.Height

    elif window:
        ps = window.getPosSize()
        _x = ps.Width / 2 - WIDTH / 2
        _y = ps.Height / 2 - HEIGHT / 2

    dialog.setPosSize(_x, _y, 0, 0, POS)

    listbox = dialog.getControl('listbox')
    #listbox.setFocus()
    
    if dialog.execute():
        value = listbox.getSelectedItem()
        index = listbox.getSelectedItemPos()
    else:
        value = ''
        index = -1

    dialog.dispose()

    return value, index

def test():
    choices = ['Option 1', 'Option 2', 'Option 3']
    default = choices[1]

    result, index = dialog_choice('Choose an option:', 'Title', choices, default)

    if result != '':
        msg(f'You chose {result} at index {index}.')
    return

Sorry that example is in Basic, I’m very busy today and probably also tomorrow.
It is example how to set the same listbox like in Dialogs in Basic IDE - there isn’t typing of text, only selecting from Listbox.

Sub pridatListBox 'set the same Listbox like in Dialogs in Basic IDE
	dim oModel
	oModel=createUNOservice("stardiv.Toolkit.UnoControlListBoxModel")
	o=createUNOservice("stardiv.Toolkit.UnoListBoxControl")
	o.setModel(oModel)
	o.Model.StringItemList=array("aaa","bb", "ccc", "d", "e", "ff")
	o.Model.DropDown=true
	o.DropDownLineCount=5
	goHlavniDialog.addControl("xxx", o)
	o=goHlavniDialog.getControl("xxx")
	o.setPosSize(10, 100, 400, 26, 15)
End Sub
1 Like