2

私はJComboBox潜在的に何千ものアイテムを持つことができるものを持っています。それらはソートされており、入力時に検索が行われるため、原則として完全に使用できなくなるわけではありません。

実際には、数百のアイテムだけではかなり使用できません。を使用して初期表示パフォーマンスを改善することができましたsetPrototypeDisplayValue()が、BasicListUIそれでもボックス内のすべてのアイテムに対してリストセルレンダラーを構成することを主張しています(を参照BasicListUI.updateLayoutState())。

これ、またはそのようなものは、明らかにSunにとって既知の問題です。8年経ちましたので、息を止めていません。

自分のUIを実装する以外に、回避策はありますか?

4

2 に答える 2

2

JListレンダリングに fly-weight アプローチを使用し、find-as-you-type をサポートしているように見えるため、より良い選択かもしれません。

を使用する場合は、コンポーネント自体がリッスンを開始するJComboBoxにモデルにエントリを追加します。これは、数千のエントリに受け入れられる単純な挿入ソートを使用します。SortedComboBoxModel

class SortedComboBoxModel extends DefaultComboBoxModel {

    /** Add elements by inserting in lexical order. */
    @Override
    public void addElement(Object element) {
        this.insertElementAt(element, 0);
    }

    /** Insert in lexical order by name; ignore index. */
    @Override
    public void insertElementAt(Object element, int index) {
        String name = element.toString();
        for (index = 0; index < this.getSize(); index++) {
            String s = getElementAt(index).toString();
            if (s.compareTo(name) > 0) {
                break;
            }
        }
        super.insertElementAt(element, index);
    }
}
于 2010-07-07T16:53:48.353 に答える
0

これが私が思いついたハックです。欠点は次のとおりです。

  • ルックアンドフィールを維持したい場合は、関心のある各BasicComboBoxUI拡張機能を個別にサブクラス化する必要があります
  • (たとえば) のサブクラスはWindowsComboBoxUILinux では読み込まれないため、リフレクションを使用して UI クラスを読み込む必要があります。
  • 拡張しない L&F (MacOS など?) では動作しません。BasicComboBoxUI
  • ListCellRenderer常に保証されるとは限らないことについての仮定を行います

私はまだよりクリーンなソリューションを受け入れています。

class FastBasicComboBoxUI extends BasicComboBoxUI {
  @Override
  public void installUI(JComponent c) {
    super.installUI(c);

    Object prototypeValue = this.comboBox.getPrototypeDisplayValue();
    if (prototypeValue != null) {
      ListCellRenderer renderer = comboBox.getRenderer();
      Component rendererComponent = renderer
          .getListCellRendererComponent(this.listBox, 
              prototypeValue, 0, false, false);
      if (rendererComponent instanceof JLabel) {
        // Preferred size of the renderer itself is (-1,-1) at this point, 
        // so we need this hack
        Dimension prototypeSize = new JLabel(((JLabel) rendererComponent)
            .getText()).getPreferredSize();
        this.listBox.setFixedCellHeight(prototypeSize.height);
        this.listBox.setFixedCellWidth(prototypeSize.width);
      }
    }
  }
}

私はまだよりクリーンなソリューションを受け入れています。

後で

これはいくつかの問題を解決しただけであることがわかりました。多数のアイテムを含むコンボ ボックスの最初の表示は、依然として非常に遅くなる可能性があります。次のように、コードをそれ自体に移動して、ポップアップ リスト ボックスがすぐに固定セル サイズになるようにする必要がありました。ComboPopup上記のように、これはプロトタイプの値に依存することに注意してください。

@Override
protected ComboPopup createPopup() {
  return new BasicComboPopup(comboBox) {
    @Override
    protected JList createList() {
      JList list = super.createList();
      Object prototypeValue = comboBox.getPrototypeDisplayValue();
      if (prototypeValue != null) {
        ListCellRenderer renderer = comboBox.getRenderer();
        Component rendererComponent = renderer
            .getListCellRendererComponent(list, prototypeValue, 0, false, false);
        if (rendererComponent instanceof JLabel) {
          // Preferred size of the renderer itself is (-1,-1) at this point, 
          // so we need this hack
          Dimension prototypeSize = new JLabel(((JLabel) rendererComponent)
              .getText()).getPreferredSize();
          list.setFixedCellHeight(prototypeSize.height);
          list.setFixedCellWidth(prototypeSize.width);
        }
      }
      return list;
    }
  };
}
于 2010-07-09T14:08:01.167 に答える