Class SJComboBox<T>

java.lang.Object
com.vaadin.flow.component.Component
com.vaadin.flow.component.AbstractField<com.vaadin.flow.component.combobox.ComboBox<T>, T>
com.vaadin.flow.component.AbstractSinglePropertyField<com.vaadin.flow.component.combobox.ComboBox<T>, T>
com.vaadin.flow.component.combobox.ComboBoxBase<com.vaadin.flow.component.combobox.ComboBox<T>, T, T>
com.vaadin.flow.component.combobox.ComboBox<T>
com.vaadin.swingbridge.surrogates.SJComboBox<T>
All Implemented Interfaces:
com.vaadin.flow.component.AttachNotifier, com.vaadin.flow.component.BlurNotifier<com.vaadin.flow.component.combobox.ComboBox<T>>, com.vaadin.flow.component.DetachNotifier, com.vaadin.flow.component.Focusable<com.vaadin.flow.component.combobox.ComboBox<T>>, com.vaadin.flow.component.FocusNotifier<com.vaadin.flow.component.combobox.ComboBox<T>>, com.vaadin.flow.component.HasAriaDescription, com.vaadin.flow.component.HasAriaLabel, com.vaadin.flow.component.HasElement, com.vaadin.flow.component.HasEnabled, com.vaadin.flow.component.HasHelper, com.vaadin.flow.component.HasLabel, com.vaadin.flow.component.HasPlaceholder, com.vaadin.flow.component.HasSize, com.vaadin.flow.component.HasStyle, com.vaadin.flow.component.HasTheme, com.vaadin.flow.component.HasValidation, com.vaadin.flow.component.HasValue<com.vaadin.flow.component.AbstractField.ComponentValueChangeEvent<com.vaadin.flow.component.combobox.ComboBox<T>, T>, T>, com.vaadin.flow.component.HasValueAndElement<com.vaadin.flow.component.AbstractField.ComponentValueChangeEvent<com.vaadin.flow.component.combobox.ComboBox<T>, T>, T>, com.vaadin.flow.component.shared.HasAllowedCharPattern, com.vaadin.flow.component.shared.HasAutoOpen, com.vaadin.flow.component.shared.HasClearButton, com.vaadin.flow.component.shared.HasPrefix, com.vaadin.flow.component.shared.HasThemeVariant<com.vaadin.flow.component.combobox.ComboBoxVariant>, com.vaadin.flow.component.shared.HasTooltip, com.vaadin.flow.component.shared.HasValidationProperties, com.vaadin.flow.component.shared.InputField<com.vaadin.flow.component.AbstractField.ComponentValueChangeEvent<com.vaadin.flow.component.combobox.ComboBox<T>, T>, T>, com.vaadin.flow.data.binder.HasValidator<T>, com.vaadin.flow.data.provider.HasDataView<T, String, com.vaadin.flow.component.combobox.dataview.ComboBoxDataView<T>>, com.vaadin.flow.data.provider.HasLazyDataView<T, String, com.vaadin.flow.component.combobox.dataview.ComboBoxLazyDataView<T>>, com.vaadin.flow.data.provider.HasListDataView<T, com.vaadin.flow.component.combobox.dataview.ComboBoxListDataView<T>>, ComponentMixin, ContainerMixin, JComponentMixin, ItemSelectable, Serializable

public class SJComboBox<T> extends com.vaadin.flow.component.combobox.ComboBox<T> implements JComponentMixin, ItemSelectable
Surrogate for JComboBox (SD_sjcombobox). Extends Vaadin ComboBox and reproduces the Swing JComboBox UI functionality: model-driven items + selection, ItemListener pair fan-out on selection commit, ActionListener fan-out on commit, PopupMenuListener fan-out on every open and close, the user's included (addOpenedChangeListener(ComponentEventListener)), editable mode wired to Vaadin's allowCustomValue, and maximumRowCount mirroring Vaadin's pageSize.

Why ComboBox, not a leaf primitive

Vaadin ComboBox is the only native dropdown selector that supports filterable item lists, custom values (typed input commit), and a configurable popup. It cleanly carries JDK JComboBox's contract for both editable and non-editable modes. Vaadin's Select<T> was rejected: it doesn't allow custom values, has no filter UI, and its popup is not page-sized.

Source of truth

The installed ComboBoxModel is the source of truth for items and selected item (R_swing_is_truth) — JDK reuses DefaultComboBoxModel, so migrated user code that constructs / manipulates a model directly keeps working unchanged. Our ListDataListener on the model snapshots items into the peer via ComboBoxBase.setItems(java.util.Collection) on every list change (Vaadin offers no incremental add API), and pushes the model's current selection through ComboBoxBase.setValue(TValue). Browser-originated edits funnel back through an explicit addValueChangeListener subscription wrapped in SHelper.callSwing(Runnable) (R_callswing_envelope) and write through ComboBoxModel.setSelectedItem(Object), which fires the model's ListDataEvent.CONTENTS_CHANGED and closes the loop. The standard preventPeerEvents flag (R_swing_is_truth) guards against peer→model→peer re-entry.

ItemEvent fan-out

On every selection commit the surrogate fans out the JDK-canonical pair: ItemEvent.DESELECTED on the previously-selected item (when non-null) followed by ItemEvent.SELECTED on the newly-selected item (when non-null). The ActionEvent fires after the pair, matching JDK JComboBox's commit sequencing. ComboBoxStateStore.lastSelected is the rolling cursor.

Editable mode

setEditable(boolean) maps to Vaadin's ComboBoxBase.setAllowCustomValue(boolean). When enabled, a customValueSetListener subscription commits the typed string back into the model via model.setSelectedItem(typedString) — the model's ListDataEvent then drives the usual fan-out. The full ComboBoxEditor surface (custom editor components, selectAll, separate editor ActionListener) is R_vaadin_first drop-and-WARN — Vaadin owns the typed-input UX inside the combobox and there's no semantic-cleanly-mappable counterpart for a custom editor component.

Renderer

Vaadin-first per R_vaadin_first. Users at the surrogate layer install Vaadin Renderer instances directly via ComboBoxBase.setRenderer(Renderer) (or setItemLabelGenerator for label-only customisation). The JDK ListCellRenderer surface lives only on the :emulators.JComboBox layer and bridges into a Vaadin renderer at the boundary — surrogate-layer code sees Vaadin idioms only. The default rendering uses Vaadin's built-in String.valueOf item-label generator (matching JDK's "model value via toString" default), so a fresh SJComboBox renders sanely with zero configuration.

R_vaadin_first drop-and-WARN surface

  • ComboBoxEditor (full editor port).
  • KeySelectionManager (browser handles type-to-search).
  • lightWeightPopupEnabled (Swing-internal popup chrome).
  • prototypeDisplayValue (sizing hint).
  • selectWithKeyChar (subsumed by browser type-to-search).

UI-thread-confined, with one exception: the installed ComboBoxModel may be mutated from any thread. A worker filling it hops onto this combo's UI thread for each model event and blocks until the fan-out has run, so every listener here — and the peer write — runs on the UI thread; while the combo is detached, inline on the worker (SD_background_model_hop):

DefaultComboBoxModel<String> model = new DefaultComboBoxModel<>();
layout.add(new SJComboBox<>(model));
executor.submit(() -> repository.findAllNames().forEach(model::addElement));
See Also:
  • Constructor Details

    • SJComboBox

      public SJComboBox()
    • SJComboBox

      public SJComboBox(ComboBoxModel<T> model)
    • SJComboBox

      public SJComboBox(T[] items)
    • SJComboBox

      public SJComboBox(Vector<T> items)
  • Method Details

    • setSelectedItem

      public void setSelectedItem(Object anObject)
      Select an item, rejecting one the model does not contain unless the combo box is editable, then route through the model so its ListDataEvent fan-out drives the ItemEvent pair and the ActionEvent.

      The rejection is javax.swing.JComboBox.setSelectedItem's own — not the model's, which is where SB-Emulators looked for it and did not find it: DefaultComboBoxModel does permit any value, so routing straight to the model left getSelectedItem() answering an item that was never in the list, where a real non-editable JComboBox answers null (D_return_value_audit). A null argument bypasses the check, as it does in the JDK.

      On a match, the model's element is selected rather than the argument — the JDK substitutes it deliberately, so an equals-but-not-== argument does not displace the instance the model holds.

    • getSelectedItem

      public Object getSelectedItem()
    • getSelectedIndex

      public int getSelectedIndex()
    • setSelectedIndex

      public void setSelectedIndex(int anIndex)
    • getSelectedObjects

      public Object[] getSelectedObjects()
      ItemSelectable.getSelectedObjects() contract: returns a single-element array when an item is selected, an empty array when none. JDK uses Object[] (not T[]) because the interface predates generics — preserved verbatim.
      Specified by:
      getSelectedObjects in interface ItemSelectable
    • setValue

      public void setValue(T value)
      Specified by:
      setValue in interface com.vaadin.flow.component.HasValue<com.vaadin.flow.component.AbstractField.ComponentValueChangeEvent<com.vaadin.flow.component.combobox.ComboBox<T>, T>, T>
      Overrides:
      setValue in class com.vaadin.flow.component.combobox.ComboBoxBase<com.vaadin.flow.component.combobox.ComboBox<T>, T, T>
    • addItem

      public void addItem(T item)
      Add an item via the model. Throws IllegalStateException if the installed model isn't a MutableComboBoxModel — matches JDK JComboBox's "you must use a MutableComboBoxModel" runtime check (R_match_swing_errors).
    • insertItemAt

      public void insertItemAt(T item, int index)
    • removeItem

      public void removeItem(Object anObject)
    • removeItemAt

      public void removeItemAt(int anIndex)
    • removeAllItems

      public void removeAllItems()
    • getItemAt

      public T getItemAt(int index)
    • getItemCount

      public int getItemCount()
    • getModel

      public ComboBoxModel<T> getModel()
    • setModel

      public void setModel(ComboBoxModel<T> newModel)
    • isEditable

      public boolean isEditable()
    • setEditable

      public void setEditable(boolean aFlag)
    • getMaximumRowCount

      public int getMaximumRowCount()
    • setMaximumRowCount

      public void setMaximumRowCount(int count)
    • isPopupVisible

      public boolean isPopupVisible()
    • setPopupVisible

      public void setPopupVisible(boolean v)
      ComboBoxBase.setOpened(boolean); the PopupMenuListeners hear it through addOpenedChangeListener(ComponentEventListener), as they hear a user's click.
    • showPopup

      public void showPopup()
    • hidePopup

      public void hidePopup()
    • addOpenedChangeListener

      public com.vaadin.flow.shared.Registration addOpenedChangeListener(com.vaadin.flow.component.ComponentEventListener<SJComboBox.OpenedChangeEvent> listener)
      Listens for the dropdown opening or closing, whichever side did it: the opened-changed event DatePicker and Select expose and ComboBox lacks.
      combo.addOpenedChangeListener(e -> {
          if (e.isOpened() && e.isFromClient()) reloadItems();
      });
      
    • addItemListener

      public void addItemListener(ItemListener l)
      Specified by:
      addItemListener in interface ItemSelectable
    • removeItemListener

      public void removeItemListener(ItemListener l)
      Specified by:
      removeItemListener in interface ItemSelectable
    • getItemListeners

      public ItemListener[] getItemListeners()
    • addActionListener

      public void addActionListener(ActionListener l)
    • removeActionListener

      public void removeActionListener(ActionListener l)
    • getActionListeners

      public ActionListener[] getActionListeners()
    • getActionCommand

      public String getActionCommand()
    • setActionCommand

      public void setActionCommand(String aCommand)
    • fireActionEvent

      protected void fireActionEvent()
      Fire ActionEvent to all registered ActionListeners. Source = this; command = current actionCommand; timestamp = now; modifiers = 0 (no input device).
    • addPopupMenuListener

      public void addPopupMenuListener(PopupMenuListener l)
    • removePopupMenuListener

      public void removePopupMenuListener(PopupMenuListener l)
    • getPopupMenuListeners

      public PopupMenuListener[] getPopupMenuListeners()
    • firePopupMenuWillBecomeVisible

      protected void firePopupMenuWillBecomeVisible()
    • firePopupMenuWillBecomeInvisible

      protected void firePopupMenuWillBecomeInvisible()
    • addListDataListener

      public void addListDataListener(ListDataListener l)
    • removeListDataListener

      public void removeListDataListener(ListDataListener l)
    • fireListDataEvent

      protected void fireListDataEvent(ListDataEvent original)
      Forward a model ListDataEvent to the surrogate's own ListDataListener registrations. JDK JComboBox does the same — it implements ListDataListener on the model and re-fires through its own listener registry. Source rebound to the surrogate's model (matches JDK source in the forwarded event).
    • setAction

      public void setAction(Action a)
      Install (or clear) a JDK Action. Matches JDK JComboBox's narrow action surface: enabled / SHORT_DESCRIPTION (tooltip) / ACTION_COMMAND_KEY are honored; NAME / icon / mnemonic are not (JDK JComboBox doesn't surface those — combo boxes don't carry label text like buttons do). The Action's actionPerformed is invoked alongside our own ActionListener fan-out on every selection commit, with source rebound to this.
    • getAction

      public Action getAction()
    • getEditor

      public Object getEditor()
    • setEditor

      public void setEditor(Object anEditor)
    • configureEditor

      public void configureEditor(Object anEditor, Object anItem)
    • getKeySelectionManager

      public Object getKeySelectionManager()
    • setKeySelectionManager

      public void setKeySelectionManager(Object aManager)
    • isLightWeightPopupEnabled

      public boolean isLightWeightPopupEnabled()
    • setLightWeightPopupEnabled

      public void setLightWeightPopupEnabled(boolean aFlag)
    • getPrototypeDisplayValue

      public T getPrototypeDisplayValue()
    • setPrototypeDisplayValue

      public void setPrototypeDisplayValue(T prototypeDisplayValue)
    • selectWithKeyChar

      public boolean selectWithKeyChar(char keyChar)
    • validate

      public void validate()
      Visibility-widening override of ComboBoxBase.validate() (Vaadin declares it protected for input validation) to satisfy ComponentMixin's public validate() contract. Delegates to super so Vaadin's input-validation behaviour is preserved.
      Specified by:
      validate in interface ComponentMixin
      Overrides:
      validate in class com.vaadin.flow.component.combobox.ComboBoxBase<com.vaadin.flow.component.combobox.ComboBox<T>, T, T>
    • getUIClassID

      public String getUIClassID()
      Description copied from interface: JComponentMixin
      Deliberate no-op — L&F key.
      Specified by:
      getUIClassID in interface JComponentMixin