使用自定义单元格编辑器显示备用toString()方法

时间:2016-03-27 21:17:39

标签: java swing jtable tablemodel tablecelleditor

我正在创建基本上我的excel副本。用户将数据输入JTable,然后解析,处理该数据,并显示适当类型的Cell的toString()方法,这是我为其创建了几个子类的接口。

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

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

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

JTable中的每个单元都有不同的类,因此我无法覆盖DefaultTableModel的getColumnClass()方法,并为Formula Cell类设置自定义单元格编辑器。

供参考,这是我的计划的主要部分:

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

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

1 个答案:

答案 0 :(得分:4)

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

Cell界面:

public interface Cell {

     public String getDetailedText();
}

FormulaCell:

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