ListCellRenderer を使用するという Oscar のアイデアに取り組んで、ほとんど機能するものを思いつきました... コンポーネントの値は正しくレンダリングされますが、リストの値には醜いハックが必要です。
リスト項目の場合、(getSize() からの) レンダラーのサイズは、値をレンダリングするために使用できるスペースの幅ではなく、最も長い項目のテキスト幅を反映するため、ハックが必要です。JComboBox 自体を使用してみましたが、その幅には小さなドロップダウン ボタンが含まれているため、スクロールバーが存在する場合、その幅は考慮されません。ハックは、レンダラーの幅がコンボボックスの幅よりも小さい場合はそれを保存し、レンダラーの幅がコンボボックスの幅よりも大きい場合は保存された幅を使用することです。これには、レンダラーの幅が内部 JLabel の幅とコンボボックスの幅の間にあるコーナーケースがあります。
レンダリングスペースはコンボボックスの幅からスクロールバーとインセットの幅を差し引いたものになるため、リストにスクロールバーがあることを知る方法とスクロールバーを取得する方法について誰かが提案を持っている場合は、幅を抽出し、私はすべての耳です。たぶん、list.getParent() を実行して、それが JScrollPane であることを期待できます (JComboBox または JList doco は、スクロール ペインを使用すると述べています)。
これを改善するための他の提案は大歓迎です。
コードは次のとおりです。
recentDirs.setRenderer(new ComboTextRenderer(recentDirs));
...
static private class ComboTextRenderer
extends DefaultListCellRenderer
implements SwingConstants
{
JComponent parent;
int renderWidth;
ComboTextRenderer(JComponent par) {
super();
parent=par;
renderWidth=-1;
}
public void paint(Graphics gc) {
String txt=getText();
int len=txt.length();
int wid=getSize().width;
Insets ins=getInsets();
FontMetrics met=gc.getFontMetrics();
if(renderWidth==-1 || wid<parent.getSize().width) { renderWidth=wid; }
else { wid=renderWidth; }
wid-=(ins.left+ins.right);
if(met.stringWidth(txt)>wid) {
String rpl=null;
for(int xa=0,pfx=Math.min(15,((len/2)-1)),sfx=(pfx+2); pfx>0 && sfx<len; xa++) {
rpl=(txt.substring(0,pfx)+" ... "+txt.substring(sfx));
if(met.stringWidth(rpl)<=wid) { break; }
rpl=null;
if ((len-sfx)>15) { sfx++; }
else if((xa%2)==0 ) { pfx--; }
else { sfx++; }
}
if(rpl!=null) { setText(rpl); }
}
super.paint(gc);
}
}