Swing不醜系列:JComboBox – JAVA編程語言程序開發技術文章

一直都是一隻菜鳥..不管別人怎麼說.
一直認為Swing不醜..所以打算這段時間寫個Swing不醜系列(獻醜瞭)


————————–>>>>>>



話說JComboBox 默認外觀確實不是太好看..在由於本人有時實在太賤.就是想要它好看…所以..這不..又折騰瞭..
其實這個ComboBox  剛開始想改變外觀 隻考慮到renderer 畢竟swing上所有的界面 顯示全靠renderer來控制..
所以  著手寫ComboBoxRenderer.  總是覺的 JComboBox 似乎不太好搞定 因為它不但有顯示框 還有小鍵頭.
還有彈出的List 還有ScrollBar..等等..  似乎不那麼好搞…不過Swing是強大的 ..隻要你能想到..就可以做到.



那麼我們要做幾件事.
1: 重載JComboBox 並且設置面板透明
2: 新建renderer 實現ListCellRenderer接口
3: 重載BasicComboBoxUI


1.重載JComboBox 並且設置面板透明 設置renderer 以及設置 ui
public class IComboBox extends JComboBox{
 
 public IComboBox(){
  super();
  init();
 }
 public IComboBox(ComboBoxModel model){
  super(model);
  init();
 }
 public IComboBox(Object[] items){
  super(items);
  init();
 }
 public IComboBox(Vector<?> items){
  super(items);
  init();
 }
 private void init(){
  setOpaque(false);
  setUI(new IComboBoxUI());
  setRenderer(new IComboBoxRenderer());
  setBackground(XUtil.defaultComboBoxColor);
 }
 public Dimension getPreferredSize(){
  return super.getPreferredSize();
 }
}


2.新建renderer 實現ListCellRenderer接口.註意.這裡的ComboBoxRenderer它是控制combobox彈出的List 並非控制JComboBox的 註意 他實現的是ListCellRenderer
public class IComboBoxRenderer implements ListCellRenderer {
 
 private DefaultListCellRenderer defaultCellRenderer = new DefaultListCellRenderer();


 public IComboBoxRenderer() {
  super();
 }


 public Component getListCellRendererComponent(JList list, Object value,
   int index, boolean isSelected, boolean cellHasFocus) {


  JLabel renderer = (JLabel)defaultCellRenderer.getListCellRendererComponent(
    list, value, index, isSelected, cellHasFocus);
  if(isSelected){
   renderer.setBackground(XUtil.defaultComboBoxBoundsColor);
   renderer.setForeground(Color.WHITE);
  }else{
   renderer.setBackground(Color.WHITE);
  }
  list.setSelectionBackground(XUtil.defaultComboBoxColor);
  list.setBorder(null);
  renderer.setFont(XUtil.defaultComboBoxFont);
  renderer.setHorizontalAlignment(JLabel.CENTER);
  return renderer;
 }
}


3重載BasicComboBoxUI .sure 這裡當然要註意.因為他是JComboBox的繪制機制
這裡包括ComboBox右邊的那個箭頭的Button.(我們已經通過重寫 createArrowButton 來改變這個Button);
至於彈出的List ,it in here, look it ..createPoput(); it create ComboPopup.(不好意思 最近在學英文 總是那麼順口來那麼幾句.)
這裡存在一個ScrollPane  它包含瞭List.並且我們重寫ScrollPane的paintBorder方法 來讓我們畫出List的Border


public class IComboBoxUI extends BasicComboBoxUI {


 private JButton arrow;
 private boolean boundsLight = false;
 private static final int ARCWIDTH = 15;
 private static final int ARCHEIGHT = 15;


 public IComboBoxUI() {
  super();
 }


 protected JButton createArrowButton() {
  arrow = new JButton();
  arrow.setIcon(XUtil.defaultComboBoxArrowIcon);
  arrow.setRolloverEnabled(true);
  arrow.setRolloverIcon(XUtil.defaultComboBoxArrowIcon_Into);
  arrow.setBorder(null);
  arrow.setBackground(XUtil.defaultComboBoxColor);
  arrow.setOpaque(false);
  arrow.setContentAreaFilled(false);
  return arrow;
 }


 public void paint(Graphics g, JComponent c) {
  hasFocus = comboBox.hasFocus();
  Graphics2D g2 = (Graphics2D)g;
  if (!comboBox.isEditable()) {
   Rectangle r = rectangleForCurrentValue();
   //重點:JComboBox的textfield 的繪制 並不是靠Renderer來控制 這點讓我很吃驚.
   //它會通過paintCurrentValueBackground來繪制背景
   //然後通過paintCurrentValue();去繪制JComboBox裡顯示的值
   paintCurrentValueBackground(g2, r, hasFocus);
   paintCurrentValue(g2, r, hasFocus);
  }
 
  g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
    RenderingHints.VALUE_ANTIALIAS_ON);
  int width = (int) this.getPreferredSize(c).getWidth()
    + arrow.getWidth() – 2;
  int height = 0;
  int heightOffset = 0;
  if (comboBox.isPopupVisible()) {
   heightOffset = 5;
   height = (int) this.getPreferredSize(c).getHeight();
   arrow.setIcon(XUtil.defaultComboBoxArrowIcon_Into);
  } else {
   heightOffset = 0;
   height = (int) this.getPreferredSize(c).getHeight() – 1;
   arrow.setIcon(XUtil.defaultComboBoxArrowIcon);
  }
  if (comboBox.isFocusable()) {
   g2.setColor(new Color(150, 207, 254));
  }
  g2.drawRoundRect(0, 0, width, height + heightOffset,ARCWIDTH,ARCHEIGHT);
 }


 public void paintCurrentValue(Graphics g, Rectangle bounds, boolean hasFocus) {
  Font oldFont = comboBox.getFont();
  comboBox.setFont(XUtil.defaultComboBoxFont);
 
  super.paintCurrentValue(g, bounds, hasFocus);
  comboBox.setFont(oldFont);
 }


 public Dimension getPreferredSize(JComponent c) {
  return super.getPreferredSize(c);
 }


 public boolean isBoundsLight() {
  return boundsLight;
 }


 public void setBoundsLight(boolean boundsLight) {
  this.boundsLight = boundsLight;
 }


 protected ComboPopup createPopup() {
  ComboPopup popup = new BasicComboPopup(comboBox) {
   protected JScrollPane createScroller() {
    IScrollPane sp = new IScrollPane(list,
      ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
      ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
    sp.setHorizontalScrollBar(null);
    return sp;
   }
   //重載paintBorder方法 來畫出我們想要的邊框..
   public void paintBorder(Graphics g){
    Graphics2D g2 = (Graphics2D) g;
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
      RenderingHints.VALUE_ANTIALIAS_ON);
    g2.setColor(new Color(150, 207, 254));
    g2.drawRoundRect(0,-arrow.getHeight(),getWidth()-1,getHeight()+arrow.getHeight()-1,0,0);
   }
  };
  return popup;
 }
}
ok. 那麼到這裡 ComboBox這塊已經end 但是似乎還有個問題存在  那就是createPopup 方法裡的ScrollPane的滾動條還是有點醜.
so。.next 我們搞定 it.


1:繼承 ScrollBar 並且 setUI();
2:繼承 BasicScrollBarUI 我們來G出我們的效果.
paintThumb 繪制scrollbar裡拖動的小box 我們先畫個邊框 and draw two Orange line.
paintTrack 繪制scrollbar裡小box的軌跡.也就是那個啥(術語怎麼說來著?拖拽滑塊?).
註意:我們首先將Graphics設置透明後 在去畫面板 然後立刻把Graphics設置為不透明..
這樣是為瞭能讓我們把軌跡左邊邊界畫出來…
createIncreaseButton draw down arrowButton 小心 千萬不要use JButton button  = new JButton();
should use BasicAr

發佈留言