Change background colour on typing certain value (jNumberField)

Tags:



I am trying to change the background colour of a number field based on the numbers that are typed in. Just like a number field turns red when you type a letter in it. I want it to also change red when you type numbers below 1 and above 7. I understand that you can do this with a button, but I want it to change when you’re typing.

This is my code:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class applet03 extends JApplet {
  private JButton bHoeveelheid = new JButton();
  private JNumberField nfAantal = new JNumberField();  
  private JTextArea taLijst = new JTextArea("");
    private JScrollPane taLijstScrollPane = new JScrollPane(taLijst);
 public void init() {
    Container cp = getContentPane();
    cp.setLayout(null);
    cp.setBounds(0, 0, 442, 478);
    bHoeveelheid.setBounds(224, 56, 59, 33);
    bHoeveelheid.setMargin(new Insets(2, 2, 2, 2));
    bHoeveelheid.addActionListener(new ActionListener() { 
      public void actionPerformed(ActionEvent evt) { 
        bHoeveelheid_ActionPerformed(evt);
      }
    });
    cp.add(bHoeveelheid);
    nfAantal.setBounds(304, 56, 99, 36);
    nfAantal.setText("Vul getal in");
    nfAantal.setHorizontalAlignment(SwingConstants.CENTER);
    nfAantal.addFocusListener(new FocusAdapter() { 
      public void focusGained(FocusEvent evt) { 
        nfAantal_FocusGained(evt);
      }
    });
    nfAantal.addKeyListener(new KeyAdapter() { 
      public void keyPressed(KeyEvent evt) { 
        nfAantal_KeyPressed(evt);
      }
    });
    cp.add(nfAantal);
    taLijstScrollPane.setBounds(224, 136, 168, 180);
    cp.add(taLijstScrollPane);
  }
  public void bHoeveelheid_ActionPerformed(ActionEvent evt) {    
    if (nfAantal.getInt() < 1 || nfAantal.getInt() > 7) {
      nfAantal.setBackground(Color.RED);
    } else {
      //some other code (not impotant for now)
      }
  }  
  public void nfAantal_FocusGained(FocusEvent evt) {    
    if (nfAantal.getText().equals("Vul getal in")) {
      nfAantal.clear();
    }
  }  
  public void nfAantal_KeyPressed(KeyEvent evt) {
    if (nfAantal.getInt() < 1 || nfAantal.getInt() > 7) {
      nfAantal.setBackground(Color.RED);
    } else {
      //some other code (not impotant for now)
      }
  }  
}

The button part works, but the KeyEvent not. And when I run this I keep getting these errors:

Exception in thread "AWT-EventQueue-1" java.lang.NumberFormatException: empty String

But when I do this, it kinda works. I still get the same errors but it works. (By the way not optimal, because it only appends it to the text field every second key pressing.):

  public void nfAantal_KeyPressed(KeyEvent evt) {
    if (nfAantal.getInt() < 1 || nfAantal.getInt() > 7) {
      taLijst.append(nfAantal.getText());
    } else {
      //some other code (not impotant for now)
      }
  }  

So if someone knows why this doesn’t work or knows a better way to accomplish this. Then that would be very appreciated!

(By the way I use Java 1.8)

Edit:

I now have (nfAantal.getText().length() > 0) && (nfAantal.getInt() < 1 || nfAantal.getInt() > 7) in the if statement and that got rid of the errors. (Thanks to @Joe)
But that still doesn’t solve my question on how to turn the background red on certain values.

Aditional information about JNumberField:

I think this link has the code that makes up JNumberField and this link contains a download to the .jar file with in there the JNumberField Java file.

Another edit:

I think I found out for myself why it doesn’t work with a JNumberfield; in the code it changes the background to white if its value is numeric so only if there is a way to get around this part of the code or change it (which I don’t know how to do) my question can be answered for a JNumberField, if this isn’t the case then I will use the JFormattedTextField instead.

This is the code that needs to be altered or circumvented:

  protected void processKeyEvent(KeyEvent e) {
    super.processKeyEvent(e);
    if (isNumeric() || getText().equals("-") ||
        getText().equals("") || getText().equals("."))
      setBackground(Color.white);
    else
      setBackground(Color.red);
  }

Answer

I don’t know what a JNumberField is. It’s not part of the JDK and when I searched with Google, it turned up several different ones.

I also don’t understand why you are writing an applet.

Therefore, the below code may not be appropriate since it is a stand-alone Swing application that uses JFormattedTextField and DocumentListener.

Explanations after the code.

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.text.NumberFormat;

import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.NumberFormatter;

public class RedNumbr implements DocumentListener, Runnable {
    private JFormattedTextField  aantal;
    private JFrame  frame;

    @Override
    public void insertUpdate(DocumentEvent event) {
        handleDocumentEvent(event);
    }

    @Override
    public void removeUpdate(DocumentEvent event) {
        handleDocumentEvent(event);
    }

    @Override
    public void changedUpdate(DocumentEvent event) {
        // Never called for 'JFormattedTextField'
    }

    @Override
    public void run() {
        showGui();
    }

    private JPanel createNumberPanel() {
        JPanel numberPanel = new JPanel();
        NumberFormat format = NumberFormat.getIntegerInstance();
        NumberFormatter formatter = new NumberFormatter(format);
        aantal = new JFormattedTextField(formatter);
        aantal.setColumns(10);
        Document doc = aantal.getDocument();
        doc.addDocumentListener(this);
        numberPanel.add(aantal);
        return numberPanel;
    }

    private void handleDocumentEvent(DocumentEvent event) {
        Document doc = event.getDocument();
        int len = doc.getLength();
        if (len > 0) {
            try {
                String text = doc.getText(0, len);
                int number = Integer.parseInt(text);
                Color fg;
                if (number < 1  ||  number > 7) {
                    fg = Color.red;
                }
                else {
                    fg = UIManager.getColor("TextField.foreground");
                }
                aantal.setForeground(fg);
            }
            catch (BadLocationException | NumberFormatException x) {
                // Ignore.
            }
        }
    }

    private void showGui() {
        frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(createNumberPanel(), BorderLayout.CENTER);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new RedNumbr());
    }
}

Whenever the contents of the JFormattedTextField are changed, the relevant DocumentListener method is invoked. In those methods I check whether the JFormattedTextField contains a number and if it does then I change the foreground color of the JFormattedTextField according to your conditions, i.e. if the number is less than one (1) or greater than 7 (seven).

Note that the NumberFormatter does not prevent entering non-digits because JFormattedTextField handles that when it loses focus. Nonetheless it handles entering positive and negative numbers, which saves you some work. And the point of my answer is simply to demonstrate how to change the foreground color based on the entered text, which I believe answers your question.

EDIT

In order to change the background of the JFormattedTextField, rather than the foreground, you just need to change two lines in my code, above.

Replace

fg = UIManager.getColor("TextField.foreground");

with

fg = UIManager.getColor("TextField.background");

and also replace

aantal.setForeground(fg);

with

aantal.setBackground(fg);


Source: stackoverflow