Allright here is the error: java.awt.dnd.InvalidDnDOperationException: The operation requested cannot be performed by the DnD system since it is not in the appropriate state. The error appears when I drop some File inside the program (grabbed from the desktop). I am using Ubuntu 16.04 with Nautilus.
import javax.swing.*;
import java.awt.datatransfer.DataFlavor;
import java.awt.dnd.*;
import java.io.File;
import java.util.List;
class UI extends JFrame {
List<File> droppedFiles;
UI(){
super("My Program");
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setLayout(null);
this.setVisible(true);
this.setResizable(true);
this.setSize(800, 500);
this.setExtendedState(MAXIMIZED_BOTH);
JTextField dropArea = getDropArea();
this.add(dropArea);
}
private JTextField getDropArea(){
JTextField dropArea = new JTextField("Drop file here");
dropArea.setBounds(50, 50, 200, 200);
dropArea.setDropTarget(createNewDropTarget(dropArea));
return dropArea;
}
private DropTarget createNewDropTarget(JTextField dropArea) {
DropTarget dt = new DropTarget(){
#Override
public synchronized void drop(DropTargetDropEvent dtde) {
super.drop(dtde);
try {
dtde.acceptDrop(DnDConstants.ACTION_COPY);
droppedFiles = (List<File>) dtde.getTransferable().
getTransferData(DataFlavor.javaFileListFlavor);
dropArea.setText(droppedFiles.get(0).getName());
}catch (Exception e){
e.printStackTrace();
}
}
};
return dt;
}
}
The Error appears on the line where droppedFiles is initialized. (in the try catch block).
In a way you set up DropTarget there is no need to call super.drop(dtde);. This is actually the reason for the exception. Here is the implementation of DropTarget.drop():
public synchronized void drop(DropTargetDropEvent dtde) {
clearAutoscroll();
if (dtListener != null && active)
dtListener.drop(dtde);
else { // we should'nt get here ...
dtde.rejectDrop();
}
}
Since you are not initializing DropTarget with a listener the drop is rejected, and the subsequent call getTransferable() fails with InvalidDnDOperationException. If you comment super.drop(dtde); the problem should go away. A cleaner alternative would be to create a listener and pass it to DropTarget. Here is a small example:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.datatransfer.DataFlavor;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetAdapter;
import java.awt.dnd.DropTargetDropEvent;
import java.io.File;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class DDTest extends JPanel {
public DDTest() {
setLayout(new BorderLayout());
final JTextField dropArea = new JTextField("Drop file here");
add(dropArea);
new DropTarget(dropArea, new DropTargetAdapter() {
#Override
public void drop(DropTargetDropEvent dtde) {
try {
dtde.acceptDrop(DnDConstants.ACTION_COPY);
List<File> droppedFiles = (List<File>) dtde
.getTransferable().getTransferData(
DataFlavor.javaFileListFlavor);
dropArea.setText(droppedFiles.get(0).getName());
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 200);
}
private static void createAndShowGUI() {
final JFrame frame = new JFrame("DDTest");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new DDTest());
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
PS:
Note that using absolute layout can be complex and usually can be avoided. See A Visual Guide to Layout Managers for some ideas.
Related
I have a full screen window that plays a simple animation, and I want to make it so that when I press any key, the full screen is restored and the program stops.
The key listener class looks like this:
import java.awt.event.*;
public class key implements KeyListener {
private framerun animation=new framerun();
public void keyPressed(KeyEvent e){}
public void keyReleased(KeyEvent e){}
public void keyTyped(KeyEvent e){
animation.x=false;
}
}
The animation runs in a method, run, with a while loop which looks like this:
public void run(DisplayMode dm){
Screen s=new Screen();
s.setFullScreen(dm, this);
while(true){
try{
System.out.println(x);
Thread.sleep(300);
}catch(Exception e){}
if(!x)
s.RestoreScreen();
repaint();
}
}
PS: x is a boolean with initial value true, initiated in the constructor.
This is the main method:
public static void main(String args []){
DisplayMode dm=new DisplayMode(800, 600, 16,DisplayMode.REFRESH_RATE_UNKNOWN);
framerun f=new framerun();
key k=new key();
f.addKeyListener(k);
f.run(dm);
}
Now this works perfectly if there is no while loop. The full screen closes and the program stop. But with the while loop there is no response when I press a key. The value of x doesn't change to false as expected.
Ideas?
I can't get the DisplayMode switching to work, but it shouldn't make a difference.
Basically, KeyListener is fiddly. It requires the component that it is attached to is focusable and has focus.
The following example basically uses a combination of requestFocusInWindow and setFocusable on a JPanel to try and force focus to the JPanel, so that when a key is typed, the JPanel can respond to it...
import java.awt.Dimension;
import java.awt.DisplayMode;
import java.awt.EventQueue;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.GridBagLayout;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
private DisplayMode defaultMode;
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
GraphicsDevice gd = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
defaultMode = gd.getDisplayMode();
JFrame frame = new JFrame("Testing");
frame.setUndecorated(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
// DisplayMode dm = new DisplayMode(800, 600, 16, DisplayMode.BIT_DEPTH_MULTI);
// gd.setDisplayMode(dm);
gd.setFullScreenWindow(frame);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setFocusable(true);
setLayout(new GridBagLayout());
add(new JLabel("Test"));
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
requestFocusInWindow();
}
});
addKeyListener(new KeyAdapter() {
#Override
public void keyTyped(KeyEvent e) {
try {
GraphicsDevice gd = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
// gd.setDisplayMode(defaultMode);
gd.setFullScreenWindow(null);
} catch (Throwable exp) {
exp.printStackTrace();
}
SwingUtilities.windowForComponent(TestPane.this).dispose();
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
}
Personlly, I'd recommend using the key bindings API, How to Use Key Bindings, but this focuses on binding a single key to a given action, but overcomes the focus issues related to KeyListener
How can i attach the OpenGl display to a JFrame and so that when i close the JFrame is destroys the display? Here is my code so far:
package test.core;
import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Component;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;
import static org.lwjgl.opengl.GL11.*;
public class Main {
private static CreateCanvas canvas;
private static CreateFrame frame;
private static int width = 800;
private static int height = 600;
public static void main(String[] args) throws InterruptedException {
startFrames();
startDisplay();
}
public static void cleanUp() {
Display.destroy();
}
private static void startDisplay() {
try
{
Display.setParent(canvas);
Display.create();
}catch(LWJGLException ex)
{
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
private static void startFrames()
{
Runnable r = new Runnable(){
#Override
public void run(){
frame = new CreateFrame();
JButton button = new JButton("BUTTON");
canvas = new CreateCanvas();
JPanel panel = frame.panel;
panel.add(canvas);
panel.add(button);
frame.add(panel);
canvas.setSize(300, 300);
frame.setSize(width, height);
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
WindowListener listen = new WindowAdapter(){
#Override
public void windowClosing(WindowEvent we){
int result = JOptionPane.showConfirmDialog(frame, "Do you want to quit the Application?");
if(result == JOptionPane.OK_OPTION){
frame.setVisible(false);
cleanUp();
frame.dispose();
}
}
};
frame.addWindowListener(listen);
frame.setVisible(true);
}
};
SwingUtilities.invokeLater(r);
}
}
I had the opengl display attach to the JFrame before i did the runnable. But after adding the runnable the display now shows up the same size as my screen size. I have tried rearranging the
canvas.setSize();
and the
frame.setSize();
but nothing changes the opengl display is still the same size and when i try to close the JFrame first rather then close the display first i get this error:
Exception in thread "AWT-EventQueue-0" java.lang.IllegalStateException: From thread Thread[AWT-EventQueue-0,6,main]: Thread[main,5,main] already has the context current
which points me to my
Display.destroy();
which im guessing is telling me that i am not properly disposing the display? Can anyone help me attach the opengl display to the JFrame and fix the error above?
It appears that you started the Display in the "main" thread (which gives the main thread the current OpenGL context), but you're trying to destroy the display from a different thread, which in this case is the Event Dispatch Thread (EDT).
However, only one thread can have the current OpenGL context at a given time.
Although it is possible to change which thread has the current context, I don't think that's what you want to do here.
What we want to do here then is to destroy the display on the same thread that we created it on (the thread with the current OpenGL context). An approach I've seen is to use the Canvas's addNotify() and removeNotify() methods, which are run on the EDT, to set a flag that is checked on the OpenGL thread to determine when to destroy the display.
Also, the question mentioned problems about setting the size of the display. Your JFrame display size and Display size were not being set to what you desired because of how setSize() and LayoutManager's work. Please see the Java tutorials and documentation for details. In the following example, I have use one approach to address this issue.
So here is an example trying to stay close to the intent of the code posted in the question:
import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Dimension;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
public class LWJGLTester {
private volatile boolean isRunning = false;
/*
* The question asker seemed to desire that the JFrame be 800x600 and
* that the Display be 300x300. Regardless of the desired sizes,
* I think the important thing is to set the Canvas and Display to the same sizes.
*/
private int frameWidth = 800;
private int frameHeight = 600;
private int displayWidth = 300;
private int displayHeight = 300;
private Thread glThread;
public static void main(String[] args) {
new LWJGLTester().runTester();
}
private void runTester() {
final JFrame frame = new JFrame("LWJGL in Swing");
frame.setSize(frameWidth, frameHeight);
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
frame.addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent we){
int result = JOptionPane.showConfirmDialog(frame, "Do you want to quit the Application?");
if(result == JOptionPane.OK_OPTION){
frame.setVisible(false);
frame.dispose(); //canvas's removeNotify() will be called
}
}
});
JPanel mainPanel = new JPanel(new BorderLayout());
JButton button = new JButton("BUTTON");
JPanel buttonPanel = new JPanel();
buttonPanel.add(button);
mainPanel.add(buttonPanel, BorderLayout.NORTH);
Canvas canvas = new Canvas() {
#Override
public void addNotify() {
super.addNotify();
startGL();
}
#Override
public void removeNotify() {
stopGL();
super.removeNotify();
}
};
canvas.setPreferredSize(new Dimension(displayWidth, displayHeight));
canvas.setIgnoreRepaint(true);
try {
Display.setParent(canvas);
} catch (LWJGLException e) {
//handle exception
e.printStackTrace();
}
JPanel canvasPanel = new JPanel();
canvasPanel.add(canvas);
mainPanel.add(canvasPanel, BorderLayout.SOUTH);
frame.getContentPane().add(mainPanel);
//frame.pack();
frame.setVisible(true);
}
private void startGL() {
glThread = new Thread(new Runnable() {
#Override
public void run() {
isRunning = true;
try {
Display.setDisplayMode(new DisplayMode(displayWidth, displayHeight));
Display.create();
} catch (LWJGLException e) {
//handle exception
e.printStackTrace();
}
// init OpenGL here
while(isRunning) {
// render OpenGL here
Display.update();
}
Display.destroy();
}
}, "LWJGL Thread");
glThread.start();
}
private void stopGL() {
isRunning = false;
try {
glThread.join();
} catch (InterruptedException e) {
//handle exception
e.printStackTrace();
}
}
}
Note: This is example was tested using lwjgl version 2.9.1, since that seemed to be the latest version available at the time the question was originally posted.
I've got a viewport, and I've attached a change listener to it. Whenever I scroll through my viewport, my change listener gets called about four times. I'm not sure how to avoid this; I only want the call to happen once?
There's no way around this, JViewport will fire several stateChanged events because it's providing notification about changes to a number of properties...
From the JavaDocs...
Adds a ChangeListener to the list that is notified each
time the view's size, position, or the viewport's extent size has
changed.
At this point, it's kind of hard to know what to suggest as we don't know what it is you are trying to achieve, however, if you have to use a ChangeListener, you could set up a coalescing mechanism. That is, rather then responding to each event, you basically wait until a long enough delay has occurred between events before responding to it...
For example...
public class DelayedChangeHandler implements ChangeListener {
private Timer timer;
private ChangeEvent last;
public DelayedChangeHandler() {
timer = new Timer(250, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
stableStateChanged();
}
});
timer.setRepeats(false);
}
#Override
public void stateChanged(ChangeEvent e) {
last = e;
timer.restart();
}
protected void stableStateChanged() {
System.out.println("Finally...");
}
}
Basically, this is a ChangeListener implementation that uses a non-repeating javax.swing.Timer with a short delay. Each time stateChanged is called, the timer is restart. Finally, when the timer is allowed to "tick", it calls stableStateChanged indicating that enough time has passed since the last event was raised.
This assumes that you don't so much care about what caused the event, only that the event occured...
A runnable example...
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class TestViewport {
public static void main(String[] args) {
new TestViewport();
}
public TestViewport() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JPanel pane = new JPanel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(1000, 1000);
}
};
JScrollPane sp = new JScrollPane(pane);
sp.getViewport().addChangeListener(new DelayedChangeHandler());
sp.getViewport().addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
System.out.println(evt.getPropertyName());
}
});
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(sp);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class DelayedChangeHandler implements ChangeListener {
private Timer timer;
private ChangeEvent last;
public DelayedChangeHandler() {
timer = new Timer(250, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
stableStateChanged();
}
});
timer.setRepeats(false);
}
#Override
public void stateChanged(ChangeEvent e) {
last = e;
timer.restart();
}
protected void stableStateChanged() {
System.out.println("Finally...");
}
}
}
You can try to use AdjustmentListener for gettign scroll event once, try next:
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.io.UnsupportedEncodingException;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
public class Example {
public static void main(String[] args) throws UnsupportedEncodingException {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JScrollPane pane = new JScrollPane(new JTextArea());
pane.getVerticalScrollBar().addAdjustmentListener(new AdjustmentListener() {
#Override
public void adjustmentValueChanged(AdjustmentEvent e) {
if(e.getValueIsAdjusting()){
return;
}
System.out.println("vertical scrolled");
System.out.println("bar value = " + e.getValue());
}
});
frame.setContentPane(pane);
frame.setSize(300, 200);
frame.setVisible(true);
}
}
Here is another example.
How to Disable/Enable JFrame components when JInternalFrame isVisible inside JFrame/JDesktopPane? For example, make every JInternalFrame1 visible on the JDesktopPane (desktop pane set on the JFrame) all frame components like JMenuBar/JButton/etc. set disabled.
Have a solution?
If you have a reference to all your components, the best shot is to write a simple method that would disable everything (more or less like a state machine).
If you don't have a reference to all of them (like a GUI that uses reflection) you will need to get a root panel and iterate over it finding every component and disabling it.
Take a look at the Jemmy tool that is used to test Netbeans, they have a GUIBrowser that can give you an idea.
That makes use of JXLayer and JHLabs filters, basically, it creates a custom frame that wraps the JRootPane in a JXLayer, which allows you to "disable" the entire frame...
import com.jhlabs.image.BlurFilter;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.HeadlessException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JRootPane;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import org.jdesktop.jxlayer.JXLayer;
import org.jdesktop.jxlayer.plaf.effect.BufferedImageOpEffect;
import org.jdesktop.jxlayer.plaf.ext.LockableUI;
public class EnabledFrame {
public static void main(String[] args) {
new EnabledFrame();
}
public EnabledFrame() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
final LayeredFrame frame = new LayeredFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridBagLayout());
JMenuBar mb = new JMenuBar();
JMenu mFile = new JMenu("File");
mFile.add("Exit");
frame.setJMenuBar(mb);
mb.add(mFile);
JButton btn = new JButton("Click me");
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
frame.setEnabled(false);
}
});
frame.add(btn);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class LayeredFrame extends JFrame {
private BlurableLockedUI lockUI;
private JXLayer<JRootPane> rootLayer;
public LayeredFrame(String title) throws HeadlessException {
super(title);
}
#Override
protected void setRootPane(JRootPane root) {
if (rootLayer != null) {
remove(rootLayer);
}
super.setRootPane(root);
JRootPane rootPane = getRootPane();
rootLayer = new JXLayer<>(root);
rootLayer.setUI(getLockUI());
add(rootLayer, BorderLayout.CENTER);
}
protected BlurableLockedUI getLockUI() {
if (lockUI == null) {
lockUI = new BlurableLockedUI();
}
return lockUI;
}
#Override
public void setEnabled(boolean b) {
getLockUI().setLocked(!b);
super.setEnabled(b);
}
}
public class BlurableLockedUI extends LockableUI {
public BlurableLockedUI() {
super(new BufferedImageOpEffect(new BlurFilter()));
}
public void repaint() {
setDirty(true);
}
public void invalidate() {
setDirty(true);
}
public void revalidate() {
setDirty(true);
}
}
}
For a task I need to make a JFormattedTextField with the following behavior:
If value is edited and isn't equal to the last validated value the background must become yellow.
Value validation may take place at any time
If focus is lost nothing should happen (if background is yellow it should remain yellow,...)
Action should be taken when Enter is pressed
I can't seem to find the correct combination of Listeners to accomplish this. I tried using KeyAdapter, InputVerifier and PropertyChangeListenerbut that gives me very ugly code wich only works for 80%.
How should this be done?
Edit: I wrote a small example:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.text.ParseException;
import javax.swing.AbstractAction;
import javax.swing.InputVerifier;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Test extends JPanel {
private JFormattedTextField field;
private JLabel label;
private JButton btn;
public Test() {
super(new BorderLayout());
label = new JLabel("Enter a float value:");
btn = new JButton(new AbstractAction("Print to stdout"){
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(field.getValue());
}
});
field = new JFormattedTextField(new Float(9.81));
field.addKeyListener(new KeyAdapter(){
#Override
public void keyPressed(KeyEvent e){
field.setBackground(Color.YELLOW);
}
#Override
public void keyTyped(KeyEvent e){
if(e.getKeyCode() == KeyEvent.VK_ENTER){
try{
field.commitEdit();
field.setBackground(Color.WHITE);
}catch(ParseException e1){
field.setBackground(Color.RED);
}
}
}
});
field.setInputVerifier(new InputVerifier(){
#Override
public boolean verify(JComponent comp) {
try{
field.commitEdit();
field.setBackground(Color.YELLOW);
return true;
}catch(ParseException e){
field.setBackground(Color.RED);
return false;
}
}
});
add(label, BorderLayout.NORTH);
add(field, BorderLayout.CENTER);
add(btn, BorderLayout.SOUTH);
}
public static void main(String[] args) {
JFrame window = new JFrame("InputVerifier test program");
Container cp = window.getContentPane();
cp.add(new Test());
window.pack();
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setVisible(true);
}
}
This almost does everything I want. But the problem is the ENTER key is never caught. I think it is consumed before it reaches my KeyListener, but how can I prevent this?
Even if this can be prevented, I still have the feeling there should be a cleaner why to accomplish what above code does.
Try your hands on this code sample, tell me is this the desired behaviour, or you expecting something else, other than this :
import java.awt.*;
import java.awt.event.*;
import java.text.NumberFormat;
import javax.swing.*;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
public class JFormattedExample
{
private String lastValidValue;
private void createAndDisplayGUI()
{
JFrame frame = new JFrame("JFormattedTextField Example");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
JPanel contentPane = new JPanel();
contentPane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
final JFormattedTextField ftf = new JFormattedTextField(
NumberFormat.getNumberInstance());
ftf.setColumns(10);
ftf.setFocusLostBehavior(JFormattedTextField.PERSIST);
ftf.setValue(100);
lastValidValue = "100";
ftf.addCaretListener(new CaretListener()
{
public void caretUpdate(CaretEvent ce)
{
System.out.println("Last Valid Value : " + lastValidValue);
if (ftf.isEditValid())
{
String latestValue = ftf.getText();
System.out.println("Latest Value : " + latestValue);
if (!(latestValue.equals(lastValidValue)))
ftf.setBackground(Color.YELLOW.darker());
else
{
lastValidValue = ftf.getText();
ftf.setBackground(Color.WHITE);
}
}
else
{
System.out.println("Invalid Edit Entered.");
}
}
});
contentPane.add(ftf);
frame.setContentPane(contentPane);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String... args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new JFormattedExample().createAndDisplayGUI();
}
});
}
}