这段时间项目上需要用 JComboBox,用上发现这个JComboBox真是问题多多,其中一个烦人的问题就是选择一个item后,显示出了一个难看的背景,查找了很多方法,发现其实是在BasicComboBoxUI.paintCurrentValue( Graphics g, Rectangle bounds, boolean hasFocus )中的多余的调用:
if( hasFocus && ! isPopupVisible( comboBox ) )
{
c.setForeground( listBox.getSelectionForeground() );
c.setBackground( listBox.getSelectionBackground() );
}
我开始想在 popupMenuWillBecomeInvisible中用listBox.setSelectionForeground( Color.WHITE ),但是这要用到反射,并且要用setAccessible,一旦SUN以后改了listBox的名字,这会出问题的,心灰意冷之时,忽然想到可以把 JComboBox的ListCellRenderer给它设成透明的,setOpaque(),这样,当选择完成后,不就只画JComboBox的背景了吗?如下是代码:
class TestComboFocus extends javax.swing.JFrame implements javax.swing.event.PopupMenuListener
{
private javax.swing.JComboBox combo;
public TestComboFocus( String title )
{
super( title );
combo = new javax.swing.JComboBox( new String[]{ "one person in this city", "two persons in this city" } );
combo.addPopupMenuListener( this );
combo.setBackground( java.awt.Color.WHITE ); hideComboFocus( false );
this.getContentPane().setLayout( new java.awt.FlowLayout() );
this.getContentPane().add( combo );
this.setBounds( 100, 100, 400, 300 );
this.setVisible( true );
}
public void popupMenuCanceled( javax.swing.event.PopupMenuEvent e ){}
public void popupMenuWillBecomeVisible( javax.swing.event.PopupMenuEvent e )
{
System.err.println( "popupMenuWillBecomeVisible" );
hideComboFocus( true );
}
public void popupMenuWillBecomeInvisible( javax.swing.event.PopupMenuEvent e )
{
System.err.println( "popupMenuWillBecomeInvisible" );
hideComboFocus( false );
}
private final void hideComboFocus( boolean hidden )
{
if( combo == null ){ return; }
javax.swing.ListCellRenderer comp = combo.getRenderer();
if( comp instanceof javax.swing.JComponent ){ ( (javax.swing.JComponent)comp ).setOpaque( hidden ); }
}
public static void main( String[] args ){ new TestComboFocus( "Test ComboFocus" ); }
}
2010.10.19补充,最近研究CellRendererPane,发现这个去掉背景色还有个更好的办法:
将JComboBox设置为可编辑,将里面的Editor(其实就是JTextField)设置为不可编辑,设置选择颜色为白色,如下:
public class TestComboFocus2 extends javax.swing.JFrame
{
private javax.swing.JComboBox combo;
public TestComboFocus2( String title )
{
super( title );
this.getContentPane().setLayout( new java.awt.FlowLayout() );
this.getContentPane().add( combo = new javax.swing.JComboBox( new String[]{ "one person in this city", "two persons in this city" } ) );
this.setBounds( 100, 100, 400, 300 );
this.setVisible( true );
this.disableFocusBackground( combo );
}
private void disableFocusBackground( javax.swing.JComboBox combo )
{
if( combo == null ){ return; }
java.awt.Component comp = combo.getEditor().getEditorComponent();
if( comp instanceof javax.swing.JTextField )
{
javax.swing.JTextField field = (javax.swing.JTextField)comp;
field.setEditable( false );
field.setSelectionColor( field.getBackground()/*java.awt.Color.WHITE*/ );
combo.setEditable( true );
}
}
public static void main( String[] args ){ new TestComboFocus2( "Test ComboFocus2" ); }
}
class NoBackgroundComboBoxUI extends javax.swing.plaf.basic.BasicComboBoxUI
{
protected java.awt.Rectangle rectangleForCurrentValue()
{
java.awt.Rectangle rect = super.rectangleForCurrentValue();
//The root cause is that this method return an invalid Rectangle, so it limited the bounds of Graphics
return rect;
}
}