无效值的JTable警报

时间:2011-08-02 14:34:13

标签: java swing

所以我有一个可编辑的Jtable(实际上是TreeTable)和一个自定义模型。需要更新当前的setValueAt方法以防止大于某个数量的值(取决于行)。

这很容易防止(如果值无效,则不设置值)但是通知用户所选数量无效的最佳方法是什么?从模型中弹出一个对话框似乎很讨厌。

4 个答案:

答案 0 :(得分:3)

  

从模型中弹出一个对话框似乎很讨厌。

同意。使用列的自定义编辑器。也许是这样的:

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

public class TableEdit extends JFrame
{
    TableEdit()
    {
        JTable table = new JTable(5,5);
        table.setPreferredScrollableViewportSize(table.getPreferredSize());

        JScrollPane scrollpane = new JScrollPane(table);
        getContentPane().add(scrollpane);

        //  Use a custom editor

        TableCellEditor fce = new FiveCharacterEditor();
        table.setDefaultEditor(Object.class, fce);
    }

    class FiveCharacterEditor extends DefaultCellEditor
    {
        FiveCharacterEditor()
        {
            super( new JTextField() );
        }

        public boolean stopCellEditing()
        {
        JTable table = (JTable)getComponent().getParent();

            try
            {
                String editingValue = (String)getCellEditorValue();

                if(editingValue.length() != 5)
                {
                    JTextField textField = (JTextField)getComponent();
                    textField.setBorder(new LineBorder(Color.red));
                    textField.selectAll();
                    textField.requestFocusInWindow();

                    JOptionPane.showMessageDialog(
                        null,
                        "Please enter string with 5 letters.",
                        "Alert!",JOptionPane.ERROR_MESSAGE);
                    return false;
                }
            }
            catch(ClassCastException exception)
            {
                return false;
            }

            return super.stopCellEditing();
        }

        public Component getTableCellEditorComponent(
            JTable table, Object value, boolean isSelected, int row, int column)
        {
            Component c = super.getTableCellEditorComponent(
                table, value, isSelected, row, column);
            ((JComponent)c).setBorder(new LineBorder(Color.black));

            return c;
        }

    }

    public static void main(String [] args)
    {
        JFrame frame = new TableEdit();
        frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
        frame.pack();
        frame.setLocationRelativeTo( null );
        frame.setVisible(true);
    }
}

答案 1 :(得分:1)

一旦用户输入无效值,将典型单元格或文本的背景更改为一些引人注目的颜色(深红色或类似的东西)......我认为这将是最简单的。

答案 2 :(得分:0)

另一种解决方案是:

  1. 创建自己的自定义CellEditor,它将扩展DefaultCellEditor。
  2. 获取您希望使用自定义CellEditor
  3. 的JTable的特定列
  4. 将您的自定义CellEditor附加到JTable的特定列
  5. 我将逐步完成以下几点:

    1. 您可以在下面找到我自定义CellEditor的完全可编辑代码。如果输入的值不在特定范围内,编辑器会向屏幕发布警告框。

      import java.awt.Color;
      import javax.swing.AbstractAction;
      import javax.swing.DefaultCellEditor;
      import javax.swing.JFormattedTextField;
      import javax.swing.JOptionPane;
      import javax.swing.JTable;
      import javax.swing.JTextField;
      import javax.swing.KeyStroke;
      import javax.swing.SwingUtilities;
      import java.awt.event.ActionEvent;
      import java.awt.event.KeyEvent;
      import java.awt.Component;
      import java.awt.Toolkit;
      import java.text.NumberFormat;
      import java.text.ParseException;
      import javax.swing.border.LineBorder;
      import javax.swing.text.DefaultFormatterFactory;
      import javax.swing.text.NumberFormatter;
      
      /**
       * 
       * This class ensures that the Mark entered
       * in the Marks column is of the correct format 
       * and within the correct range.<p>
       * 
       * In the event that there is an incorrect format/value entered,
       * an alert box will appear instructing the user same.
       * Implements a cell editor that uses a formatted text field
       * to edit Integer values.<p>
       * 
       * When instantiated, the object essentially is listening for
       * any events with regards to it's associated table i.e.
       * first 100 table etc.
       *  
       * @author      Mark Burleigh
       * @version     %I%, %G%
       * @since       1.0
       */
      public class MarksColumnEditor extends DefaultCellEditor
      {
          JFormattedTextField ftf;
          NumberFormat integerFormat;
          private Integer minimum, maximum;
          private boolean DEBUG = false;
      
          public MarksColumnEditor(int min, int max)
          {
              super(new JFormattedTextField());
              ftf = (JFormattedTextField)getComponent();
              minimum = new Integer(min);
              maximum = new Integer(max);
      
              //Set up the editor for the integer cells.
              integerFormat = NumberFormat.getIntegerInstance();
              NumberFormatter intFormatter = new NumberFormatter(integerFormat);
      
              intFormatter.setFormat(integerFormat);
              /**
              *
              * NumberFormatter inherits setMinimum and setMaximum
              * from class Class InternationalFormatter
              * 
              * setMinimum() - Sets the minimum permissible value.
              * setMaximum() - Sets the maximum permissible value.
              *
              * @see https://docs.oracle.com/javase/7/docs/api/javax/swing/text/InternationalFormatter.html#setMaximum(java.lang.Comparable)
              *
              */
              //
              intFormatter.setMinimum(minimum);
              intFormatter.setMaximum(maximum);
      
              ftf.setFormatterFactory(
                      new DefaultFormatterFactory(intFormatter));
              ftf.setValue(minimum);
              ftf.setHorizontalAlignment(JTextField.TRAILING);
              ftf.setFocusLostBehavior(JFormattedTextField.PERSIST);
      
              //React when the user presses Enter while the editor is
              //active.  (Tab is handled as specified by
              //JFormattedTextField's focusLostBehavior property.)
              ftf.getInputMap().put(KeyStroke.getKeyStroke(
                                              KeyEvent.VK_ENTER, 0),
                                              "check");
              ftf.getActionMap().put("check", new AbstractAction()
              {
                  public void actionPerformed(ActionEvent e) {
              if (!ftf.isEditValid()) { //The text is invalid.
                          if (userSaysRevert()) { //reverted
                      ftf.postActionEvent(); //inform the editor
                  }
                      } else try {              //The text is valid,
                          ftf.commitEdit();     //so use it.
                          ftf.postActionEvent(); //stop editing
                      } catch (java.text.ParseException exc) { }
                  }
              });
          }
      
          /**
          *
          *  This method is implicitly used as soon as 
          *  a MarksColumnEditor object is instantiated 
          *  e.g. inside in the Eas_Main.java 
          *  somJTableColumn.setCellEditor(
          *               new MarksColumnEditor(aMinMark,aMaxMark));
          *  <p>
          * It overrides the same method in the DefaultCellEditor
          * 
          * 
          * @param  table - the JTable that is asking the editor to edit; can be null
          * @param  value - the value of the cell to be edited; it is up to the specific 
          * editor to interpret and draw the value. For example, if value is the string 
          * "true", it could be rendered as a string or it could be rendered as a check 
          * box that is checked. null is a valid value
          * @param isSelected - true if the cell is to be rendered with highlighting
          * @param row - the row of the cell being edited
          * @param column - the column of the cell being edited
          * 
          * @return Component - the component for editing
          * 
          * @see https://docs.oracle.com/javase/7/docs/api/javax/swing/table/TableCellEditor.html
          *
          */
          public Component getTableCellEditorComponent(JTable table,
                  Object value, boolean isSelected,
                  int row, int column)
          {
              JFormattedTextField ftf =
                  (JFormattedTextField)super.getTableCellEditorComponent(
                      table, value, isSelected, row, column);
              ftf.setValue(value);
              ftf.setFont(new java.awt.Font("Tahoma", 1, 15));
              ftf.setBorder(new LineBorder(Color.BLUE));
            //  ftf.setBackground(Color.LIGHT_GRAY);
            //  ftf.setBackground(new Color(204,255,204));
              ftf.setBackground(new Color(219,254,219));
              return ftf;
          }
      
          /**
          *
          * This overrides the method located in DefaultCellEditor.
          * This method is never implicitly called by the developer.
          * The method ensures that the value entered is an integer
          *
          * 
          * @param  
          * @param  
          *
          * @return Object - the integer value entered by the user
          * into the particular cell
          * 
          * @see https://docs.oracle.com/javase/7/docs/api/javax/swing/CellEditor.html#getCellEditorValue()
          *
          */
          public Object getCellEditorValue()
          {
              JFormattedTextField ftf = (JFormattedTextField) getComponent();
      
              Object o = ftf.getValue();
      
              if(o != null)
              {
                  if (o instanceof Integer)
                  {
                      return o;
                  }
                  else if (o instanceof Number)
                  {
                      return new Integer(((Number)o).intValue());
      
                  }
                  else
                  {
                      if (DEBUG)
                      {
                          System.out.println("getCellEditorValue: o isn't a Number");
                      }
                      if(o == null)
                      {
                          System.out.println();
                          System.out.println("Object o = null");
                          System.out.println();
                      }
                      try
                      {
                          return integerFormat.parseObject(o.toString());
                      }
                      catch (ParseException exc)
                      {
                          System.err.println("getCellEditorValue: can't parse o: " + o);
                          return null;
                      }
                  }
      
              }// end if o != null
      
              return null; // if the value in the cell is null and is left unchanged
                          // then the value null is return to the cell 
      
          }
      
          /**
          * Override to check whether the edit is valid,
          * setting the value if it is and complaining if
          * away, we need to invoke the superclass's version
          * of this method so that everything gets cleaned up.
          *  
          *
          * @return {boolean} true - let the editor go away
          * 
          * @see 
          *
          */
          public boolean stopCellEditing() {
              JFormattedTextField ftf = (JFormattedTextField)getComponent();
              if (ftf.isEditValid()) {
                  try {
                      ftf.commitEdit();
                  } catch (java.text.ParseException exc) { }
      
              } else { //text is invalid
                  if (!userSaysRevert()) { //user wants to edit
                  return false; //don't let the editor go away
              }
              }
              return super.stopCellEditing();
          }
      
          /**
           * Lets the user know that the text they entered is
           * bad. Returns true if the user elects to revert to
           * the last good value. Otherwise, returns false,
           * indicating that the user wants to continue editing.
           *
           * @return {boolean} true - referred to the previous Mark
           * 
           */
          protected boolean userSaysRevert()
          {
              Toolkit.getDefaultToolkit().beep();
              ftf.selectAll();
      
              if (maximum !=0)
              {
                  Object[] options = {"Edit",
                                      "Revert"};
                  int answer = JOptionPane.showOptionDialog(
                      SwingUtilities.getWindowAncestor(ftf),
                      "The Mark must be an number between "+ minimum + " and "+ maximum + ".\n"
                      +"You can either continue editing or revert to the\n"
                      +"last valid Mark entered.",
                      "Invalid Mark",
                      JOptionPane.YES_NO_OPTION,
                      JOptionPane.ERROR_MESSAGE,
                      null,
                      options,
                      options[1]);
      
                  if (answer == 1) { //Revert!
                      ftf.setValue(ftf.getValue());
                      return true;
                  }
      
              }
              else
              {
                  JOptionPane.showMessageDialog(SwingUtilities.getWindowAncestor(ftf),
      
                      "You must press the save button first",
      
                      "Alert",
      
                      JOptionPane.ERROR_MESSAGE
      
                  );
      
                  ftf.setValue(null);
                  ftf.repaint();
                  return true; //revert to empty mark
              }
      
          return false;
          }
      }
      
    2. 获取您想要使用自定义CellEditor的JTable的特定列。此代码在您的GUI类中实现,例如

          TableColumn marks_column_A = first_100_Table.getColumnModel().getColumn(2);
      
    3. 将您的自定义CellEditor附加到JTable的特定列。此代码在您的GUI类中实现(setCellRenderer()方法位于Class TableColumn中)例如。

          mark_column_A.setCellRenderer(new MarksColumnEditor(0,300));
      
    4. 产生的结果   您可以在下面找到使用上述代码的JTable的屏幕截图。每当用户输入一个小于0(最小值)或大于300(最大值)的数字时,就会出现一个警告框,勾勒出错误值的用户。

      enter image description here

答案 3 :(得分:0)

camickr建议的自定义单元格编辑器在大多数情况下都可以。但有时您的模型的setValueAt方法可能会出现错误,如果您无法处理,则必须通知您的用户。

对于这种情况,您可以实现自定义事件和事件侦听器。 出错时,您从setValueAt方法触发自定义事件。在JTable或任何其他适当的组件中,您可以向模型添加事件侦听器以侦听这些事件并处理它们,例如通过弹出对话框。

可以找到如何实现自定义事件的基本示例here