2017-05-07 73 views
2

我目前正在JComboBox組件中,我希望有一個下拉選擇組合框內的JTable。我已經擴展了ListCellRenderer,並且在彈出窗口中有表格。JComboBox與JTable作爲ListCellRenderer組件

我想以兩種不同的方式呈現它。第一個作爲彈出窗口不可見時所選行的綁定列的標籤。第二種是在彈出窗口可見時用JScrollPane顯示錶格。

不幸的是,當我這樣做時,彈出窗口正在收縮到列表的行高度,只留下表格的列空間。

如果我只是使用滾動窗口,我可以看到完整的表格,但當彈出窗口不可見時,我看到組合框內的表格不是我想要的。

如何設置表格可以放置的高度,但仍然只有在彈出窗口不可見時才能顯示標籤?

下面是編譯和運行一個小例子:

import java.awt.Color; 
import java.awt.Component; 
import java.awt.event.MouseAdapter; 
import java.awt.event.MouseEvent; 
import javax.swing.JComboBox; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JList; 
import javax.swing.JScrollPane; 
import javax.swing.JTable; 
import javax.swing.ListCellRenderer; 
import javax.swing.event.ListDataEvent; 
import javax.swing.event.ListSelectionEvent; 
import javax.swing.event.ListSelectionListener; 
import javax.swing.table.DefaultTableModel; 

public class TableComboBoxMain { 
    public static void main(String[] args) { 
     JTableComboBox<Employee> combo = new JTableComboBox<>(); 
     combo.addItem(new Employee("April",3)); 
     //combo.setMaximumRowCount(10); 
     combo.setRenderer(new TableListCellRenderer(combo)); 
     JFrame frame = new JFrame("Test Table Combo Box"); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.add(combo); 
     frame.pack(); 
     frame.setVisible(true); 
    } 

    public static class Employee{ 
     String name; 
     int nr; 
     public Employee(String name, int number){ 
      this.name =name; 
      this.nr = number; 
     } 
    } 

    public static class JTableComboBox<E> extends JComboBox<E> implements ListSelectionListener{ 
     @Override 
     public void valueChanged(ListSelectionEvent e) {System.out.println("Row selected"+e.getFirstIndex()); 
      this.setSelectedIndex(e.getFirstIndex()); 
     } 
    } 

    public static class TableListCellRenderer extends JScrollPane implements ListCellRenderer{ 
    JTable table; 
    JTableComboBox combo; 
    boolean mouseListenerAdded; 
    public TableListCellRenderer(JTableComboBox combo){ 
     this.combo=combo; 
     DefaultTableModel model = new DefaultTableModel(); 
     String[] cols1 = new String[]{"1","2","3","4"}; 
     String[] cols2 = new String[]{"Mark","John","April","Mary"}; 
     model.addColumn("Nr", cols1);model.addColumn("Name",cols2); 
     table = new JTable(model);table.setShowGrid(true);table.setGridColor(Color.gray); 
     this.getViewport().add(table); 
    } 
    @Override 
    public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { 
     if(!mouseListenerAdded){ 
      list.addMouseListener(this.getListener()); 
      mouseListenerAdded = true; 
     }//If this is uncommented then the BasicComboPopup size is always no more than 1 row?!! 
     if(!combo.isPopupVisible()){ 
      Employee emp = (Employee) value; 
      return new JLabel(emp.name); 

     }else 
      return this; 
    } 

    public MouseAdapter getListener(){ 
     MouseAdapter adapter = new MouseAdapter(){ 
     @Override 
     public void mousePressed(MouseEvent e) { 
       if(combo.isPopupVisible()){ 
        System.out.println("MouseClicked over list"); 
        int row = table.rowAtPoint(e.getPoint()); 
        if(row>0){ 
         table.setRowSelectionInterval(row-1, row-1); 
         ListDataEvent event = new ListDataEvent(combo,ListDataEvent.CONTENTS_CHANGED,row-1,row-1); 
         combo.contentsChanged(event); 
        } 
       } 
      } 
     }; 
     return adapter; 
    } 
} 
} 
+0

也許看看[概念:編輯和渲染器(http://docs.oracle.com/javase/tutorial/uiswing/components/table.html#editrender)和[使用其他編輯器(HTTP:/ /docs.oracle.com/javase/tutorial/uiswing/components/table.html#editor) – MadProgrammer

+0

非常感謝參考!不幸的是,在過去的幾個星期裏,我對這兩件事進行了相當的研究。我一直在左右創建渲染器。這是我遇到的唯一一個我無法解決的問題。看着圖書館,這似乎是因爲我無法控制的列表行高,因爲我能看到。我可以設置可見行的數量,但是我無法觸摸由列表單元格渲染器中的項目確定的行高度。不過謝謝你! – Mark

回答

0

所以我找到了一個解決問題的辦法。我還沒說完呢,因爲有一些交互我還是希望有:

  1. 我希望能夠以移動列
  2. 我希望能夠有柱彈出菜單
  3. 我想能夠用鼠標垂直滾動

我想發佈解決方案,以防其他人想要一個起點示例。我將在解決這些其他問題時更新我的​​答案。

下面是測試類:

import java.awt.BorderLayout; 
import java.awt.Component; 
import java.awt.event.MouseAdapter; 
import java.awt.event.MouseEvent; 
import javax.swing.DefaultListCellRenderer; 
import javax.swing.JComboBox; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JList; 
import javax.swing.JPanel; 
import javax.swing.JScrollPane; 
import javax.swing.JTable; 
import javax.swing.ScrollPaneConstants; 
import javax.swing.event.ListDataEvent; 
import javax.swing.event.ListSelectionEvent; 
import javax.swing.event.ListSelectionListener; 
import javax.swing.plaf.basic.BasicComboBoxUI; 
import javax.swing.plaf.basic.BasicComboPopup; 
import javax.swing.plaf.basic.ComboPopup; 
import javax.swing.table.DefaultTableModel; 

public class TableComboBoxMain { 
    public static void main(String[] args) { 
     JTableComboBox<String> combo = new JTableComboBox<>(); 
     combo.addItem(""); 
     BasicComboBoxUI ui = new BasicComboBoxUI(){ 
      @Override 
      protected ComboPopup createPopup() { 
       return new BasicComboPopup(comboBox){ 
        @Override 
        protected int getPopupHeightForRowCount(int maxRowCount) { 
         return 100; 
        } 
        @Override 
        protected JScrollPane createScroller() { 
         JScrollPane sp = new JScrollPane(list, 
          ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, 
          ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); 
         sp.getHorizontalScrollBar().setFocusable(false); 
         return sp; 
        } 
       }; 
      } 
     }; 
     combo.setUI(ui); 
     combo.setRenderer(new TableListCellRenderer(combo)); 
     JFrame frame = new JFrame("Test Table Combo Box"); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.add(combo); 
     frame.pack(); 
     frame.setVisible(true); 
    } 

    public static class Employee{ 
     String name; 
     int nr; 
     public Employee(String name, int number){ 
      this.name =name; 
      this.nr = number; 
     } 
    } 

    public static class JTableComboBox<E> extends JComboBox<E> implements ListSelectionListener{ 
     @Override 
     public void valueChanged(ListSelectionEvent e) { 
      System.out.println("Row selected"+e.getFirstIndex()); 
      this.setSelectedIndex(e.getFirstIndex()); 
     } 
    } 

    public static class TableListCellRenderer extends DefaultListCellRenderer{ 
     JTable table; 
     JTableComboBox combo; 
     JPanel renderer = new JPanel(); 
     JPanel colHeader = new JPanel(); 
     JScrollPane scroll = new JScrollPane(); 
     boolean mouseListenerAdded; 
     public TableListCellRenderer(JTableComboBox combo){ 
      this.combo=combo; 
      DefaultTableModel model = new DefaultTableModel(); 
      String[] cols1 = new String[]{"1","2","3","4","5","6"}; 
      String[] cols2 = new String[]{"Mark","John","April","Mary","Joe","Jack"}; 
      model.addColumn("Nr", cols1);model.addColumn("Name",cols2); 
      table = new JTable(model); 
      table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); 
      colHeader.add(table.getTableHeader()); 
      renderer.setLayout(new BorderLayout()); 
      renderer.add(colHeader, BorderLayout.NORTH); 
      renderer.add(table,BorderLayout.CENTER); 
      scroll.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); 
      scroll.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER); 
      scroll.getViewport().add(table); 

     } 
     @Override 
     public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { 
      list.setFixedCellHeight(table.getRowHeight()*(table.getRowCount()+1)+10); 
      list.setFixedCellWidth(table.getPreferredSize().width); 
      JLabel label = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); 
      if(!mouseListenerAdded){ 
       list.addMouseListener(this.getListener()); 
       mouseListenerAdded = true; 
      } 
      if(!combo.isPopupVisible()){ 
       label.setText("Select..."); 
       if(table.getSelectedRowCount()>0) 
        label.setText(""+table.getModel().getValueAt(table.getSelectedRow(),1)); 
       return label; 
      } 
       return scroll; 
     } 

     public MouseAdapter getListener(){ 
      MouseAdapter adapter = new MouseAdapter(){ 
      @Override 
      public void mousePressed(MouseEvent e) { 
        if(combo.isPopupVisible()){ 
         System.out.println("MouseClicked over list"); 
         int row = table.rowAtPoint(e.getPoint()); 
         if(row>0){ 
          table.setRowSelectionInterval(row-1, row-1); 
          ListDataEvent event = new ListDataEvent(combo,ListDataEvent.CONTENTS_CHANGED,row-1,row-1); 
          combo.contentsChanged(event); 
         } 
        } 
       } 
      }; 
      return adapter; 
     } 
    } 
} 

解決方案的關鍵部分是爲了有桌子,你想在一個彈出表的特點是,你需要重寫UI。具體而言,您需要覆蓋BasicComboBoxUI,getPopupHeightForRowCountcreateScroller上的createPopup,BasicComboPopup。最後,在執行getListCellRenderingComponent時,您已設置與表格首選高度和寬度相匹配的固定高度和寬度。這將允許彈出窗口的主滾動器充當表格的滾動窗格。