2013-02-22 74 views
3

我遇到了一個前面已經討論過的問題:獲取包含JTableJScrollPane,以按我的意願顯示水平滾動條。 HERE是我試過的帖子,但由於某種原因,它似乎不適用於我的情況(我認爲這是因爲我已將其中一列設置爲固定寬度)基於一列寬度的JTable水平滾動條

這是一個SSCCE:

import javax.swing.JFrame; 
import javax.swing.JScrollPane; 
import javax.swing.JTable; 
import javax.swing.table.DefaultTableModel; 

@SuppressWarnings("serial") 
public class TableScrollTest extends JFrame 
{ 
    public TableScrollTest() { 

     DefaultTableModel model = new DefaultTableModel(new Object[]{"key", "value"},0); 
     model.addRow(new Object[]{"short", "blah"}); 
     model.addRow(new Object[]{"long", "blah blah blah blah blah blah blah"}); 

     JTable table = new JTable(model) { 
      public boolean getScrollableTracksViewportWidth() { 
       return getPreferredSize().width < getParent().getWidth(); 
      } 
     };   
     table.getColumn("key").setPreferredWidth(60); 
     table.getColumn("key").setMinWidth(60); 
     table.getColumn("key").setMaxWidth(60); 
     table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); 

     JScrollPane scrollPane = new JScrollPane(table); 
     getContentPane().add(scrollPane); 
    } 

    public static void main(String[] args) { 
     TableScrollTest frame = new TableScrollTest(); 
     frame.setDefaultCloseOperation(EXIT_ON_CLOSE); 
     frame.pack(); 
     frame.setSize(200, 200); 
     frame.setResizable(false); 
     frame.setVisible(true); 
    } 
} 

總之,我有兩列的表,用於顯示鍵/值對。保持所述表中的容器是固定寬度的,並且該表的第一列也是固定的寬度(因爲我知道如何長的所有鍵名將是)第二列將包含不同字符串長度的值水平滾動條應該只出現在存在的值太長而不適合列分配的寬度時

enter image description here

由於上述第二值具有這樣的長的長度,滾動條應該是可見的。然而,事實並非如此,而且我所嘗試過的所有方法都只能成功地使其始終可見,這不是我想要的......我只希望它在「長」值存在的情況下可見。看起來好像getScrollableTracksViewportWidth()方法在表構造函數中被覆蓋,檢查表的首選寬度是什麼......所以我需要引導表根據第二列的內容來選擇更大的寬度......但是我很難過。

任何想法?

+1

你直接的問題是,因爲你覆蓋'getScrollableTracksViewportWidth'這意味着該表格永遠不會比滾動窗格更寬... – MadProgrammer 2013-02-22 01:07:55

+0

@MadProgrammer你確定嗎?我鏈接的示例中已覆蓋該方法,並且在該示例中,表的確會比滾動窗格更寬。 – The111 2013-02-22 01:11:36

+1

但是表的preferredWidth是基於'TableColumn'的寬度,它沒有考慮到內容的寬度,這意味着除非你改變第二列的寬度,就像改變第一列的寬度一樣,將始終返回「true」。我刪除了'getScrollableTracksViewportWidth'方法並手動調整了列的大小,並能夠顯示水平滾動條。 – MadProgrammer 2013-02-22 01:14:09

回答

6

這是一個hackey溶液

基本上,它的作用是根據從所有的行中的值的所有列的「優選的」寬度。

它考慮到對模型的更改以及父容器的更改。

一旦完成,它會檢查「首選」寬度是大於還是小於可用空間,並相應地設置變量。

您可以添加固定列的檢查(我沒有打擾過),這會使進程「略快」一些,但是隨着您向表中添加更多的列和行,這會受到影響,因爲每次更新都是將需要整個模型的散步。

你可以把某種緩存,但說得對,那麼,我會考慮固定寬度的列;)

import java.awt.Container; 
import java.awt.EventQueue; 
import java.awt.event.ComponentAdapter; 
import java.awt.event.ComponentEvent; 
import javax.swing.JFrame; 
import static javax.swing.JFrame.EXIT_ON_CLOSE; 
import javax.swing.JScrollPane; 
import javax.swing.JTable; 
import javax.swing.JViewport; 
import javax.swing.UIManager; 
import javax.swing.UnsupportedLookAndFeelException; 
import javax.swing.event.ChangeEvent; 
import javax.swing.event.ListSelectionEvent; 
import javax.swing.event.TableColumnModelEvent; 
import javax.swing.event.TableColumnModelListener; 
import javax.swing.event.TableModelEvent; 
import javax.swing.table.DefaultTableModel; 
import javax.swing.table.TableColumn; 
import javax.swing.table.TableColumnModel; 

public class TableScrollTest extends JFrame { 

    public TableScrollTest() { 

     DefaultTableModel model = new DefaultTableModel(new Object[]{"key", "value"}, 0); 
     model.addRow(new Object[]{"short", "blah"}); 
     model.addRow(new Object[]{"long", "blah blah blah blah blah blah blah"}); 

     JTable table = new JTable(model) { 
      private boolean trackViewportWidth = false; 
      private boolean inited = false; 
      private boolean ignoreUpdates = false; 

      @Override 
      protected void initializeLocalVars() { 
       super.initializeLocalVars(); 
       inited = true; 
       updateColumnWidth(); 
      } 

      @Override 
      public void addNotify() { 
       super.addNotify(); 
       updateColumnWidth(); 
       getParent().addComponentListener(new ComponentAdapter() { 
        @Override 
        public void componentResized(ComponentEvent e) { 
         invalidate(); 
        } 
       }); 
      } 

      @Override 
      public void doLayout() { 
       super.doLayout(); 
       if (!ignoreUpdates) { 
        updateColumnWidth(); 
       } 
       ignoreUpdates = false; 
      } 

      protected void updateColumnWidth() { 
       if (getParent() != null) { 
        int width = 0; 
        for (int col = 0; col < getColumnCount(); col++) { 
         int colWidth = 0; 
         for (int row = 0; row < getRowCount(); row++) { 
          int prefWidth = getCellRenderer(row, col). 
            getTableCellRendererComponent(this, getValueAt(row, col), false, false, row, col). 
            getPreferredSize().width; 
          colWidth = Math.max(colWidth, prefWidth + getIntercellSpacing().width); 
         } 

         TableColumn tc = getColumnModel().getColumn(convertColumnIndexToModel(col)); 
         tc.setPreferredWidth(colWidth); 
         width += colWidth; 
        } 

        Container parent = getParent(); 
        if (parent instanceof JViewport) { 
         parent = parent.getParent(); 
        } 

        trackViewportWidth = width < parent.getWidth(); 
       } 
      } 

      @Override 
      public void tableChanged(TableModelEvent e) { 
       super.tableChanged(e); 
       if (inited) { 
        updateColumnWidth(); 
       } 
      } 

      public boolean getScrollableTracksViewportWidth() { 
       return trackViewportWidth; 
      } 

      @Override 
      protected TableColumnModel createDefaultColumnModel() { 
       TableColumnModel model = super.createDefaultColumnModel(); 
       model.addColumnModelListener(new TableColumnModelListener() { 
        @Override 
        public void columnAdded(TableColumnModelEvent e) { 
        } 

        @Override 
        public void columnRemoved(TableColumnModelEvent e) { 
        } 

        @Override 
        public void columnMoved(TableColumnModelEvent e) { 
         if (!ignoreUpdates) { 
          ignoreUpdates = true; 
          updateColumnWidth(); 
         } 
        } 

        @Override 
        public void columnMarginChanged(ChangeEvent e) { 
         if (!ignoreUpdates) { 
          ignoreUpdates = true; 
          updateColumnWidth(); 
         } 
        } 

        @Override 
        public void columnSelectionChanged(ListSelectionEvent e) { 
        } 
       }); 
       return model; 
      } 
     }; 
     table.getColumn("key").setPreferredWidth(60); 
//  table.getColumn("key").setMinWidth(60); 
//  table.getColumn("key").setMaxWidth(60); 
//  table.setAutoResizeMode(JTable.AUTO_RESIZE_NEXT_COLUMN); 

     JScrollPane scrollPane = new JScrollPane(table); 
     getContentPane().add(scrollPane); 
    } 

    public static void main(String[] args) { 
     EventQueue.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       try { 
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
       } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { 
       } 

       TableScrollTest frame = new TableScrollTest(); 
       frame.setDefaultCloseOperation(EXIT_ON_CLOSE); 
       frame.pack(); 
       frame.setSize(200, 200); 
       frame.setResizable(true); 
       frame.setVisible(true); 
      } 
     }); 
    } 
} 
+0

謝謝!這與我上面提到的非常相似,但是我只是因爲你的評論和@ kleopatra的帖子而與我聯繫。然而,在你的解決方案中有一個小錯誤...你的寬度累加了每一行的寬度值......所以你添加的行越多,你在每行末尾得到的「死」空間就越多。我想你想像我一樣使用最大化功能。但是,我仍然需要在我的回答中添加我評論的1-5像素模糊因子。 Upvoting你的幫助。 :-) – The111 2013-02-22 01:40:34

+0

也會接受這個答案,因爲覆蓋到'addNotify','tableChanged'等是聰明的,並使其全部自動。我計劃在每次更改表格時手動調用一些'update'方法,但將它包含在表格定義中就像你做的那樣好得多。 – The111 2013-02-22 01:42:41

+1

@ The111固定錯誤 - 也加入了intercellSpacing因子。好地方! – MadProgrammer 2013-02-22 01:58:17

4

看來那時,我的目標是迫使單元格渲染自動使細胞適應長串

這不是渲染器的工作。您必須手動設置列的寬度。

請參閱Table Column Adjuster一個方法來做到這一點。

1

如果發佈了更智能的東西,我不一定會接受這個答案,但這裏是我自己根據迄今爲止發佈的評論和THIS發佈的數據找出的解決方案。唯一的問題是,我想要的寬度總是約1像素太短(在一些外觀和感覺是好的),所以我在末端width += 5附近添加了這條線,這似乎使它工作正常,但對我來說感覺很不好。歡迎對此方法發表任何意見。

import java.awt.Component; 

import javax.swing.JFrame; 
import javax.swing.JScrollPane; 
import javax.swing.JTable; 
import javax.swing.table.DefaultTableModel; 
import javax.swing.table.TableCellRenderer; 

@SuppressWarnings("serial") 
public class TableScrollTest extends JFrame { 
    public TableScrollTest() { 
     DefaultTableModel model = new DefaultTableModel(new Object[]{"key", "value"},0); 
     model.addRow(new Object[]{"short", "blah"}); 
     model.addRow(new Object[]{"long", "blah blah blah blah blah blah blah"}); 

     JTable table = new JTable(model);   
     table.getColumn("key").setPreferredWidth(60); 
     table.getColumn("key").setMinWidth(60); 
     table.getColumn("key").setMaxWidth(60); 
     table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); 

     int width = 0; 
     for (int row = 0; row < table.getRowCount(); row++) { 
      TableCellRenderer renderer = table.getCellRenderer(row, 1); 
      Component comp = table.prepareRenderer(renderer, row, 1); 
      width = Math.max (comp.getPreferredSize().width, width); 
     } 
     width += 5; 
     table.getColumn("value").setPreferredWidth(width); 
     table.getColumn("value").setMinWidth(width); 
     table.getColumn("value").setMaxWidth(width); 

     JScrollPane scrollPane = new JScrollPane(table); 
     getContentPane().add(scrollPane); 
    } 

    public static void main(String[] args) { 
     TableScrollTest frame = new TableScrollTest(); 
     frame.setDefaultCloseOperation(EXIT_ON_CLOSE); 
     frame.pack(); 
     frame.setSize(200, 200); 
     frame.setResizable(false); 
     frame.setVisible(true); 
    } 
} 
+1

使用['JTable.getIntercellSpacing().width'](http://docs.oracle.com/javase/7/docs/api/javax/swing/JTable.html#getIntercellSpacing%28%29)而不是「fudging 「像素填充 – MadProgrammer 2013-02-22 01:59:25

+0

@MadProgrammer酷,感謝您的提示和更新您的解決方案。 – The111 2013-02-22 02:41:11