【问题标题】:Display alternate toString() Method with custom cell editor使用自定义单元格编辑器显示备用 toString() 方法
【发布时间】:2016-03-27 21:17:38
【问题描述】:

我正在创建基本上是我复制的 excel。用户将数据输入到 JTable 中,然后对该数据进行解析、处理,并显示相应类型 Cell 的 toString() 方法,这是我为其创建了多个子类的接口。

当用户开始编辑 FormulaCell 时,我希望单元格显示通过 getFormula() 方法检索到的公式,而不是通过 toString() 方法检索到的计算公式。

我探索了自定义单元格编辑器,但我不知道要覆盖哪个方法。我认为代码在自定义单元格编辑器或我需要创建的任何内容中都是这样的:

if (cell instanceof FormulaCell) {
  startingText = (FormulaCell) cell).getFormula();
}

JTable 中的每个单元格都有不同的类,所以我不能真正重写 DefaultTableModel 的 getColumnClass() 方法并为公式单元格类设置自定义单元格编辑器。

作为参考,这是我程序的主要部分:

import java.awt.*;
import java.awt.event.*;

import javax.swing.*;
import javax.swing.table.*;

import cell.*;

public class Program extends JPanel {

    private DefaultTableModel model;
    private JTable table;

    public static final int ASCII_SHIFT = 64, HEIGHT = 10, WIDTH = 7, ROW_HEIGHT = 40;
    public static final Dimension BUTTON_SIZE = new Dimension(70,30),
            TABLE_SIZE = new Dimension(780, 400);

    //makes program runnable
    public static void main(String[] args) {
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });
    }

    public static void createAndShowGUI() {

        //sets title and does everything necessary to
        //create and show the GUI
        JFrame frame = new JFrame("TextExcel");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        Program contentPane = new Program();
        contentPane.setOpaque(true);
        frame.setContentPane(contentPane);
        frame.setResizable(false);
        frame.pack();
        frame.setVisible(true);
    }

    public Program() {

        //sets the layout
        super(new BorderLayout());

        //creates a String[] for column headers
        String[] letter = new String[WIDTH];
        for (int i = 0; i < letter.length; i++) {
            byte[] character = {(byte) (i + ASCII_SHIFT + 1)};
            letter[i] = new String(character);
        }

        //creates the table
        model = new DefaultTableModel(letter, HEIGHT);
        table = new JTable(model);

        //makes a cell parse the input when enter is pressed
        Action action = new AbstractAction()
        {
            public void actionPerformed(ActionEvent e)
            {
                TableCellListener tcl = (TableCellListener)e.getSource();
                int row = tcl.getRow();
                int column = tcl.getColumn();
                String input = (String) model.getValueAt(row, column);
                parse(input, row, column);
            }
        };
        @SuppressWarnings("unused")
        TableCellListener tcl = new TableCellListener(table, action);

        //centers the headers
        JTableHeader header = table.getTableHeader();
        header.setDefaultRenderer(new HeaderRenderer(table));
        header.setReorderingAllowed(false);

        //centers text in cells
        DefaultTableCellRenderer centerRenderer = new DefaultTableCellRenderer();
        centerRenderer.setHorizontalAlignment(SwingConstants.CENTER);
        table.setDefaultRenderer(Object.class, centerRenderer);

        //sets the height of rows
        for (int i = 0; i < HEIGHT; i++) {
            table.setRowHeight(i, ROW_HEIGHT);
        }

        //creates a scroll-pane for the table and numbers the rows
        JScrollPane scrollPane = new JScrollPane(table);
        JTable rowTable = new RowNumberTable(table);
        scrollPane.setRowHeaderView(rowTable);
        scrollPane.setCorner(JScrollPane.UPPER_LEFT_CORNER, rowTable.getTableHeader());
        add(scrollPane);

        //sizes the table
        table.setFillsViewportHeight(true);
        table.setPreferredScrollableViewportSize(TABLE_SIZE);

        //creates a panel to place buttons
        JPanel buttonPanel = new JPanel(new FlowLayout());

        //creates a button to clear the table
        JButton clearButton = new JButton("clear");
        clearButton.setPreferredSize(BUTTON_SIZE);
        clearButton.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e) 
            {
                clearTable();
            }
        });
        buttonPanel.add(clearButton);

        //message displayed when help button is pressed
        String helpMessage = "To construct a Cell, double click a cell, "
                + "enter the argument, and press enter.\n"
                + "To clear a Cell, press the \"clear\" button.\n\n"
                + "There are 5 subclasses of Cell:\n"
                + "StringCell, DateCell, NumberCell, "
                + "FormulaCell, and SumAvgCell.\n"
                + "All numbers are displayed as Fractions and all Cells displaying numbers extend\n"
                + "NumberCell. Any double entered will be converted to a Fraction.\n\n"
                + "* StringCells display text and are simply typed into the cell. If an input is\n"
                + "invalid for all other types of Cell, it will become a StringCell.\n"
                + "* DateCells display dates in the form (Month Day, Year). They are constructed\n"
                + "in the form (m/d/yy) or (m/d/yyyy). Extra zeroes in m and d are not necessary.\n"
                + "* NumberCells simply display Fractions and can be constructed from a double,\n"
                + "int, standard fraction, or mixed fraction.\n"
                + "* FormulaCells are constructed from any combination of operations(+-*/%),\n"
                + "values, parantheses, and references. Order of operations is supported. An\n"
                + "example of a valid input would be \"(A1 + 4.4 * b3) % C2 - 3_6/8\".\n"
                + "* SumAvgCells can be used to find the sum or average of a rectangular area of\n"
                + "cells. They are constructed in the form (command reference - reference).\n"
                + "The first reference is the top-left corner and the second reference is the\n"
                + "bottom-right corner. An example of a valid input would be \"sum A1 - B2\".\n"
                + "Another valid input would be \"avg C1 - C8\".";

        //creates a help button to display a helpful message
        JButton helpButton = new JButton("help");
        helpButton.setPreferredSize(BUTTON_SIZE);
        helpButton.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e) 
            {
                JOptionPane.showMessageDialog(getComponent(0), helpMessage, "HelpBox", 1);
            }
        });
        buttonPanel.add(helpButton);

        //creates a panel to place the table
        JPanel tablePanel = new JPanel(new BorderLayout());
        tablePanel.add(scrollPane, BorderLayout.CENTER);

        //adds the button and table panels
        add(tablePanel, BorderLayout.NORTH);
        add(buttonPanel, BorderLayout.SOUTH);
    }

    //parses user input to set a cell value
    public void parse(String input, int row, int column) {

        //initializes cell to be set
        Cell cell = null;

        //helpful variables
        String ref = "([a-g]\\d*)";
        String dub = "([-+]?\\d*\\.?\\d*)";
        String frac = "((\\d+_\\d+/\\d+)|(\\d+/\\d+))";

        //parses the input according to regular expressions
        input = input.toLowerCase();
        if (input.matches("(" + ref + "|" + dub + "|" + frac + ")"
                + "( [-+*/%] (" + ref + "|" + dub + "|" + frac + "))+")) {
            cell = new FormulaCell(input, model);
        }
        else if (input.matches("((sum)|(avg)) " + ref + " - " + ref)) {
            cell = new SumAvgCell(input, model);
        }
        else if (input.matches(dub + "|" + frac)) {
            cell = new NumberCell(input);
        }
        else if (input.matches("(\\d{1}|\\d{2})/(\\d{1}|\\d{2})/(\\d{2}|\\d{4})")) {
            cell = new DateCell(input);
        }
        else {
            cell = new StringCell(input);
        }

        //sets the cell value
        model.setValueAt(cell, row, column);
    }

    //sets all cell values to null
    public void clearTable() {
        for (int i = 0; i < HEIGHT; i++) {
            for(int j = 0; j < WIDTH; j++) {
                model.setValueAt(null, i, j);
            }
        }
    }
}

任何有关如何创建所需行为的指导都将受到高度赞赏。

【问题讨论】:

    标签: java swing jtable tablemodel tablecelleditor


    【解决方案1】:

    Cell 接口中定义一个方法,例如getDetailedText(),该方法返回将在单元格编辑器中使用的文本。然后在FormulaCell 中从此方法返回公式。对于其他单元格,您可以返回toString()

    单元界面:

    public interface Cell {
    
         public String getDetailedText();
    }
    

    公式单元格:

    public class FormulaCell implements Cell {
    
        public String getDetailedText() {
             return formula;
        }
    }
    

    其他单元格(如果您想为每个单元格显示另一个文本,请返回此处):

    public class OtherCell implements Cell {
    
        public String getDetailedText() {
             return toString();
        }
    }
    

    然后创建一个单元格编辑器并将其设置为表格的默认编辑器。

    默认单元格编辑器:

    public class MyDefaultCellEditor extends DefaultCellEditor {
        public MyDefaultCellEditor() {
            super(new JTextField());
        }
    
        @Override
        public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row,
                int column) {
            JTextField textField = (JTextField) super.getTableCellEditorComponent(table, value, isSelected, row, column);
            Cell cell = (Cell) value;
    
            textField.setText(cell.getEditorText());
            return textField;
        }
    } 
    

    设置到桌子上:

    table.setDefaultEditor(Object.class, new MyDefaultCellEditor());
    

    【讨论】:

    • 当我运行它时,getTableCellEditorComponent(...) 方法无休止地调用自己,导致 StackOverflowError。这可能有帮助,也可能没有帮助,但我正在使用一个名为 TableCellListener 的自定义单元侦听器,我在 Java Tips Weblog 上找到了它。
    • 我只是忘记添加super.。现在更新了那部分。
    • 太棒了;解决了它!唯一的其他复杂情况是对 super 的调用需要转换为 JTextField。
    猜你喜欢
    • 2021-02-12
    • 2020-12-09
    • 1970-01-01
    • 1970-01-01
    • 2012-08-05
    • 2011-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多