2013-09-25 113 views
5

我需要为JTable的几列指定固定宽度,然后对所有其他列指定相等的宽度。按百分比设置JTable的列宽

假设JTable有5列。第一列的宽度应为100,第二列的宽度应为150.如果在设置两列的宽度后JTable的剩余宽度为600,则我希望将其平均分配到其他三列中。

问题是table.getParent().getSize().width通常是0,即使它被添加到JFrame并且可见,所以我不能用它作为基础。

我如何去这样做呢?

+2

如果一个答案适用于你,接受它。 – Astrobleme

回答

3

我想你需要用table.getPreferredSize()来代替。试试这个代码片段:

import java.awt.Dimension; 
import javax.swing.JFrame; 
import javax.swing.JScrollPane; 
import javax.swing.JTable; 
import javax.swing.SwingUtilities; 
import javax.swing.table.DefaultTableModel; 


public class Tests { 

    private void initGUI(){   
     Object[] tableHeader = new Object[]{"Name", "Category", "Color","Ranking"}; 
     DefaultTableModel dftm = new DefaultTableModel(tableHeader, 0);   
     dftm.addRow(new Object[]{"Watermelon","Fruit","Green and red",3}); 
     dftm.addRow(new Object[]{"Tomato","Vegetable","Red",5}); 
     dftm.addRow(new Object[]{"Carrot","Vegetable","Orange",2}); 

     JTable table = new JTable(dftm); 

     JScrollPane scrollPane = new JScrollPane(); 
     scrollPane.setViewportView(table); 

     Dimension tableSize = table.getPreferredSize(); 
     table.getColumn("Name").setPreferredWidth(100); 
     table.getColumn("Category").setPreferredWidth(150); 
     table.getColumn("Color").setPreferredWidth(Math.round((tableSize.width - 250)* 0.70f)); 
     table.getColumn("Ranking").setPreferredWidth(Math.round((tableSize.width - 250)* 0.30f)); 

     JFrame frame = new JFrame("Demo"); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.getContentPane().add(scrollPane); 
     frame.pack(); 
     frame.setLocationRelativeTo(null); 
     frame.setVisible(true); 
    } 

    /** 
    * @param args the command line arguments 
    */ 
    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       new Tests().initGUI(); 
      } 
     });   

    } 
} 

正如你所看到的,Name列将具有100宽度,Category将有150的宽度,Color列将在合适宽度剩余的70%和Ranking将适合的最后30%。

更新

基于此评论:

谢谢,但如果Jframe的大小设置得比JTable中明确 较大,这将不起作用......

解决方法可以使用setMinWidthsetMaxWidth方法修复静态列宽,也可以实现自己的TableColumnModelListener。在上面的例子中代替setPreferredWith线如下,并尝试设置帧的优选尺寸为您希望:

final JTable table = new JTable(dftm);   
    table.getColumnModel().addColumnModelListener(new TableColumnModelListener() { 

     @Override 
     public void columnAdded(TableColumnModelEvent e) { 
      table.columnAdded(e); 
     } 

     @Override 
     public void columnRemoved(TableColumnModelEvent e) { 
      table.columnRemoved(e); 
     } 

     @Override 
     public void columnMoved(TableColumnModelEvent e) { 
      table.columnMoved(e); 
     } 

     @Override 
     public void columnMarginChanged(ChangeEvent e) { 
      Dimension tableSize = table.getSize(); 
      table.getColumn("Name").setWidth(100); 
      table.getColumn("Category").setWidth(150); 
      table.getColumn("Color").setWidth(Math.round((tableSize.width - 250)* 0.70f)); 
      table.getColumn("Ranking").setWidth(Math.round((tableSize.width - 250)* 0.30f)); 
     } 

     @Override 
     public void columnSelectionChanged(ListSelectionEvent e) { 
      table.columnSelectionChanged(e); 
     } 
    }); 
+0

谢谢,但如果JFrame的大小设置为明确大于JTable,则这不起作用... –

+1

我明白了你的观点。玩setMinWidth'和'setMaxWidth'方法怎么样?例如,对于第一列,您可以调用'setMinWidth(100)'和'setMaxWidth(100)'。无论帧的大小,甚至帧的大小调整,其宽度将始终为100。 – dic19

+0

@TomTucker请参阅最新的答案。 – dic19

5

我需要一个固定的宽度相等的宽度分配给一个JTable的几列,然后向所有的其他栏目。

让表格的调整大小模式为您做好工作。设置的调整模式,所有列,并设置固定列的最小值/最大值:

import java.awt.*; 
import javax.swing.*; 
import javax.swing.table.*; 

public class TableLayout extends JPanel 
{ 
    public TableLayout() 
    { 
     setLayout(new BorderLayout()); 

     JTable table = new JTable(5, 7); 
     add(new JScrollPane(table)); 

     table.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); 
     TableColumn columnA = table.getColumn("A"); 
     columnA.setMinWidth(100); 
     columnA.setMaxWidth(100); 
     TableColumn columnC = table.getColumn("C"); 
     columnC.setMinWidth(50); 
     columnC.setMaxWidth(50); 
    } 

    private static void createAndShowUI() 
    { 
     JFrame frame = new JFrame("TableLayout"); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.add(new TableLayout()); 
     frame.setSize(600, 200); 
     frame.setLocationByPlatform(true); 
     frame.setVisible(true); 
    } 

    public static void main(String[] args) 
    { 
     EventQueue.invokeLater(new Runnable() 
     { 
      public void run() 
      { 
       createAndShowUI(); 
      } 
     }); 
    } 
} 
+0

+1:当调整模式为AUTO_RESIZE_ALL_COLUMNS时,'column.setPreferredWidth()'不起作用,所以必须使用'setMin/MaxWidth()'。 – Matthieu

0

我不得不动态设置我的表中的列宽为一个项目,必须在不同的屏幕分辨率DPI设置正确显示。我的解决方案的想法来自dic19s的答案。

基本上我得到了JPanel的首选大小,JTable的JSrollPane被放置并工作得很好。请参考下面

Dimension tableSize = tableScrollPanePanel.getPreferredSize(); 
table.getColumnModel().getColumn(0).setPreferredWidth(Math.round(tableSize.width*0.35f)); 
table.getColumnModel().getColumn(1).setPreferredWidth(Math.round(tableSize.width*0.215f)); 
table.getColumnModel().getColumn(2).setPreferredWidth(Math.round(tableSize.width*0.20f)); 
table.getColumnModel().getColumn(3).setPreferredWidth(Math.round(tableSize.width*0.10f)); 
table.getColumnModel().getColumn(4).setPreferredWidth(Math.round(tableSize.width*0.10f)); 

希望这有助于有人

感谢

9
public MyJFrame() { 
    initComponents(); 
    resizeColumns(); 
    addComponentListener(new ComponentAdapter() { 
     @Override 
     public void componentResized(ComponentEvent e) { 
      resizeColumns(); 
     } 
    }); 
} 
//SUMS 100% 
float[] columnWidthPercentage = {20.0f, 55.0f, 10.0f, 5.0f, 5.0f, 5.0f}; 

private void resizeColumns() { 
    int tW = jTable1.getWidth(); 
    TableColumn column; 
    TableColumnModel jTableColumnModel = jTable1.getColumnModel(); 
    int cantCols = jTableColumnModel.getColumnCount(); 
    for (int i = 0; i < cantCols; i++) { 
     column = jTableColumnModel.getColumn(i); 
     int pWidth = Math.round(columnWidthPercentage[i] * tW); 
     column.setPreferredWidth(pWidth); 
    } 
} 
+1

这是我见过的最好的答案:) – 2015-08-17 07:11:05

+0

请注意,您可以使用['TableColumnModel.getTotalColumnWidth()'](https://docs.oracle.com/javase/7/docs/api/javax/swing/table /TableColumnModel.html#getTotalColumnWidth()),以防您的表包含在“JScrollPane”中(通常是这种情况)。 – Matthieu

+0

晚了一点,但columnWidthPercentage应该加起来1.0,否则你的桌子会变得非常快 –

0

它认为这将是更容易使用(和再利用)相对组分调整,如果我们在自己的封装它类。由于我也面临同样的问题,我想在这里发布我的代码。

从客户端的角度来看,我想这样做

TableColumnModel columnModel = jTable.getColumnModel(); 

TableColumn firstColumn = columnModel.getColumn(0); 
TableColumn secondColumn = columnModel.getColumn(1); 

ComponentResize<TableColumn> columnResize = new TableColumnResize(); 
RelativeWidthResizer<TableColumn> relativeWidthResizer = new RelativeWidthResizer<TableColumn>(columnResize); 

relativeWidthResizer.setRelativeWidth(firstColumn, 0.8); 
relativeWidthResizer.setRelativeWidth(secondColumn, 0.2); 

jTable.addComponentListener(relativeWidthResizer); 

所以我首先定义了ComponentResize接口和实现TableColumnResize

public interface ComponentResize<T> { 
    public void setWidth(T component, int width); 
} 

public class TableColumnResize implements ComponentResize<TableColumn> { 

    public void setWidth(TableColumn component, int width) { 
     component.setPreferredWidth(width); 
    } 
} 

ComponentResize接口解耦组件大小的方式是从具体的API中设置的。例如。一个TableColumn的宽度可以通过setPreferredWidth(int)被设置而JComponent的尺寸可以通过setPreferredWidth(Dimension)

比我实现封装的相对宽度计算逻辑的RelativeWidthResizer进行设置。

public class RelativeWidthResizer<T> extends ComponentAdapter { 

    private Map<T, Double> relativeWidths = new HashMap<T, Double>(); 
    private ComponentResize<T> componentResize; 

    public RelativeWidthResizer(ComponentResize<T> componentResize) { 
     this.componentResize = componentResize; 
    } 

    public void setRelativeWidth(T component, double relativeWidth) { 
     if (relativeWidth < 0.0) { 
      throw new IllegalArgumentException(
        "Relative width must be greater or equal to 0.0"); 
     } 

     if (relativeWidth > 1.0) { 
      throw new IllegalArgumentException(
        "Relative width must be less or equal to 1.0"); 
     } 

     double totalRelativeWidth = 0.0; 
     for (Double relativeComponentWidth : relativeWidths.values()) { 
      totalRelativeWidth += relativeComponentWidth.doubleValue(); 
     } 

     double availableRelativeWidth = 1.0d - (totalRelativeWidth + relativeWidth); 

     boolean totalPercentageExceeded = availableRelativeWidth < 0; 
     if (totalPercentageExceeded) { 
      double remainingRelativeWidth = 1.0d - totalRelativeWidth; 
      String message = MessageFormat.format(
        "Can't set component's relative width to {0}." 
          + " {1} relative width remaining", relativeWidth, 
        remainingRelativeWidth); 
      throw new IllegalArgumentException(message); 
     } 

     relativeWidths.put(component, relativeWidth); 
    } 

    @Override 
    public void componentResized(ComponentEvent e) { 
     Component component = e.getComponent(); 
     apply(component); 
    } 

    public void apply(Component baseComponent) { 
     Dimension size = baseComponent.getSize(); 
     int maxWidth = (int) size.getWidth(); 

     int remaining = maxWidth; 

     Set<Entry<T, Double>> entrySet = relativeWidths.entrySet(); 
     Iterator<Entry<T, Double>> entrySetIter = entrySet.iterator(); 

     while (entrySetIter.hasNext()) { 
      Entry<T, Double> componentEntry = entrySetIter.next(); 
      T componentToResize = componentEntry.getKey(); 
      Double relativeWidth = componentEntry.getValue(); 

      int width = (int) (maxWidth * relativeWidth.doubleValue()); 
      remaining -= width; 

      boolean lastComponent = !entrySetIter.hasNext(); 
      if (lastComponent && remaining > 0) { 
       width += remaining; 
      } 
      componentResize.setWidth(componentToResize, width); 
     } 
    } 
} 
相关问题