📄 comboboxui.java
字号:
package com.digitprop.tonic;
import java.awt.*;
import java.awt.event.*;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeEvent;
import javax.swing.*;
import javax.swing.plaf.basic.*;
import javax.accessibility.*;
import javax.swing.plaf.*;
import javax.swing.event.*;
import sun.awt.AppContext;
/** UI delegate for combo boxes.
*
* @author Markus Fischer
*
* <p>This software is under the <a href="http://www.gnu.org/copyleft/lesser.html" target="_blank">GNU Lesser General Public License</a>
*/
/*
* ------------------------------------------------------------------------
* Copyright (C) 2004 Markus Fischer
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
* You can contact the author at:
* Markus Fischer
* www.digitprop.com
* info@digitprop.com
* ------------------------------------------------------------------------
*/
public class ComboBoxUI extends javax.swing.plaf.metal.MetalComboBoxUI/*Basic*/
{
/** If true, the combo box is used in the JTable DefaultCellEditor */
private boolean isTableCellEditor= false;
/** Helper string */
private static final String IS_TABLE_CELL_EDITOR="JComboBox.isTableCellEditor";
/** The focus listener */
FocusListener editorFocusListener;
/** Flag for calculating the display size */
private boolean isDisplaySizeDirty = true;
/** This is used for knowing when to cache the minimum preferred size.
* If the data in the list changes, the cached value get marked for recalc.
* Added to the current JComboBox model.<p>
*
* Cached the size that the display needs to render the largest item
*/
private Dimension cachedDisplaySize= new Dimension(0, 0);
/** Key used for lookup of the DefaultListCellRenderer in the AppContext. */
private static final Object COMBO_UI_LIST_CELL_RENDERER_KEY=
new StringBuffer("DefaultListCellRendererKey");
/** Returns the default ListCellRenderer */
private static ListCellRenderer getDefaultListCellRenderer()
{
ListCellRenderer renderer=
(ListCellRenderer) AppContext.getAppContext().get(
COMBO_UI_LIST_CELL_RENDERER_KEY);
if (renderer == null)
{
renderer= new DefaultListCellRenderer();
AppContext.getAppContext().put(
COMBO_UI_LIST_CELL_RENDERER_KEY,
new DefaultListCellRenderer());
}
return renderer;
}
/** Creates and returns the UI delegate for the specified component */
public static ComponentUI createUI(JComponent c)
{
return new ComboBoxUI();
}
/** Installs an UI delegate for the specified component */
public void installUI(JComponent c)
{
isMinimumSizeDirty= true;
comboBox= (JComboBox) c;
installDefaults();
popup= createPopup();
listBox= popup.getList();
// Is this combo box a cell editor?
Boolean inTable= (Boolean) c.getClientProperty(IS_TABLE_CELL_EDITOR);
if (inTable != null)
{
isTableCellEditor= inTable.equals(Boolean.TRUE) ? true : false;
}
if (comboBox.getRenderer() == null
|| comboBox.getRenderer() instanceof UIResource)
{
comboBox.setRenderer(createRenderer());
}
if (comboBox.getEditor() == null
|| comboBox.getEditor() instanceof UIResource)
{
comboBox.setEditor(createEditor());
}
installListeners();
installComponents();
comboBox.setLayout(createLayoutManager());
comboBox.setRequestFocusEnabled(true);
installKeyboardActions();
/* 4353597: XXX - remove this hack but keep it here for some more testing. This block
* should be removed before FCS.
// An invokeLater() was used here because updateComponentTree() resets
// our sub-components after this method is completed. By delaying, we
// can set what we need after updateComponentTree() has set all of the
// values to defaults.
Runnable initializer = new Runnable() {
public void run(){
// This test for comboBox being null is required because it's possible for the UI
// to become uninstalled before this block of code is executed.
if ( comboBox != null ) {
if ( editor != null ) {
editor.setFont( comboBox.getFont() );
}
installKeyboardActions();
}
}
};
SwingUtilities.invokeLater( initializer ); */
}
/** Uninstalls the UI delegate for the specified component */
public void uninstallUI(JComponent c)
{
setPopupVisible(comboBox, false);
popup.uninstallingUI();
uninstallKeyboardActions();
comboBox.setLayout(null);
uninstallComponents();
uninstallListeners();
uninstallDefaults();
if (comboBox.getRenderer() == null
|| comboBox.getRenderer() instanceof UIResource)
{
comboBox.setRenderer(null);
}
if (comboBox.getEditor() == null
|| comboBox.getEditor() instanceof UIResource)
{
comboBox.setEditor(null);
}
keyListener= null;
focusListener= null;
listDataListener= null;
propertyChangeListener= null;
editorFocusListener= null;
popup= null;
listBox= null;
comboBox= null;
}
/** Installs the default colors, default font, default renderer, and default
* editor into the JComboBox.
*/
protected void installDefaults()
{
LookAndFeel.installColorsAndFont(
comboBox,
"ComboBox.background",
"ComboBox.foreground",
"ComboBox.font");
LookAndFeel.installBorder(comboBox, "ComboBox.border");
}
/** Create and install the listeners for the combo box and its model.
* This method is called when the UI is installed.
*/
protected void installListeners()
{
if ((itemListener= createItemListener()) != null)
{
comboBox.addItemListener(itemListener);
}
if ((propertyChangeListener= createPropertyChangeListener()) != null)
{
comboBox.addPropertyChangeListener(propertyChangeListener);
}
if ((keyListener= createKeyListener()) != null)
{
comboBox.addKeyListener(keyListener);
}
if ((focusListener= createFocusListener()) != null)
{
comboBox.addFocusListener(focusListener);
}
if ((popupMouseListener= popup.getMouseListener()) != null)
{
comboBox.addMouseListener(popupMouseListener);
}
if ((popupMouseMotionListener= popup.getMouseMotionListener()) != null)
{
comboBox.addMouseMotionListener(popupMouseMotionListener);
}
if ((popupKeyListener= popup.getKeyListener()) != null)
{
comboBox.addKeyListener(popupKeyListener);
}
if (comboBox.getModel() != null)
{
if ((listDataListener= createListDataListener()) != null)
{
comboBox.getModel().addListDataListener(listDataListener);
}
}
}
/** Uninstalls the default colors, default font, default renderer, and
* default editor into the JComboBox.
*/
protected void uninstallDefaults()
{
LookAndFeel.installColorsAndFont(
comboBox,
"ComboBox.background",
"ComboBox.foreground",
"ComboBox.font");
LookAndFeel.uninstallBorder(comboBox);
}
/** Remove the installed listeners from the combo box and its model.
* The number and types of listeners removed and in this method should be
* the same that was added in <code>installListeners</code>
*/
protected void uninstallListeners()
{
if (keyListener != null)
{
comboBox.removeKeyListener(keyListener);
}
if (itemListener != null)
{
comboBox.removeItemListener(itemListener);
}
if (propertyChangeListener != null)
{
comboBox.removePropertyChangeListener(propertyChangeListener);
}
if (focusListener != null)
{
comboBox.removeFocusListener(focusListener);
}
if (popupMouseListener != null)
{
comboBox.removeMouseListener(popupMouseListener);
}
if (popupMouseMotionListener != null)
{
comboBox.removeMouseMotionListener(popupMouseMotionListener);
}
if (popupKeyListener != null)
{
comboBox.removeKeyListener(popupKeyListener);
}
if (comboBox.getModel() != null)
{
if (listDataListener != null)
{
comboBox.getModel().removeListDataListener(listDataListener);
}
}
}
/** Creates the popup portion of the combo box.
*
* @return an instance of <code>ComboPopup</code>
*
* @see ComboPopup
*/
protected ComboPopup createPopup()
{
BasicComboPopup popup= new BasicComboPopup(comboBox);
popup.getAccessibleContext().setAccessibleParent(comboBox);
return popup;
}
/** Creates a <code>KeyListener</code> which will be added to the
* combo box. If this method returns null then it will not be added
* to the combo box.
*
* @return an instance <code>KeyListener</code> or null
*/
protected KeyListener createKeyListener()
{
return new KeyHandler();
}
/** Creates a <code>FocusListener</code> which will be added to the combo box.
* If this method returns null then it will not be added to the combo box.
*
* @return an instance of a <code>FocusListener</code> or null
*/
protected FocusListener createFocusListener()
{
return new FocusHandler();
}
/** Creates a list data listener which will be added to the
* <code>ComboBoxModel</code>. If this method returns null then
* it will not be added to the combo box model.
*
* @return an instance of a <code>ListDataListener</code> or null
*/
protected ListDataListener createListDataListener()
{
return new ListDataHandler();
}
/**
* Creates an <code>ItemListener</code> which will be added to the
* combo box. If this method returns null then it will not
* be added to the combo box.
* <p>
* Subclasses may override this method to return instances of their own
* ItemEvent handlers.
*
* @return an instance of an <code>ItemListener</code> or null
*/
protected ItemListener createItemListener()
{
return null;
}
/**
* Creates a <code>PropertyChangeListener</code> which will be added to
* the combo box. If this method returns null then it will not
* be added to the combo box.
*
* @return an instance of a <code>PropertyChangeListener</code> or null
*/
public PropertyChangeListener createPropertyChangeListener()
{
return new PropertyChangeHandler();
}
/**
* Creates a layout manager for managing the components which make up the
* combo box.
*
* @return an instance of a layout manager
*/
protected LayoutManager createLayoutManager()
{
return new ComboBoxLayoutManager();
}
/**
* Creates the default renderer that will be used in a non-editiable combo
* box. A default renderer will used only if a renderer has not been
* explicitly set with <code>setRenderer</code>.
*
* @return a <code>ListCellRender</code> used for the combo box
* @see javax.swing.JComboBox#setRenderer
*/
protected ListCellRenderer createRenderer()
{
return new BasicComboBoxRenderer.UIResource();
}
/**
* Creates the default editor that will be used in editable combo boxes.
* A default editor will be used only if an editor has not been
* explicitly set with <code>setEditor</code>.
*
* @return a <code>ComboBoxEditor</code> used for the combo box
* @see javax.swing.JComboBox#setEditor
*/
protected ComboBoxEditor createEditor()
{
return new javax.swing.plaf.metal.MetalComboBoxEditor.UIResource();
}
//
// end UI Initialization
//======================
//======================
// begin Inner classes
//
/**
* This listener checks to see if the key event isn't a navigation key. If
* it finds a key event that wasn't a navigation key it dispatches it to
* JComboBox.selectWithKeyChar() so that it can do type-ahead.
*
* This public inner class should be treated as protected.
* Instantiate it only within subclasses of
* <code>BasicComboBoxUI</code>.
*/
public class KeyHandler extends KeyAdapter
{
public void keyPressed(KeyEvent e)
{
if (comboBox.isEnabled()
&& !isNavigationKey(e.getKeyCode())
&& isTypeAheadKey(e))
{
if (comboBox.selectWithKeyChar(e.getKeyChar()))
{
e.consume();
}
}
}
boolean isTypeAheadKey(KeyEvent e)
{
return !e.isAltDown() && !e.isControlDown() && !e.isMetaDown();
}
}
/**
* This listener watches for changes in the
* <code>ComboBoxModel</code>.
* <p>
* This public inner class should be treated as protected.
* Instantiate it only within subclasses of
* <code>BasicComboBoxUI</code>.
*/
public class ListDataHandler implements ListDataListener
{
public void contentsChanged(ListDataEvent e)
{
if (!(e.getIndex0() == -1 && e.getIndex1() == -1))
{
isMinimumSizeDirty= true;
comboBox.revalidate();
}
// set the editor with the selected item since this
// is the event handler for a selected item change.
if (comboBox.isEditable() && editor != null)
{
comboBox.configureEditor(
comboBox.getEditor(),
comboBox.getSelectedItem());
}
comboBox.repaint();
}
public void intervalAdded(ListDataEvent e)
{
isDisplaySizeDirty= true;
contentsChanged(e);
}
public void intervalRemoved(ListDataEvent e)
{
isDisplaySizeDirty= true;
contentsChanged(e);
}
}
/**
* This listener watches for changes to the selection in the
* combo box.
* <p>
* This public inner class should be treated as protected.
* Instantiate it only within subclasses of
* <code>BasicComboBoxUI</code>.
*/
public class ItemHandler implements ItemListener
{
// This class used to implement behavior which is now redundant.
public void itemStateChanged(ItemEvent e)
{
}
}
/**
* This listener watches for bound properties that have changed in the
* combo box.
* <p>
* Subclasses which wish to listen to combo box property changes should
* call the superclass methods to ensure that the combo box ui correctly
* handles property changes.
* <p>
* This public inner class should be treated as protected.
* Instantiate it only within subclasses of
* <code>BasicComboBoxUI</code>.
*/
public class PropertyChangeHandler implements PropertyChangeListener
{
public void propertyChange(PropertyChangeEvent e)
{
String propertyName= e.getPropertyName();
JComboBox comboBox= (JComboBox) e.getSource();
if (propertyName.equals("model"))
{
ComboBoxModel newModel= (ComboBoxModel) e.getNewValue();
ComboBoxModel oldModel= (ComboBoxModel) e.getOldValue();
if (oldModel != null && listDataListener != null)
{
oldModel.removeListDataListener(listDataListener);
}
if (newModel != null && listDataListener != null)
{
newModel.addListDataListener(listDataListener);
}
if (editor != null)
{
comboBox.configureEditor(
comboBox.getEditor(),
comboBox.getSelectedItem());
}
isMinimumSizeDirty= true;
isDisplaySizeDirty= true;
comboBox.revalidate();
comboBox.repaint();
}
else if (propertyName.equals("editor") && comboBox.isEditable())
{
addEditor();
comboBox.revalidate();
}
else if (propertyName.equals("editable"))
{
if (comboBox.isEditable())
{
comboBox.setRequestFocusEnabled(false);
addEditor();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -