2016-03-27 20 views
1

Ich erstelle, was ich im Grunde Kopie von Excel bin. Der Benutzer gibt Daten in eine JTable ein, dann werden diese Daten analysiert, verarbeitet und es wird die toString() - Methode für den entsprechenden Zellentyp angezeigt, bei dem es sich um eine Schnittstelle handelt, für die ich mehrere Unterklassen erstellt habe.Anzeige alternative toString() -Methode mit benutzerdefinierten Zelle Editor

Wenn ein Benutzer beginnt, ein FormulaCell zu bearbeiten, möchte ich, dass die Zelle die Formel anzeigt, die von einer getFormula() - Methode abgerufen wird, und nicht die ausgewertete Formel, die von der toString() -Methode abgerufen wird.

Ich erkunde benutzerdefinierte Zelleditoren, aber ich konnte nicht herausfinden, welche Methode zu überschreiben. Ich denke, dass der Code so etwas wie dieses innerhalb eines benutzerdefinierten Zellen-Editor sein würde oder was ich schaffen müssen:

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

Jede Zelle in der JTable eine andere Klasse hat, so kann ich nicht wirklich überschreiben DefaultTableModel des getColumnClass() Methode und legen Sie einen benutzerdefinierten Zelleneditor für die Formula Cell-Klasse fest.

als Referenz, hier ist der Hauptteil meines Programms:

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

Alle Hinweise, wie das gewünschte Verhalten erzeugen würden sehr geschätzt werden.

Antwort

4

Definieren Sie eine Methode, z. B. getDetailedText(), in Cell Schnittstelle, die den Text zurückgibt, der im Zelleneditor verwendet wird. Dann geben Sie die Formel von dieser Methode in FormulaCell zurück. Für andere Zellen können Sie toString() zurückgeben.

Handy-Schnittstelle:

public interface Cell { 

    public String getDetailedText(); 
} 

FormulaCell:

public class FormulaCell implements Cell { 

    public String getDetailedText() { 
     return formula; 
    } 
} 

Andere Zellen (wenn Sie einen anderen Text für jede Zelle nur zurückgeben hier angezeigt werden soll):

public class OtherCell implements Cell { 

    public String getDetailedText() { 
     return toString(); 
    } 
} 

Dann erstellen einen Zelleneditor und legen Sie ihn als Standardeditor für die Tabelle fest.

Standardzelleneditor:

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

Set zur Tabelle:

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

Als ich es lief, die getTableCellEditorComponent (...) Methode selbst endlos genannt, in einem Stackoverflow führt. Dies kann hilfreich sein oder nicht, aber ich verwende einen benutzerdefinierten Cell Listener namens TableCellListener, den ich im Java Tips Weblog gefunden habe. – traviata

+0

Ich habe gerade den Zusatz "Super" vergessen. Jetzt aktualisiert diesen Teil. – rdonuk

+1

Großartig; das hat es behoben! Die einzige andere Komplikation war, dass der Aufruf von super in ein JTextField umgewandelt werden musste. – traviata