我正在使用keyTyped listerner来模拟Windows的组合框功能,以便在用户键入编辑框时自动滚动组合列表框。当使用默认的跨平台LookAndFeel时,它运行良好。 我发现当LookAndFeel更改为系统LookAndFeel时,JComboBox.setSelectedItem出现故障:
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
以下代码使用针对末尾的setSelectedItem(OrigTypeface)调用来恢复编辑框中的原始文本。
使用跨平台LookAndFeel,当用户键入“abc”时,列表框会逐渐显示与列表框中键入的文本匹配的第一个项目。但是,使用System LookAndFeel,编辑框中的文本从“a”变为“b”变为“c”,最后在文本框中仅显示字母“c”,并显示带有条目的列表框第一个字母'c'。实际上,setSelectedItem失败了,并在文本框中放了一个空白。
任何人都知道解决这个问题的方法吗?
getEditor().getEditorComponent().addKeyListener(new KeyAdapter() {
@Override public void keyTyped(KeyEvent ev) {
String OrigTypeface=(String)cb.getEditor().getItem();
if (OrigTypeface==null) OrigTypeface="";
char CurChar=ev.getKeyChar();
String typeface=OrigTypeface + CurChar; character
typeface=typeface.toLowerCase();
if (typeface.length()==0 || (int)CurChar==8) return; // exclude the backspace key
int i,count=cb.getItemCount();
for (i=0;i<count;i++) {
String item=(String)cb.getItemAt(i);
if (item!=null) {
item=item.toLowerCase();
if (item.startsWith(typeface) && cb.getSelectedIndex()!=i) {
int BumpUp=cb.getMaximumRowCount()/2; // normally list-bolx would position the item the end of the list, so we bump its position to the middle
if ((i+BumpUp)<count) cb.setSelectedIndex(i+BumpUp);
cb.setSelectedIndex(i); // select this item
cb.hidePopup(); // hide/show to actually display this item in the scroll list
cb.showPopup();
cb.setSelectedItem(OrigTypeface); // put this item back in the edit box since it gets overridden by the above setSelectedIndex call
break;
}
}
}
}
}
});
这是一个小的java文件,您可以编译并运行它来重新创建此问题。只需在两个组合框中键入“abc”即可。你会看到左边的那个工作正常,但右边没有。
import java.awt.*;
import java.lang.*;
import java.util.*;
import java.io.*;
import javax.swing.*;
import java.awt.event.*;
import java.awt.print.*;
import java.lang.reflect.Method;
import java.awt.font.*; // to get TextAttribute class
import java.awt.geom.*; // to get AffilineTransform
import java.lang.reflect.Array;
import java.nio.charset.*;
import java.text.*; // to get SimpleDateFormat
import javax.swing.event.*;
import java.awt.datatransfer.*;
import java.awt.image.*;
import javax.print.attribute.standard.*;
import javax.print.attribute.standard.Media.*;
import javax.swing.border.*;
import java.awt.Robot;
import java.util.prefs.*;
import java.awt.dnd.*;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.ComboBoxUI;
import javax.swing.plaf.basic.BasicComboBoxUI;
public class demo extends JPanel {
OurComboBox cb1;
OurComboBox cb2;
JLabel lbl1;
JLabel lbl2;
public demo() {
super(new GridLayout(2,2));
JLabel lbl1=new JLabel();
lbl1.setPreferredSize(new Dimension(250, 15));
lbl1.setText("ComboBox using cross-platform L&F");
add(lbl1);
JLabel lbl2=new JLabel();
lbl2.setPreferredSize(new Dimension(250, 15));
lbl2.setText("ComboBox using System L&F");
add(lbl2);
cb1=new OurComboBox();
cb1.setPreferredSize(new Dimension(200, 15));
cb1.setLightWeightPopupEnabled(false);
cb1.setEditable(true); // allow edit box
AddComboItems(cb1);
add(cb1);
// change to System LookAndFeel temporarily
try {UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());}
catch (Exception ex) {}
cb2=new OurComboBox();
cb2.setPreferredSize(new Dimension(200, 15));
cb2.setLightWeightPopupEnabled(false);
cb2.setEditable(true); // allow edit box
AddComboItems(cb2);
add(cb2);
// rever back LookAndFeel
try {UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName()); }
catch (Exception ex) {}
}
// add items to the combo-box
void AddComboItems(OurComboBox cb) {
for (int i=0;i<20;i++) cb.addItem("a"+((Integer)i).toString());
for (int i=0;i<20;i++) cb.addItem("ab"+((Integer)i).toString());
for (int i=0;i<20;i++) cb.addItem("abc"+((Integer)i).toString());
for (int i=0;i<20;i++) cb.addItem("bc"+((Integer)i).toString());
}
/**
* Create the GUI and show it. For thread safety,
* this method should be invoked from the
* event dispatch thread.
*/
private static void createAndShowGUI() {
//Create and set up the window.
JFrame frame = new JFrame("demo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Add content to the window.
frame.add(new demo());
//Display the window.
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
//Schedule a job for the event dispatch thread:
//creating and showing this application's GUI.
SwingUtilities.invokeLater(new Runnable() {
public void run() {
//Turn off metal's use of bold fonts
UIManager.put("swing.boldMetal", Boolean.FALSE);
createAndShowGUI();
}
});
}
}
class OurComboBox extends JComboBox {
public boolean locked;
public OurComboBox cb;
OurComboBox() {
cb=this; // save so it can be accessed inside the key listerner below
getEditor().getEditorComponent().addKeyListener(new KeyAdapter() { // add key listenr to the editor component
@Override public void keyTyped(KeyEvent ev) {
String OrigTypeface=(String)cb.getEditor().getItem();
if (OrigTypeface==null) OrigTypeface=""; // 20150313
char CurChar=ev.getKeyChar();
String typeface=OrigTypeface + CurChar; // getItem() returns the prviously typed text, getKeyChar()) returns the latest character
typeface=typeface.toLowerCase();
if (typeface.length()==0 || (int)CurChar==8) return; // exclude the backspace key
if ((int)CurChar==0xa) return; // just return for now
else { // scroll the combo-box to show the currently typed typefacee
int i,count=cb.getItemCount();
for (i=0;i<count;i++) {
String item=(String)cb.getItemAt(i);
if (item!=null) {
item=item.toLowerCase();
if (item.startsWith(typeface) && cb.getSelectedIndex()!=i) {
cb.locked=true; // don't process item state changed for this change
if ((i+cb.getMaximumRowCount()/2)<count) cb.setSelectedIndex(i+cb.getMaximumRowCount()/2); // try to move the actual index in the middle because java by default shows the selected index at the bottom
cb.setSelectedIndex(i); // select this item
cb.hidePopup(); // hide/show to actually display this item in the scroll list
cb.showPopup();
cb.setSelectedItem(OrigTypeface); // put this item back in the edit box
cb.locked=false;
break;
}
}
}
}
}
});
}
}