【问题标题】:Set Column Width of JTable by Percentage按百分比设置 JTable 的列宽
【发布时间】:2013-10-01 12:05:32
【问题描述】:

我需要为JTable 的几列分配固定宽度,然后为所有其他列分配相同的宽度。

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

问题是table.getParent().getSize().width经常是0,即使加到JFrame上也是可见的,所以不能作为依据。

我该怎么做?

【问题讨论】:

  • 如果答案对你有用,请接受。

标签: java swing percentage jtableheader preferredsize


【解决方案1】:
public MyJFrame() {
    initComponents();
    resizeColumns();
    addComponentListener(new ComponentAdapter() {
        @Override
        public void componentResized(ComponentEvent e) {
            resizeColumns();
        }
    });
}
//SUMS 1
float[] columnWidthPercentage = {0.2f, 0.55f, 0.1f, 0.05f, 0.05f, 0.05f};

private void resizeColumns() {
    // Use TableColumnModel.getTotalColumnWidth() if your table is included in a JScrollPane
    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);
    }
}

【讨论】:

  • 这是我见过的最好的答案:)
  • 请注意,如果您的表包含在JScrollPane 中(通常是这种情况),您可以使用TableColumnModel.getTotalColumnWidth()
  • 晚会有点晚,但 columnWidthPercentage 加起来应该是 1.0,否则你的桌子会增长得非常快
【解决方案2】:

我需要为 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();
            }
        });
    }
}

【讨论】:

  • +1:column.setPreferredWidth() 在调整大小模式为AUTO_RESIZE_ALL_COLUMNS 时不起作用,因此必须使用setMin/MaxWidth()
【解决方案3】:

我认为您需要改用table.getPreferredSize()。试试这个代码 sn-p:

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);
        }
    });

【讨论】:

  • 谢谢,但是如果 JFrame 的大小被显式设置为大于 JTable...
  • 我明白你的意思。使用setMinWidthsetMaxWidth 方法怎么样?例如,对于您的第一列,您可以调用setMinWidth(100)setMaxWidth(100)。无论框架的大小,甚至框架的大小调整,它的宽度都将始终为 100。
【解决方案4】:

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

基本上,我得到了 JTable 的 JSrollPane 所在的 JPanel 的首选大小,并且效果很好。请看下文

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));

希望这对某人有所帮助

谢谢

【讨论】:

    【解决方案5】:

    它认为如果我们将它封装在一个自己的类中,使用(和重用)相对组件大小调整会更容易。由于我也遇到了同样的问题,所以我想在这里发布我的代码。

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

    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);
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2013-03-12
      • 2012-05-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-22
      • 2013-03-12
      • 2010-10-31
      相关资源
      最近更新 更多