Java Forum / GUI / January 2008
Choppy refresh problem with JLabels and JMenuItem accelerators
Daniel Gee - 12 Jan 2008 23:10 GMT I've got a tile based game (a roguelike) which uses a grid of JLabels each displaying an ImageIcon to display what's happening within the game. I want to use keyboard input, so I setup JMenuItem instances each with an accelerator for a different key. When a key is pressed, the key is responded to with the accelerators and the hero goes one square left, right, or whatever using an action listener to get an appropriate command to the game model. Then the screen is redrawn. Very simple.
My problem is this: if a key is held down, the refreshing becomes very choppy and although every event is responded to, the program doesn't refresh the display fast enough and ends up skipping. What I'd like is either a suggestion of a way to make the graphics faster or a way to set a "delay" on the menu accelerator or the event processing so that events aren't generated faster than a specific speed.
Andrew Thompson - 12 Jan 2008 23:44 GMT ...
> ...What I'd like is > either a suggestion .. Post shorter line to usenet? Or..
>..of a way to make the graphics faster ... ..oh, in that case, post code we can play with. (but please note the line width).
-- Andrew T. PhySci.org
Daniel Gee - 13 Jan 2008 00:55 GMT Sorry about the lines, Google Groups shows them wrapped around when it posts but I guess it doesn't actually send it out to others like that.
ok, so there are a few classes involved: the main class: http://paste.uni.cc/18079 the JRogueFrame: http://paste.uni.cc/18080 the MapPanel: http://paste.uni.cc/18081
The LogFrame just captures the System.out stream. The HeroStatusPanel just has some player stats along the bottom of the JRogueFrame.
MapInfo just returns a string of what image file should be at that location, and the IconManager stores all the game's images in a HashMap, and loads new ones lazily as they're required.
Andrew Thompson - 13 Jan 2008 01:43 GMT > Sorry about the lines, Google Groups shows them wrapped around when it > posts > but I guess it doesn't actually send it out to others like that. Sure it does, then the *client* newsreader wraps the lines wherever it feels like. That is the point. Since you cannot control where the *reader's* news client wraps the text, it is better to claim control of it yourself by breaking lines relatively short.
(As an aside, by 'short' I mean around 62-70 chars, as opposed to the larger widths at which you seem to be hitting 'newline'.)
Here is a tool I developed to help check line width. You might find it useful. <http://www.physci.org/codes/sscce.html#twc>
> ok, so there are a few classes involved: > the main class:http://paste.uni.cc/18079 > the JRogueFrame:http://paste.uni.cc/18080 > the MapPanel:http://paste.uni.cc/18081 There are acutally a few more, like.. 'JRogueGlobals'. But please do not 'put up' that class - I prefer a *single* source file that has everything included 'out of the box'. Specifically an SSCCE.
* <http://www.physci.org/codes/sscce.html>
> The LogFrame just captures the System.out stream. Wa'..Huh? Is this output stream necessary for displaying the problem? If not, remove it. If so, try to programmatically emulate it (rather than force the user to supply data).
-- Andrew T. PhySci.org
Daniel Gee - 13 Jan 2008 03:54 GMT Alright, here's a SSCCE that seems to still capture the problem: http://paste.uni.cc/18083
As you should be able to see, if you tap a key extremely rapidly then it'll take one step at a time over and over just fine. But if you hold a key down running from one edge to another then it'll become laggy and only show every few 'frames' of movement.
So it seems I need either a different (faster) way to display and get input, or a way to slow down how often a held key generates Action Events. There might be a third option I'm not seeing.
Because of the nature of the game, I can't just update the player's label only, since there will be many other creatures, as well as "fog of war" being updated over a variable area every turn. The exact area would depend on the shape of the level.
(On the same aside, I was using line width slightly less than 80 in the second post, which I figured was short enough for everyone. Oh well.)
Andrew Thompson - 13 Jan 2008 07:55 GMT > Alright, here's a SSCCE that seems to still capture the problem: > http://paste.uni.cc/18083 Hmmm. That code was frustratingly close to code that displays the problem (after re-enabling the menu!).
Still - I was intrigued enough to continue with it, and came up with this variant*. I chose to: - dump the JLabels for a direct 'paint()' - lose the try/catch - change the ActionListener for a KeyListener - a number of other minor things I cannot recall.
* See how this works for you.. <sscce> import java.awt.*; import java.awt.event.*; import javax.swing.*;
public class JRSCE extends JFrame implements KeyListener { static final int COLS = 80; static final int ROWS = 22; String[][] grid = new String[COLS][ROWS];
int columnX = 3; int columnY = 3;
/** * @param args none. */ public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() { JRSCE thisClass = new JRSCE(); thisClass.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE); thisClass.setVisible(true); } }); }
/** * build. */ public JRSCE() { super("Use NUMPAD");
GridPanel gp = new GridPanel(); gp.addKeyListener(this); this.setContentPane(gp); pack(); for (int y = 0 ; y < ROWS ; y++) { for (int x = 0 ; x < COLS ; x++) { grid[x][y] = "."; } } refresh(); }
public void keyReleased(KeyEvent ke) {} public void keyTyped(KeyEvent ke) {} public void keyPressed(KeyEvent ke) { switch ( ke.getKeyCode() ) { case KeyEvent.VK_NUMPAD1: columnX--; columnY++; break; case KeyEvent.VK_NUMPAD2: columnY++; break; case KeyEvent.VK_NUMPAD3: columnX++; columnY++; break; case KeyEvent.VK_NUMPAD4: columnX--; break; case KeyEvent.VK_NUMPAD6: columnX++; break; case KeyEvent.VK_NUMPAD7: columnX--; columnY--; break; case KeyEvent.VK_NUMPAD8: columnY--; break; case KeyEvent.VK_NUMPAD9: columnX++; columnY--; break; default: System.err.println( "Use the numpad to walk! " + ke.getKeyCode() + " / " + ke.getKeyChar()); } /** * Bounds check to not "walk off the screen" */ columnX = Math.min(COLS - 1, columnX); columnY = Math.min(ROWS - 1, columnY); columnX = Math.max(0, columnX); columnY = Math.max(0, columnY); refresh(); repaint(); }
/** * Refresh the screen after each STEP. */ void refresh() { for (int y = 0 ; y < ROWS ; y++) { for (int x = 0 ; x < COLS ; x++) { if (columnX == x && columnY == y) { grid[x][y]="P"; } else { grid[x][y]="."; } } } }
class GridPanel extends JPanel {
static final int STEP=10;
GridPanel() { setFocusable(true); }
/** * The displayed dgrid of labels. */ public void paintComponent(Graphics g) { for (int y = 0 ; y < ROWS ; y++) { for (int x = 0 ; x < COLS ; x++) { g.drawString( grid[x][y], (x+1)*STEP, (y+1)*STEP ); } } }
public Dimension getPreferredSize() { return new Dimension( (COLS+1)*STEP, (ROWS+1)*STEP); } } } </sscce>
-- Andrew T. PhySci.org
Daniel Gee - 13 Jan 2008 22:08 GMT Andrew:: Thank you. That example works extremely well.
I'm not sure why my example didn't work for you with the JMenu disabled, but maybe you're on Windows or Mac which might treat it differently (I didn't test). I kept it disabled to most closely match the actual program.
I also didn't know that KeyListener was even available for use outside of things like TextArea and TextField. Good tip there. I was afraid that I'd have to use JNI to just make a Curses program, which would have killed all possible mouse support. Thanks again.
Roedy:: I'm afraid since it was not literal flicker in the normal sense, the only tip that applies is tip #8, which was already in use.
Andrew Thompson - 14 Jan 2008 02:49 GMT > Andrew:: Thank you. That example works extremely well. You're welcome.
> I'm not sure why my example didn't work for you with the > JMenu disabled, but maybe you're on Windows ... Right first time. Win XP, running Java 1.6.something.
-- Andrew T. PhySci.org
Lew - 13 Jan 2008 16:45 GMT > Alright, here's a SSCCE that seems to still capture the problem: > http://paste.uni.cc/18083 Small stylistic notes, not related to your primary question:
"thisClass" is a very misleading name for a variable that is neither a class nor points to 'this'.
Also, the convention for class names is that the first letter of each compound word part is capitalized, not the entire identifier (e.g., "SwingUtilities", not "SWINGUTILITIES") - so JRSCE should be "Jrsce", or better yet, a name that actually describes something about the class, e.g., "FlickerDemo".
May I further suggest that you choose an indent level smaller than 8 spaces? You run past the nominal 80-character line width much faster with such a large indent.
 Signature Lew
Jeff Higgins - 13 Jan 2008 01:59 GMT > ok, so there are a few classes involved: > the main class: http://paste.uni.cc/18079 > the JRogueFrame: http://paste.uni.cc/18080 > the MapPanel: http://paste.uni.cc/18081 Gee, thanks for the pointer to pastebin.com. I wasn't aware of this excellent service. Wish I could help with your refresh query. Appreciative, JH
Andrew Thompson - 13 Jan 2008 02:40 GMT > > ok, so there are a few classes involved: > > the main class: http://paste.uni.cc/18079 ...
> I wasn't aware of this excellent service. Yes. Daniel neatly sidestepped some of the perils of posting code to usenet, by instead loading it up at pastebin (they offer semi-nice code formatting, too).
Sites like pastebin are of great use to us 'distributed tech types'. :-)
-- Andrew T. PhySci.org
Roedy Green - 13 Jan 2008 08:30 GMT On Sat, 12 Jan 2008 15:10:28 -0800 (PST), Daniel Gee <zefria@gmail.com> wrote, quoted or indirectly quoted someone who said
>My problem is this: if a key is held down, the refreshing becomes very >choppy and although every event is responded to, the program doesn't >refresh the display fast enough and ends up skipping. See http://mindprod.com/jgloss/flicker.html
 Signature Roedy Green, Canadian Mind Products The Java Glossary, http://mindprod.com
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|