包装线,右对齐,自动调整JTable中的行高

时间:2018-08-12 07:01:31

标签: java swing jtable tablecellrenderer

我编写了一个Java应用程序,我需要一个JTable类的对象,它具有一些功能:

  1. 自动换行
  2. 右对齐
  3. 自动调整行高的大小(例如,一行的大小为25,而表中另一行的大小为50,其中一行的内容为大小)
  4. 渲染速度必须

但是我的代码无法快速运行并且没有完整的主要功能,我在最后一个问题中编写了应用程序的最低版本:

这是我的gui类:

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

public class GUI extends JFrame {
    private BankTable table;
    private JScrollPane scrollPane;

    public GUI(){
        super("Bank Table");
        JPanel contentPanel = new JPanel();
        setContentPane(contentPanel);
        contentPanel.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
        setLayout(new BorderLayout());
        setMinimumSize(new Dimension(1000,700));
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        makeTable();

        scrollPane = new JScrollPane(table);
        scrollPane.getVerticalScrollBar().setUnitIncrement(50);

        add(scrollPane,BorderLayout.CENTER);

        setVisible(true);
    }

    public void makeTable(){
        String[][]data= new String[][]{{"0212670003009", "ص 318", "77081634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/01"},
                {"0212670003009", "ص 318", "77081634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/02"},
                {"0212670003009", "ص 318", "77081634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/03"},
                {"0212670003009", "ص 318", "77081634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/04"},
                {"0212670003009", "ص 318", "77081634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/05"},
                {"0212670003009", "ص 318", "77081634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/06"},
                {"0212670003009", "ص 318", "77081634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/07"},
                {"0212670003009", "ص 318", "77081634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/08"},
                {"0212670003009", "ص 318", "77081634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/09"},
                {"0212670003009", "ص 318", "77081634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/10"},
                {"0212670003009", "ص 318", "77081634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/11"},
                {"0212670003009", "ص 318", "77081634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/12"},
                {"0212670003009", "ص 318", "77081634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/13"},
                {"0212670003009", "ص 318", "77081634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/14"},
                {"0212670003009", "ص 318", "77081634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/15"},
                {"0212670003009", "ص 318", "77081634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/16"},
                {"0212670003009", "ص 318", "77081634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/17"},
                {"0212670003009", "ص 318", "77081111111111111111111111111111111111634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/18"},
                {"0212670003009", "ص 318", "77081222222222222222222222222222634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/19"},
                {"0212670003009", "ص 318", "77081634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/20"},
                {"0212670003009", "ص 318", "77081634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/21"},
                {"0212670003009", "ص 318", "77081634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/22"},
                {"0212670003009", "ص 318", "77081634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/23"},
                {"0212670003009", "ص 318", "77081634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/24"},
                {"0212670003009", "ص 318", "77081634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/25"},
                {"0212670003009", "ص 318", "77081634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/26"},
                {"0212670003009", "ص 318", "77081634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/27"},
                {"0212670003009", "ص 318", "77081634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/28"},
                {"0212670003009", "ص 318", "77081634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/29"},
                {"0212670003009", "ص 318", "77081634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/30"}};

        String[] columns= new String[]{"شماره حساب", "اطلاعات اضافه", "مانده","واریز","برداشت","فیش/ حواله","کد شعبه","شرح","ساعت","تاریخ"};

        table = new BankTable(data,columns);
        table.updateRowHeights();
        System.out.println("Table");
    }

    public static void main(String args[]){
        GUI gui = new GUI();
    }

}

这是表格的呈现:

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

public class TextAreaRenderer extends JTextArea
        implements TableCellRenderer {

    public TextAreaRenderer() {
        setLineWrap(true);
        setWrapStyleWord(true);
        setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);    

        setEditable(false);
        setCursor(null);
        setOpaque(false);
        setFocusable(false);
        setLineWrap(true);
        setWrapStyleWord(true);

    }

    public Component getTableCellRendererComponent(JTable jTable,
                                                   Object obj, boolean isSelected, boolean hasFocus, int row,
                                                   int column) {
        setText((String)obj);
        setFont(new Font("bnazanin", Font.BOLD, 15));

        return this;
    }    
}

这是表类:

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

public class BankTable extends JTable {

    public BankTable(String[][] data,String[] columns){
        super(data,columns);

        setForeground(Color.BLACK);
        setBounds(60,80,400,600);

        changeTableHeader();

        DefaultTableCellRenderer rightRenderer = new DefaultTableCellRenderer();
        rightRenderer.setHorizontalAlignment(JLabel.RIGHT);

        TextAreaRenderer textAreaRenderer = new TextAreaRenderer();

        for(int i=0 ; i<columns.length ; i++){
            getColumnModel().getColumn(i).setCellRenderer(textAreaRenderer);
        }    
    }

    public void changeTableHeader(){
        getTableHeader().setBackground(new Color(57,77,112));
        getTableHeader().setForeground(Color.WHITE);
        getTableHeader().setFont(new Font("Calibri Light", Font.BOLD, 20));

    }

    @Override
    public boolean isCellEditable(int i, int i1) {
        return false;
    }

    public void updateRowHeights()
    {
        for (int row = 0; row < getRowCount(); row++)
        {
            int rowHeight = getRowHeight();

            for (int column = 0; column < getColumnCount(); column++)
            {
                Component comp = prepareRenderer(getCellRenderer(row, column), row, column);
                rowHeight = Math.max(rowHeight, comp.getPreferredSize().height);
            }
            setRowHeight(row, rowHeight + 20);
        }
    }    
}

编辑:   This is a simple for my table

2 个答案:

答案 0 :(得分:1)

在这里值得花的是我躺在的一些旧代码。

它使用带换行的JTextArea,但将文本区域中的行限制为2行。然后,您可以滚动文本区域以查看其他行。

也许这种方法可以帮助您满足要求?

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

public class TableTextArea extends JFrame
{
    public TableTextArea()
    {
        JTable table = new JTable(40, 5);
        table.setPreferredScrollableViewportSize(table.getPreferredSize());
        table.setRowHeight(40);
        table.setValueAt("one two three four five six seven eight nine ten", 0, 2);
        table.setValueAt("aaa bbb ccccc dddd eeee fff ggggg hhhhh iiii jjj", 1, 2);
        table.setValueAt("1111 2222 3333 4444 5555 6666 7777 8888 9999 0000", 0, 4);
        table.setValueAt("one two three four five six seven eight nine ten", 2, 2);
        table.setValueAt("aaa bbb ccccc dddd eeee fff ggggg hhhhh iiii jjj", 3, 2);
        table.setValueAt("1111 2222 3333 4444 5555 6666 7777 8888 9999 0000", 4, 4);
        table.setValueAt("one two three four five six seven eight nine ten", 5, 2);
        table.setValueAt("aaa bbb ccccc dddd eeee fff ggggg hhhhh iiii jjj", 6, 2);
        table.setValueAt("1111 2222 3333 4444 5555 6666 7777 8888 9999 0000", 7, 4);
        table.setValueAt("one two three four five six seven eight nine ten", 8, 2);
        table.setValueAt("aaa bbb ccccc dddd eeee fff ggggg hhhhh iiii jjj", 9, 2);
        table.setValueAt("1111 2222 3333 4444 5555 6666 7777 8888 9999 0000", 10, 4);
        table.setValueAt("one two three four five six seven eight nine ten", 11, 2);
        table.setValueAt("aaa bbb ccccc dddd eeee fff ggggg hhhhh iiii jjj", 12, 2);
        table.setValueAt("1111 2222 3333 4444 5555 6666 7777 8888 9999 0000", 13, 4);
        table.setValueAt("one two three four five six seven eight nine ten", 14, 2);
        table.setValueAt("aaa bbb ccccc dddd eeee fff ggggg hhhhh iiii jjj", 15, 2);
        table.setValueAt("1111 2222 3333 4444 5555 6666 7777 8888 9999 0000", 16, 4);
        table.setValueAt("one two three four five six seven eight nine ten", 17, 2);
        table.setValueAt("aaa bbb ccccc dddd eeee fff ggggg hhhhh iiii jjj", 18, 2);
        table.setValueAt("1111 2222 3333 4444 5555 6666 7777 8888 9999 0000", 19, 4);
        table.setValueAt("one two three four five six seven eight nine ten", 20, 2);
        table.setValueAt("aaa bbb ccccc dddd eeee fff ggggg hhhhh iiii jjj", 21, 2);
        table.setValueAt("1111 2222 3333 4444 5555 6666 7777 8888 9999 0000", 22, 4);
        table.setValueAt("one two three four five six seven eight nine ten", 23, 2);
        table.setValueAt("aaa bbb ccccc dddd eeee fff ggggg hhhhh iiii jjj", 24, 2);
        table.setValueAt("1111 2222 3333 4444 5555 6666 7777 8888 9999 0000", 25, 4);
        table.setValueAt("one two three four five six seven eight nine ten", 26, 2);
        table.setValueAt("aaa bbb ccccc dddd eeee fff ggggg hhhhh iiii jjj", 27, 2);
        table.setValueAt("1111 2222 3333 4444 5555 6666 7777 8888 9999 0000", 28, 4);
        JScrollPane scrollPane = new JScrollPane( table );
        add( scrollPane );

        //  Override default renderer for a specific column

        TableCellRenderer renderer = new TextAreaRenderer();
        table.getColumnModel().getColumn(2).setCellRenderer( renderer );
        table.getColumnModel().getColumn(4).setCellRenderer( renderer );
        table.changeSelection(0, 0, false, false);
    }

    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                TableTextArea frame = new TableTextArea();
                frame.setDefaultCloseOperation( EXIT_ON_CLOSE );
                frame.pack();
                frame.setLocationRelativeTo( null );
                frame.setVisible(true);
            }
        });
    }

    /*
    **
    */
    class TextAreaRenderer implements TableCellRenderer
    {
        private JTextArea renderTextArea;
        private JScrollPane renderScrollPane;
        private JTextArea focusTextArea;
        private JScrollPane focusScrollPane;
        private boolean firstTime = true;

        public TextAreaRenderer()
        {
            renderTextArea = new JTextArea();
            renderTextArea.setEditable( false );
            renderTextArea.setLineWrap( true );
            renderTextArea.setWrapStyleWord( true );
            renderScrollPane = new JScrollPane( renderTextArea );
            renderScrollPane.setBorder(null);
            renderScrollPane.revalidate();

            focusTextArea = new JTextArea();
            focusTextArea.setEditable( false );
            focusTextArea.setLineWrap( true );
            focusTextArea.setWrapStyleWord( true );
            focusScrollPane = new JScrollPane( focusTextArea );
            focusScrollPane.setBorder(null);
        }

        public Component getTableCellRendererComponent(
            final JTable table, Object value, boolean isSelected, boolean hasFocus, final int row, final int column)
        {
            //  For some reason the scrollbars don't appear on the first cell renderered.
            //  Forcing a repaint of the cell seems to fix the problem.

            if (firstTime)
            {
                firstTime = false;
                Rectangle cellRectangle = table.getCellRect(row, column, false);
//              renderScrollPane.setBounds(cellRectangle);
//              table.add(renderScrollPane);
//              renderScrollPane.revalidate();
                table.repaint(cellRectangle);
            }

            System.out.println(row + " :: " + column + " : " + hasFocus);
            table.remove(focusScrollPane);

            renderTextArea.setText( value != null ? value.toString() : "" );
            renderTextArea.setCaretPosition(0);

            if (hasFocus)
            {
                renderTextArea.setBackground( table.getSelectionBackground() );

                SwingUtilities.invokeLater( new Runnable()
                {
                    public void run()
                    {
                        addRealTextAreaToTable(table, row, column);
                    }
                });
            }
            else if (isSelected)
                renderTextArea.setBackground( table.getSelectionBackground() );
            else
                renderTextArea.setBackground( table.getBackground() );

            return renderScrollPane;
        }

        private void addRealTextAreaToTable(JTable table, int row, int column)
        {
            System.out.println(row + " :: " + column);
            Object value = table.getValueAt(row, column);
            focusTextArea.setText( value != null ? value.toString() : "" );
            focusTextArea.setCaretPosition(0);
//          focusTextArea.setBackground( table.getBackground() );
            focusTextArea.setBackground( table.getSelectionBackground() );
            Rectangle cellRectangle = table.getCellRect(row, column, false);
            focusScrollPane.setBounds(cellRectangle);
            table.add(focusScrollPane);
            focusScrollPane.revalidate();
            focusTextArea.requestFocusInWindow();
        }
    }
}

答案 1 :(得分:0)

因此,我花了一些时间来尝试各种不同的事情。

TextAreaRenderer开始。我更喜欢使用DefaultTableCelllRenderer,但是在使用它之后,我无法使其令人满意地工作。因此,我取而代之的是,将大部分优化措施应用到TextAreaRenderer本身。

您真正想做的一件事就是减少每个getTableCellRendererComponent所做的更改量。 JTextArea已经很复杂了。

我删除了setOpaque调用,并将setFont调用移到了构造函数。我还添加了选择支持(这是我的测试的一部分)

public class TextAreaRenderer extends JTextArea
        implements TableCellRenderer {

    public TextAreaRenderer() {
        setLineWrap(true);
        setWrapStyleWord(true);
        setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);

        setEditable(false);
        setCursor(null);
        //setOpaque(false);
        setFocusable(false);
        setLineWrap(true);
        setWrapStyleWord(true);
        setFont(new Font("bnazanin", Font.BOLD, 15));

        getCaret().setBlinkRate(0);
    }

    public Component getTableCellRendererComponent(JTable jTable,
            Object obj, boolean isSelected, boolean hasFocus, int row,
            int column) {
        setText((String) obj);

        if (isSelected) {
            System.out.println("!!Selected");
            setBackground(jTable.getSelectionBackground());
            setForeground(jTable.getSelectionForeground());
        } else {
            setBackground(jTable.getBackground());
            setForeground(jTable.getForeground());
        }

        return this;
    }

    /**
     * Overridden for performance reasons. See the
     * <a href="#override">Implementation Note</a>
     * for more information.
     */
    public boolean isOpaque() {
        Color back = getBackground();
        Component p = getParent();
        if (p != null) {
            p = p.getParent();
        }

        // p should now be the JTable.
        boolean colorMatch = (back != null) && (p != null)
                && back.equals(p.getBackground())
                && p.isOpaque();
        return !colorMatch && super.isOpaque();
    }

    /**
     * Overridden for performance reasons. See the
     * <a href="#override">Implementation Note</a>
     * for more information.
     *
     * @since 1.5
     */
    public void invalidate() {
    }

    /**
     * Overridden for performance reasons. See the
     * <a href="#override">Implementation Note</a>
     * for more information.
     */
    public void validate() {
    }

    /**
     * Overridden for performance reasons. See the
     * <a href="#override">Implementation Note</a>
     * for more information.
     */
    public void revalidate() {
    }

    /**
     * Overridden for performance reasons. See the
     * <a href="#override">Implementation Note</a>
     * for more information.
     */
    public void repaint(long tm, int x, int y, int width, int height) {
    }

    /**
     * Overridden for performance reasons. See the
     * <a href="#override">Implementation Note</a>
     * for more information.
     */
    public void repaint(Rectangle r) {
    }

    /**
     * Overridden for performance reasons. See the
     * <a href="#override">Implementation Note</a>
     * for more information.
     *
     * @since 1.5
     */
    public void repaint() {
    }

    /**
     * Overridden for performance reasons. See the
     * <a href="#override">Implementation Note</a>
     * for more information.
     */
    public void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) {
    }

}

然后我袭击了BlankTable ...

最大的变化之一是表格现在能够动态计算行的高度。由于计算成本很高,因此将缓存此操作的结果。不过,问题是JTable也有它自己的内部缓存...这是私有的...因此,与其追踪反射路径,我们还需要提供一些补偿来避免这种副作用。 API创建。

调用setRowHeight时,JTable会调用invalidaterepaint本身。在执行计算时,我们想停止此操作,但是在某些情况下,我们仍应允许工作(例如,当调整列的大小并且JTableinvalidated时)

public class BankTable extends JTable {

    public BankTable(String[][] data, String[] columns) {
        super(data, columns);

        changeTableHeader();

        setGridColor(Color.RED);

        TableCellRenderer textAreaRenderer = new TextAreaRenderer();

        for (int i = 0; i < columns.length; i++) {
            getColumnModel().getColumn(i).setCellRenderer(textAreaRenderer);
        }
    }

    public void changeTableHeader() {
        getTableHeader().setBackground(new Color(57, 77, 112));
        getTableHeader().setForeground(Color.WHITE);
        getTableHeader().setFont(new Font("Calibri Light", Font.BOLD, 20));

    }

    @Override
    public boolean isCellEditable(int i, int i1) {
        return false;
    }

    private Map<Integer, Integer> rowMap = new HashMap<>();
    private boolean quietUpdate = false;
    private boolean forceUpdate = false;

    @Override
    public void invalidate() {
        rowMap.clear();
        forceUpdate = true;
        super.invalidate();
        forceUpdate = false;
    }

    @Override
    protected void resizeAndRepaint() {
        if (quietUpdate) {
            if (forceUpdate) {
                super.resizeAndRepaint();
            }
        } else {
            super.resizeAndRepaint();
        }
    }

    @Override
    public int getRowHeight(int row) {
        Integer rowHeight = rowMap.get(row);
        if (rowHeight == null) {
            TableColumnModel model = getColumnModel();
            rowHeight = getRowHeight();
            for (int column = 0; column < getColumnCount(); column++) {
                int colWidth = model.getColumn(column).getWidth();
                Component comp = prepareRenderer(getCellRenderer(row, column), row, column);
                comp.setSize(new Dimension(colWidth, Integer.MAX_VALUE));
                rowHeight = Math.max(rowHeight, comp.getPreferredSize().height);
            }
            rowMap.put(row, rowHeight);
            quietUpdate = true;
            setRowHeight(row, rowHeight);
            quietUpdate = false;
        }
        return rowHeight;
    }

    @Override
    public void tableChanged(TableModelEvent e) {
        if (rowMap == null) {
            super.tableChanged(e);
            return;
        }
        if (e == null || e.getFirstRow() == TableModelEvent.HEADER_ROW) {
            rowMap.clear();
            super.tableChanged(e);
            return;
        }

        if (e.getType() == TableModelEvent.INSERT) {
            super.tableChanged(e);
            return;
        }

        int modelColumn = e.getColumn();
        int start = e.getFirstRow();
        int end = e.getLastRow();

        if (e.getType() == TableModelEvent.DELETE || e.getType() == TableModelEvent.UPDATE) {
            for (int row = start; row <= end; row++) {
                rowMap.remove(row);
            }
            super.tableChanged(e);
            return;
        }

        if (end == Integer.MAX_VALUE) {
            rowMap.clear();
        }
        super.tableChanged(e); //To change body of generated methods, choose Tools | Templates.
    }
}

还有一些其他区域可能需要进一步优化(我尚未测试排序表,因此tableChanged需要更新,并且我也未测试单元格的更改)< / p>

在初始加载之后,我发现渲染是合理的。由于使用的组件,字体和其他系统问题,您的里程可能会很公平。