📄 synthcomboboxui.java
字号:
/* * @(#)SynthComboBoxUI.java 1.29 08/06/20 * * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */package javax.swing.plaf.synth;import java.awt.*;import java.awt.event.*;import java.lang.reflect.*;import javax.swing.*;import javax.swing.plaf.*;import javax.swing.event.*;import javax.swing.plaf.basic.*;import java.beans.PropertyChangeListener;import java.beans.PropertyChangeEvent;import sun.swing.plaf.synth.SynthUI;/** * Synth's ComboBoxUI. * * @version 1.29, 06/20/08 * @author Scott Violet */class SynthComboBoxUI extends BasicComboBoxUI implements PropertyChangeListener, SynthUI { private SynthStyle style; private boolean useListColors; /** * Used to adjust the location and size of the popup. Very useful for * situations such as we find in Nimbus where part of the border is used * to paint the focus. In such cases, the border is empty space, and not * part of the "visual" border, and in these cases, you'd like the popup * to be adjusted such that it looks as if it were next to the visual border. * You may want to use negative insets to get the right look. */ Insets popupInsets; /** * This flag may be set via UIDefaults. By default, it is false, to * preserve backwards compatibility. If true, then the combo will * "act as a button" when it is not editable. */ private boolean buttonWhenNotEditable; /** * A flag to indicate that the combo box and combo box button should * remain in the PRESSED state while the combo popup is visible. */ private boolean pressedWhenPopupVisible; /** * When buttonWhenNotEditable is true, this field is used to help make * the combo box appear and function as a button when the combo box is * not editable. In such a state, you can click anywhere on the button * to get it to open the popup. Also, anywhere you hover over the combo * will cause the entire combo to go into "rollover" state, and anywhere * you press will go into "pressed" state. This also keeps in sync the * state of the combo and the arrowButton. */ private ButtonHandler buttonHandler; /** * Handler for repainting combo when editor component gains/looses focus */ private EditorFocusHandler editorFocusHandler; /** * If true, then the cell renderer will be forced to be non-opaque when * used for rendering the selected item in the combo box (not in the list), * and forced to opaque after rendering the selected value. */ private boolean forceOpaque = false; /** * NOTE: This serves the same purpose as the same field in BasicComboBoxUI. * It is here because I could not give the padding field in * BasicComboBoxUI protected access in an update release. */ private Insets padding; public static ComponentUI createUI(JComponent c) { return new SynthComboBoxUI(); } /** * @inheritDoc * * Overridden to ensure that ButtonHandler is created prior to any of * the other installXXX methods, since several of them reference * buttonHandler. */ @Override public void installUI(JComponent c) { buttonHandler = new ButtonHandler(); super.installUI(c); } @Override protected void installDefaults() { //NOTE: This next line of code was added because, since squareButton in //BasicComboBoxUI is private, I need to have some way of reading it from UIManager. //This is an incomplete solution (since it implies that squareButons, //once set, cannot be reset per state. Probably ok, but not always ok). //This line of code should be removed at the same time that squareButton //is made protected in the super class. super.installDefaults(); //This is here instead of in updateStyle because the value for padding //needs to remain consistent with the value for padding in //BasicComboBoxUI. I wouldn't have this value here at all if not //for the fact that I cannot make "padding" protected in any way //for an update release. This *should* be fixed in Java 7 padding = UIManager.getInsets("ComboBox.padding"); updateStyle(comboBox); } private void updateStyle(JComboBox comboBox) { SynthStyle oldStyle = style; SynthContext context = getContext(comboBox, ENABLED); style = SynthLookAndFeel.updateStyle(context, this); if (style != oldStyle) { popupInsets = (Insets)style.get(context, "ComboBox.popupInsets"); useListColors = style.getBoolean(context, "ComboBox.rendererUseListColors", true); buttonWhenNotEditable = style.getBoolean(context, "ComboBox.buttonWhenNotEditable", false); pressedWhenPopupVisible = style.getBoolean(context, "ComboBox.pressedWhenPopupVisible", false); if (oldStyle != null) { uninstallKeyboardActions(); installKeyboardActions(); } forceOpaque = style.getBoolean(context, "ComboBox.forceOpaque", false); } context.dispose(); } @Override protected void installListeners() { comboBox.addPropertyChangeListener(this); comboBox.addMouseListener(buttonHandler); editorFocusHandler = new EditorFocusHandler(comboBox); super.installListeners(); } @Override public void uninstallUI(JComponent c) { if (popup instanceof SynthComboPopup) { ((SynthComboPopup)popup).removePopupMenuListener(buttonHandler); } super.uninstallUI(c); buttonHandler = null; } @Override protected void uninstallDefaults() { SynthContext context = getContext(comboBox, ENABLED); style.uninstallDefaults(context); context.dispose(); style = null; } @Override protected void uninstallListeners() { editorFocusHandler.unregister(); comboBox.removePropertyChangeListener(this); comboBox.removeMouseListener(buttonHandler); buttonHandler.pressed = false; buttonHandler.over = false; super.uninstallListeners(); } @Override public SynthContext getContext(JComponent c) { return getContext(c, getComponentState(c)); } private SynthContext getContext(JComponent c, int state) { return SynthContext.getContext(SynthContext.class, c, SynthLookAndFeel.getRegion(c), style, state); } private Region getRegion(JComponent c) { return SynthLookAndFeel.getRegion(c); } private int getComponentState(JComponent c) { // currently we have a broken situation where if a developer // takes the border from a JComboBox and sets it on a JTextField // then the codepath will eventually lead back to this method // but pass in a JTextField instead of JComboBox! In case this // happens, we just return the normal synth state for the component // instead of doing anything special if (!(c instanceof JComboBox)) return SynthLookAndFeel.getComponentState(c); JComboBox box = (JComboBox)c; if (shouldActLikeButton()) { int state = ENABLED; if ((!c.isEnabled())) { state = DISABLED; } if (buttonHandler.isPressed()) { state |= PRESSED; } if (buttonHandler.isRollover()) { state |= MOUSE_OVER; } if (box.isFocusOwner()) { state |= FOCUSED; } return state; } else { // for editable combos the editor component has the focus not the // combo box its self, so we should make the combo paint focused // when its editor has focus int basicState = SynthLookAndFeel.getComponentState(c); if (box.isEditable() && box.getEditor().getEditorComponent().isFocusOwner()) { basicState |= FOCUSED; } return basicState; } } @Override protected ComboPopup createPopup() { SynthComboPopup p = new SynthComboPopup(comboBox); p.addPopupMenuListener(buttonHandler); return p; } @Override protected ListCellRenderer createRenderer() { return new SynthComboBoxRenderer(); } @Override protected ComboBoxEditor createEditor() { return new SynthComboBoxEditor(); } // // end UI Initialization //====================== @Override public void propertyChange(PropertyChangeEvent e) { if (SynthLookAndFeel.shouldUpdateStyle(e)) { updateStyle(comboBox); } } @Override protected JButton createArrowButton() { SynthArrowButton button = new SynthArrowButton(SwingConstants.SOUTH); button.setName("ComboBox.arrowButton"); button.setModel(buttonHandler); return button; } //================================= // begin ComponentUI Implementation @Override public void update(Graphics g, JComponent c) { SynthContext context = getContext(c); SynthLookAndFeel.update(context, g); context.getPainter().paintComboBoxBackground(context, g, 0, 0, c.getWidth(), c.getHeight()); paint(context, g); context.dispose(); } @Override public void paint(Graphics g, JComponent c) { SynthContext context = getContext(c); paint(context, g); context.dispose(); } protected void paint(SynthContext context, Graphics g) { hasFocus = comboBox.hasFocus(); if ( !comboBox.isEditable() ) { Rectangle r = rectangleForCurrentValue(); paintCurrentValue(g,r,hasFocus); } } @Override public void paintBorder(SynthContext context, Graphics g, int x, int y, int w, int h) { context.getPainter().paintComboBoxBorder(context, g, x, y, w, h); } /** * Paints the currently selected item. */ @Override public void paintCurrentValue(Graphics g,Rectangle bounds,boolean hasFocus) { ListCellRenderer renderer = comboBox.getRenderer(); Component c; c = renderer.getListCellRendererComponent( listBox, comboBox.getSelectedItem(), -1, false, false ); // Fix for 4238829: should lay out the JPanel. boolean shouldValidate = false; if (c instanceof JPanel) { shouldValidate = true; } if (c instanceof UIResource) { c.setName("ComboBox.renderer"); } boolean force = forceOpaque && c instanceof JComponent; if (force) { ((JComponent)c).setOpaque(false); } int x = bounds.x, y = bounds.y, w = bounds.width, h = bounds.height; if (padding != null) { x = bounds.x + padding.left; y = bounds.y + padding.top; w = bounds.width - (padding.left + padding.right); h = bounds.height - (padding.top + padding.bottom); } currentValuePane.paintComponent(g, c, comboBox, x, y, w, h, shouldValidate); if (force) { ((JComponent)c).setOpaque(true); } } /** * @return true if this combo box should act as one big button. Typically * only happens when buttonWhenNotEditable is true, and comboBox.isEditable * is false. */ private boolean shouldActLikeButton() { return buttonWhenNotEditable && !comboBox.isEditable(); } /** * Return the default size of an empty display area of the combo box using * the current renderer and font. * * This method was overridden to use SynthComboBoxRenderer instead of * DefaultListCellRenderer as the default renderer when calculating the * size of the combo box. This is used in the case of the combo not having * any data. * * @return the size of an empty display area * @see #getDisplaySize */ @Override protected Dimension getDefaultSize() { SynthComboBoxRenderer r = new SynthComboBoxRenderer(); Dimension d = getSizeForComponent(r.getListCellRendererComponent(listBox, " ", -1, false, false)); return new Dimension(d.width, d.height); } /** * This has been refactored out in hopes that it may be investigated and * simplified for the next major release. adding/removing * the component to the currentValuePane and changing the font may be * redundant operations. * * NOTE: This method was copied in its entirety from BasicComboBoxUI. Might * want to make it protected in BasicComboBoxUI in Java 7 */ private Dimension getSizeForComponent(Component comp) { currentValuePane.add(comp); comp.setFont(comboBox.getFont()); Dimension d = comp.getPreferredSize(); currentValuePane.remove(comp); return d; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -