JTextField in fullscreen game

why JTextField causing deadlock?
i have set all swing component to ignore repaint
and only JTextField cause the game stop responding

deadlock happen when i type text in JTextField area
pressing non-letter like arrow key is alright

someone can explain this?
oh yeah i have turn off double buffering too
anyway it happens in all mode
(window mode, fullscreen mode, active rendering, and passive rendering)

thanks in advance

Post some code that shows the problem so that we also can try to verify the problem or come with a solution.

not sure which code i must post :-[

this is my rendering loop:


      private synchronized void mainLoop() {
            while (running) {
                  try { wait(); } catch (Exception e) { printStackTrace(e, "mainLoop wait"); }
                  update();      // updating the screen
                  if (activeRendering)
                        doActiveRender(); else       // render using buffer strategy into screen
                        doRender();                        // render using volatile image into screen
            }
}

this is the render code :


      private void render(Graphics2D g) {
            paint(g);
            mainFrame.getContentPane().paintComponents(g);
            if (showFPS) {
                  g.setFont(defaultFont); g.setColor(Color.red);
                  g.drawString("FPS : "+currentFPS, 20, 50);
                  g.drawString("FPS : "+currentFPS, 21, 50);
            }
      }
      private void doActiveRender() {
            Graphics2D bufferGfx;
            /* Active rendering using buffer strategy. */
            do {
                  bufferGfx = (Graphics2D) bufferStrategy.getDrawGraphics();
                  render(bufferGfx);
                  bufferGfx.dispose();
            } while (bufferStrategy.contentsLost());      // if (contentsLost) re-rendering

            bufferStrategy.show();      // draw to screen
      }

I meant posting a small complete program that shows the problem. Just a frame, active rendering, a JTextField. If you make such a program and notice that the problem isn’t occuring the error is in your old code somewhere… Then just start searching, otherwise we can test your small problem to verify the problem and find a solution

Hmmm…

Since JTextField is a subclass of JTextComponent, it should be thread safe. However, the JavaDocs say:

“The swing text components provide some support of thread safe operations. Because of the high level of configurability of the text components, it is possible to circumvent the protection provided. The protection primarily comes from the model, so the documentation of AbstractDocument describes the assumptions of the protection provided.”

Have you tried using a shortcut for invoking non-thread-safe methods to modify your GUI:

EventQueue.invokeLater
(or better)
SwingUtilities.invokeLater
(
new Runnable()
{
public void run()
{
field.setText(“Hola, Gringo!”);
}
}
);

or:

SwingUtilities.invokeLater
(
new Runnable()
{
public void run()
{
try
{
// Some GUI modifying method which throws InterruptedException
}
catch (InterruptedException x)
{
x.printStackTrace();
}
}
}
);

See the discussion of the AbstractDocument class for further clues. There are read/write locks firing…

more confusing! >:(
the error occured when typing JTextField in a panel
if typing in standalone JTextField, nothing happen, it works fine ???
this is the code

Game.java


import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.swing.*;
import java.net.URL;
import java.net.MalformedURLException;
import java.util.Random;
import java.util.Locale;
import java.io.File;

public class Game implements Runnable {
      private final MainFrame mainFrame;
      private Font                  defaultFont = new Font("Helvetica", Font.PLAIN, 12);
      private GraphicsDevice       myDevice;
      private Dimension            appDimension;
      private BufferStrategy       bufferStrategy = null;

      /* Thread animation */
      private Thread                  animate = null;
      private boolean             running = false;

      /* Frame per second */
      private int                        fps;
      private boolean                  showFPS = true;
      private long                   oldTime, newTime;
      private int                   ticks = 0, currentFPS = 0;
      private long                   msDelay, targetMs;
      private long                   timeDiff;
      private long                   startTime, finishTime;

      public Game() {
            myDevice = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
            GraphicsConfiguration gc = myDevice.getDefaultConfiguration();
            mainFrame = new MainFrame(gc, "test frame");

            appDimension = new Dimension(640, 480);
            setFPS(40);

            JTextField text = new JTextField("this JTextField is thread safety");
            text.setBounds(80,200,300,40);
            mainFrame.add(text);

            JPanel pane = new JPanel();
                  JTextField textInPane = new JTextField("type fast or repetitive in this text field to get crash! :)");
                  textInPane.setPreferredSize(new Dimension(320,50));
            pane.setBounds(80,80,360,100);
            pane.setBorder(BorderFactory.createTitledBorder("why JTextField in a panel causing deadlock???"));
            pane.add(textInPane);
            mainFrame.add(pane);

            JButton btn = new JButton("safety button");
            btn.setBounds(200,25,120,30);
            mainFrame.add(btn);

            mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            mainFrame.setVisible(true);
            int width = appDimension.width + mainFrame.getInsets().left + mainFrame.getInsets().right,
                  height = appDimension.height + mainFrame.getInsets().top + mainFrame.getInsets().bottom;
            mainFrame.setSize(width, height);

            mainFrame.createBufferStrategy(2);
            bufferStrategy = mainFrame.getBufferStrategy();

            mainFrame.validate();
      }

      protected final void setFPS(int targetFPS) {
            fps = targetFPS;
            msDelay = 1000/fps;
            targetMs = msDelay;
      }

      protected final void startGame() {
            running = true;
            // create rendered thread
            animate = new Thread(this);
            animate.setDaemon(true);
            animate.setPriority(Thread.MAX_PRIORITY-1);
            animate.start();      // start the rendered thread
            /* The Game Loop */
            mainLoop();
      }

      private synchronized void mainLoop() {
      try {
            while (running) {
            try { wait(); } catch (Exception e) { }
                  //update();      // updating the screen
                  doActiveRender();
            }
      } finally {
      } }

      private void render(Graphics2D g) {
            g.setColor(Color.red);
            g.fillRect(0,0,appDimension.width,appDimension.height);
            mainFrame.getContentPane().paintComponents(g);
            if (showFPS) {
                  g.setFont(defaultFont); g.setColor(Color.black);
                  g.drawString("FPS : "+currentFPS, 20, 50);
                  g.drawString("FPS : "+currentFPS, 21, 50);
            }
      }
      private void doActiveRender() {
            Graphics2D bufferGfx;
            /* Active rendering using buffer strategy. */
            do {
                  bufferGfx = (Graphics2D) bufferStrategy.getDrawGraphics();
                  bufferGfx.translate(mainFrame.getInsets().left, mainFrame.getInsets().top);
                  render(bufferGfx);
                  bufferGfx.dispose();
            } while (bufferStrategy.contentsLost());      // if (contentsLost) re-rendering

            bufferStrategy.show();      // draw to screen
      }

      private void calculateFPS() {
            // calculating current FPS
            newTime = System.currentTimeMillis();
            if (newTime > oldTime+1000) {
                  currentFPS = ticks; ticks = 0;
                  oldTime = newTime;
            }
      }
      public void run() {
            startTime = System.currentTimeMillis();
            oldTime = startTime;
            while (running) {
                  try { Thread.sleep(msDelay);
                  } catch (Exception e) { }

                  ticks++;
                  if (showFPS) calculateFPS();
                  synchronized(this) { notifyAll(); }

                  if (ticks%fps == 0) {
                        finishTime = System.currentTimeMillis();
                        timeDiff = ((finishTime-startTime)/fps) - targetMs;
                        if (timeDiff > 0) msDelay--; else
                           if (timeDiff < 0) msDelay++;
                        startTime = finishTime;
                        //System.out.println("Sleep for "+msDelay+"   target = "+targetMs+"   time diff = "+timeDiff);
                  }
            }
            synchronized(this) { notifyAll(); }
      }

      /** Quit the game and back to system. */
      public void quitGame() { running = false; }

      public static void main(String[] args) {
            Game game = new Game();
            game.startGame();
      }

}

and MainFrame.java code:


import java.awt.Component;
import java.awt.Container;
import java.awt.GraphicsConfiguration;
import java.awt.Cursor;
import java.awt.*;
import java.awt.event.*;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JComponent;
import javax.swing.*;

final class MainFrame extends JFrame {
      private final JDesktopPane pane = new JDesktopPane();

      public MainFrame(GraphicsConfiguration gc, String title) {
            super(title, gc);
            setResizable(false);
            setIconImage(null);

            setContentPane(pane);

            /* sets all frame child to ignore repaint */
            getContentPane().setIgnoreRepaint(true);
            getRootPane().setIgnoreRepaint(true);
            getLayeredPane().setIgnoreRepaint(true);
            setIgnoreRepaint(true);
      }

      void add(JComponent c) {
            setRepaintOff(c);
            pane.add(c);
            validate();
      }

      /* recursively turn off double buffering and
         sets component to ignore repaint. */
      private void setRepaintOff(Component c) {
            c.setIgnoreRepaint(true);
            if (c instanceof JComponent) ((JComponent)c).setDoubleBuffered(false);
            if (c instanceof Container) {
                  Component[] children = ((Container)c).getComponents();
                  for(int i=0;i < children.length;i++)
                        setRepaintOff(children[i]);
            }
      }

}

mattocks, i’m not modify the gui by press any button or code modify, so can’t use swing.invokeLlater

Perhaps this link is relevant:

http://www.milk.com/java-rants/bug01-awt-event.html

Excerpt:

“The case is that a user thread calls JFrame.setVisible(true) on a frame which contains a text field. The act of visible-izing causes an attempt to acquire a read lock on the document of the text field. At the same time, the user is typing in the field, and a text insertion event is being processed, which has already caused a write lock to be acquired on the same document. Given that the write lock has already been acquired, the read lock acquisition is stalled. However, the thread doing the setVisible() has already managed to acquire the anonymous universal lock (which I suspect is java.awt.Component.LOCK). Soon, the AWT event thread tries to acquire that same lock (i.e. synchronize on it). Oops! Deadlock: the event queue has the document lock and wants the anonymous lock; the user thread has the anonymous lock and wants the document lock.”

humm…still don’t get it what the article says… ???
anyway, is my code cause deadlock in other machine?
or just in my machine?
the strangest thing is in my game, the deadlock occur when i type only one or two words. >:(