Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java: GUI и Java FX приложения > Калькулятор выражения в JFormattedTextField


Автор: Connie 15.11.2008, 15:26
Необходимо позволять пользователю вводить выражение, примерно так:
125+63-89,6

Потом вычислять результат.

Я реализовал это в InputVerifier'е
Код

public boolean verify(JComponent input) {
             if (input instanceof JFormattedTextField) {
             JFormattedTextField ftf = (JFormattedTextField)input;
             JFormattedTextField.AbstractFormatter formatter = ftf.getFormatter();
             if (formatter != null) {
                 String text = ftf.getText();
                 //Если calc - true то нужно делать вычисление
                 //Если false то это обычное поле и мы просто проверяем число,
                 //что бы оно не было отрицательным
                 if (calc) { text = Calc(text,formatter); 
                    try{
                    ftf.setValue(((Number)formatter.stringToValue(text)).floatValue());
                    }catch (ParseException pe) {}
                      //ftf.setText(text);
                 }
                 try {
                      float vl = ((Number)formatter.stringToValue(text)).floatValue();
                      if (vl<0.0f) ftf.setText(formatter.valueToString(0.0f));
                      return true;
                  } catch (ParseException pe) {
                      return false;
                  }
              }
          }
          return true;
  }

Функцию Calc приводить не буду, она работает.

Выглядит это так
http://ipicture.ru/Gallery/Viewfull/9145514.html
После того как нажимаем TAB или нажимаем мышкой на Ok все работает, в JFormattedTextField подставляется вычисленное значение, но это и правильно, т.к. фокус покидает это поле, либо переходит к другому полю ввода, либо на какую либо кнопку.

Однако я хотел бы использовать эту возможность и в таблице.

Для ввода числа я написал FloatEditor для float чисел в таблице
Код

public class FloatEditor extends AbstractCellEditor
implements TableCellEditor, PropertyChangeListener {
    
    private JFormattedTextField fld;
    private static final String VALUE_CHANGED = "value";
    
    public FloatEditor(ProgramSettings settings){ 
        super();
        
        fld = new JFormattedTextField(new DecimalFormat("0.0"));
        fld.setFont(settings.getFont(fld.getFont()));//тут меняем размер шрифта
        
        fld.setHorizontalAlignment(JFormattedTextField.RIGHT);
        fld.setFocusLostBehavior(JFormattedTextField.PERSIST);
        fld.setBorder(BorderFactory.createEmptyBorder());
        
        fld.setInputVerifier(new PositiveFloatVerifier(true));//вот тут устанавливаем проверку ввода
        //fld.addFocusListener(new MyFocusListener());
        fld.addMouseListener(new MyMouseAdapter());//выделение всей ясейки при попадании в нее фокуса
           
        fld.addPropertyChangeListener(VALUE_CHANGED, this);
    }
    
    public Object getCellEditorValue(){
        //fld.setText(fld.getText());  
        //System.out.println("this1 "+fld.getValue());
        return fld.getValue();
    }   
   
    public Component getTableCellEditorComponent(JTable table,
                                      Object value,
                                      boolean isSelected,
                                      int row,
                                      int column){
        System.out.println("this "+value);
        fld.setValue(((Number)value).doubleValue());
        fld.selectAll();
        
        return fld;
    }
    
    public void propertyChange(PropertyChangeEvent e) {
        //Установили новое значение, т.е. нажали Enter        
       if (e.getPropertyName().equals(VALUE_CHANGED)){
             //JFormattedTextField ftf = (JFormattedTextField)e.getSource();
             
             //ftf.setValue(ftf.getValue());
            // if (ftf.getInputVerifier().verify(ftf)) {//doSomeThing();
                fireEditingStopped();
             //}
       }
    } 

Так вот проблема в следующем, в таблице написать можно
http://ipicture.ru/
И если мышкой перевести фокус в другое место программы, то значение будет вычислено, и оно будет записано в таблицу
Код

@Override
  public void setValueAt(Object value, int row, int col){
      if (col==1){
        System.out.println(""+value);
        ProductInMenu prod = (ProductInMenu)products.get(row);
        prod.setWeight(((Number)value).floatValue());
        mgr.updateProd(prod);
      
        fireTableRowsUpdated(row,row);
      }
  }

Это код модели таблицы

А вот если нажать Enter находясь в таблице, то в ячейку будет записано только первая часть выражения, т.е. написав там 85+63 и нажав Enter в таблицу будет записано только 85.

Вот как то так.

Может как то передавать фокус после нажатия enter, а потом его возвращать назад?


Похожее поведени, точнее оно и связано с этим у InputVerifier'а 
Если находясь в JFormattedTextField нажимать enter, то корректировки значения не происходит, хотя обратобка начинается, т.е. событие propertyChanged возбуждается, а вот если покинуть это поле, т.е. оно потеряет фокус, то и propertyChanged  произойдет и InputVerifier сработает.

Автор: Connie 15.11.2008, 18:33
Спросишь и мозги проясняются smile

сделал так, вычисления из строки выделил в отдельный класс Calculator

В FloatEditor изменил работу функции
Код

public void propertyChange(PropertyChangeEvent e) {
        //Установили новое значение, т.е. нажали Enter        
       if (e.getPropertyName().equals(VALUE_CHANGED)){
             JFormattedTextField ftf = (JFormattedTextField)e.getSource();
             ftf.setText(calculator.Calc(ftf.getText(), ftf.getFormatter()));
             try{
                    ftf.setValue(((Number)ftf.getFormatter()
                            .stringToValue(ftf.getText())).floatValue());
             }catch (ParseException pe) {}
             System.out.println("Text data "+ftf.getText());
             System.out.println("Number data "+ftf.getValue());
             
             
             //ftf.setValue(ftf.getValue());
            // if (ftf.getInputVerifier().verify(ftf)) {//doSomeThing();
                fireEditingStopped();
             //}
       }
    } 

Автор: Connie 16.11.2008, 10:39
Приведу и класс Calculator, может кому сгодиться
Код

import javax.swing.JFormattedTextField;
import java.text.ParseException;
import java.text.DecimalFormatSymbols;

public class Calculator {
    private DecimalFormatSymbols symbols;
    
    public Calculator(){
        symbols = new DecimalFormatSymbols();
    }
public String Calc(String textIn, 
              JFormattedTextField.AbstractFormatter formatter){
          String res = textIn;
          textIn = textIn.trim();
          if (textIn.length()>1){
            if (checkCorrect(textIn)){
                textIn = checkOneComma(textIn,symbols.getDecimalSeparator());
                textIn = checkOneComma(textIn,'+');
                textIn = checkOneComma(textIn,'-');
                float sum = 0;
                String buf = "0";
                float sign = 1;
                int i = 0;
                float vl = 0;
                while (i<textIn.length())
                {
                    if ((textIn.charAt(i)!='+')&&(textIn.charAt(i)!='-'))
                        buf = buf + textIn.charAt(i);
                    else
                    {
                        vl = 0;
                        try {
                            vl = ((Number)formatter.stringToValue(buf)).floatValue();
                        } catch (ParseException pe) {}
                        
                        sum = sum + sign *  vl;
                        buf = "0";
                        switch (textIn.charAt(i))
                        {   
                            case '+': sign = 1; break;
                            case '-': sign = -1;
                        }
                    }
                    i++;
                }
                if (buf.length()>1)
                {
                    vl = 0;
                    try {
                        vl = ((Number)formatter.stringToValue(buf)).floatValue();
                    } catch (ParseException pe) {}
                    sum = sum + sign * vl;
                }
                System.out.println("Sum:"+sum);
                try{
                    return formatter.valueToString(sum);
                } catch (ParseException pe) {}
                
            }
          }
          return res;//если не получается обработка, то возвращаем то, что взяли
  }
      
  public String checkOneComma(String InStr, char ch)
  {
        if (InStr.length()==0) return "0";
        boolean conj = false;
        int i=0;
        StringBuilder stBl = new StringBuilder(InStr);
        while (i<stBl.length() )
        { 
                if (stBl.charAt(i)==ch){
                  if (conj) 
                  { stBl = stBl.deleteCharAt(i); i--; }
                  else conj = true;
                } else { conj=false;}
                i++;
        }
        if ((stBl.length()==1)&&(conj)) stBl = new StringBuilder("0");
        return stBl.toString();
  }
    
  public boolean checkCorrect(String StrToCheck )
  {
        int i=0;
                
        StringBuilder stBl = new StringBuilder(StrToCheck);
        while (i<stBl.length() && stBl.length()>0)
        {
            char ch = stBl.charAt(i);    
            if ( ( ch>='0' && ch<='9')||
                (ch==symbols.getDecimalSeparator())||
                (ch=='+')||(ch=='-'))  i++;
                else stBl = stBl.deleteCharAt(i);
        }

        //String t = stBl.toString();
        
        if (stBl.length()==0)  return false;
        else return true;
  }
}

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)