Java 按百分比设置JTable的列宽

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19012691/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 13:21:26  来源:igfitidea点击:

Set Column Width of JTable by Percentage

javaswingpercentagejtableheaderpreferredsize

提问by Tom Tucker

I need to assign a fixed width to a few columns of a JTableand then an equal width to all the other columns.

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

Suppose a JTablehas 5 columns. The first column should have a width of 100 and the second one a width of 150. If the remaining width of the JTableis 600 after setting the width of the two columns, I'd like to evenly split it among the other three columns.

假设 aJTable有 5 列。第一列的宽度应该是100,第二列的宽度应该是150。如果JTable设置了两列的宽度后剩下的宽度是600,我想将它平均分配给其他三列。

The problem is table.getParent().getSize().widthis often 0, even if it is added to the JFrameand visible, so I can't use it as a basis.

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

How do I go about doing this?

我该怎么做?

回答by dic19

I think you need to use table.getPreferredSize()instead. Try this code snippet:

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

    }
}

As you'll see, Namecolumn will have a width of 100, Categorywill have a width of 150, Colorcolumn will fit at 70% of remanent width and Rankingwill fit at last 30%.

如您所见,Name列的宽度为 100,Category宽度为 150,Color列将适合剩余宽度的 70% 并Ranking适合最后 30%。

Update

更新

Based on this comment:

基于此评论:

Thanks, but this will not work if the JFrame's size is set explicitly larger than the JTable...

谢谢,但是如果 JFrame 的大小设置为显式大于 JTable,这将不起作用...

Solution could be play with setMinWidthand setMaxWidthmethods to fix static columns width, or you can implement your own TableColumnModelListener. In the example above replace setPreferredWithlines as follows and try set frame's preferred size as you wish:

解决方案可以使用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);
        }
    });

回答by camickr

I need to assign a fixed width to a few columns of a JTable and then an equal width to all the other columns.

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

Let the table's resize mode do the work for you. Set the resize mode to all columns and set the min/max values of the fixed columns:

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

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

回答by bluchip.gr

I had to dynamically set my table columns width for a project that had to display correctly on different screen resolution DPI settings. The idea for my solution came from dic19s answer.

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

Basically I got the preferred size of the JPanel where the JSrollPane of the JTable was placed and work great. Please see below

基本上我得到了 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));

Hope this helps somebody

希望这可以帮助某人

Thanks

谢谢

回答by Carlos Parraga

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

回答by René Link

It think it would be easier to use (and re-use) relative component resizing if we encapsulate it in an own class. Since I also was confronted with the same issue, I would like to post my code here.

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

From a client perspective I would like to do something like this

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

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

So I first defined the ComponentResizeinterface and implement a TableColumnResize

所以我首先定义了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);
    }
}

The ComponentResizeinterface decouples the way a component's size is set from the concrete APIs. E.g. a TableColumn's width can be set via setPreferredWidth(int)while a JComponent's size can be set by setPreferredWidth(Dimension)

ComponentResize接口将组件大小的设置方式与具体的 API 分离。例如 aTableColumn的宽度可以通过设置setPreferredWidth(int)而 aJComponent的大小可以通过setPreferredWidth(Dimension)

Than I implemented the RelativeWidthResizerthat encapsulates the relative width calculation logic.

比我实现的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);
        }
    }
}