vmorph
vmorph

Reputation: 709

Java Swing Graphics - Why does the first-time rendering not work as expected?

I have a strange problem that probably stems from lack of understanding of how Swing works. When, for the first time since program start, I attempt to render the panel inside a window frame anew as soon as I press one of the alphabetic keys, the character in question is painted very briefly on the panel, before the panel turns white again.

On subsequent key strokes the program then behaves as expected: the panel re-renders with the character associated with the pressed key.

Since the character IS painted on the first key stroke, the fact, that it disappears immediately afterwards must mean the panel is rendered AGAIN, thus overriding the previous contents.

Here's the code:

// Main.java
public class Main {
public static void main(String[] args) {
    new GlyphFrame(new GlyphPanel());
}
}

// ---------------------------------------------------

// GlyphFrame.java
import javax.swing.JFrame;

public class GlyphFrame extends JFrame {
private static final long serialVersionUID = -7754180294993638709L;

private final int WIDTH = 500;
private final int LENGTH = 400;

public GlyphFrame(GlyphPanel panel){
    this.add(panel);
    this.setSize(WIDTH, LENGTH);
    this.setVisible(true);
    }
}

// ---------------------------------------------------
// GlyphPanel.java
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.JPanel;

public class GlyphPanel extends JPanel {
private static final long serialVersionUID = -6330730323655696958L;

public GlyphPanel(){
    this.setBackground(Color.WHITE);
    this.setFocusable(true);
    this.requestFocusInWindow();
    this.setFont(new Font("Dialog", Font.PLAIN, 12));

    this.addKeyListener(new GlyphKeyListener(this));
}

private void paintPanel(Graphics g, char c){
    super.paintComponent(g);
    g.drawString("" + c, 10, 10);
    g.setColor(this.getBackground());
    g.fillRect(0, 0, this.getWidth(), this.getHeight());

    g.setColor(Color.BLACK);
    g.drawString("" + c, 10, 10);

}

private class GlyphKeyListener implements KeyListener{

    private GlyphPanel panel;
    private int i = 0;

    public GlyphKeyListener(GlyphPanel panel){
    this.panel = panel;
    }

    @Override
    public void keyTyped(KeyEvent e) {}

        @Override
    public void keyPressed(KeyEvent e) {
    if(e.getKeyCode() >= KeyEvent.VK_A && e.getKeyCode() <= KeyEvent.VK_Z){
            System.out.println("Call number " + (++i));
        panel.paintPanel(panel.getGraphics(), e.getKeyChar());
    }
    }

    @Override
    public void keyReleased(KeyEvent e) {}
}
}

EDIT: Thanks for answering. Now I understand how painting is supposed to work in Swing.

If I need the panel to redraw itself I simply call repaint() which makes the system call paintComponent(Graphics g). Thus, whatever I want to paint I put it in an overridden paintComponent() method. paintComponent() is never called directly. Only use repaint().

Upvotes: 2

Views: 385

Answers (1)

Konstantin Solomatov
Konstantin Solomatov

Reputation: 10332

You shouldn't call paintPanel directly. swing manages painting itself. Instead of that you should do the following:

  • Override JComponent.paintComponent(Graphics g); It should use a field to retrieve the pressed character
  • On key press you should set the field and call JComponent.repaint();

That should work fine.

Upvotes: 5

Related Questions