Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Updating my Graphics

I'm just starting to learn about programming in Java and even more recently with graphics, and I've run into some problems. I want to create a game like dwarf fortress in look, with colored text instead of images.

This is what I have so far:

public void paint(Graphics g) {
    super.paint(g);
    g.setColor(Color.red);

    for (int i = 0; i < 50; i++) {
        g.drawString("[Game goes here]", 100, 150);
        g.dispose();
        System.out.println(i);
    }
    g.dispose();
}

public GTest() {
    setSize(Toolkit.getDefaultToolkit().getScreenSize().width / 3, Toolkit
            .getDefaultToolkit().getScreenSize().width / 3 + 50);
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    setVisible(true);
}

public static void main(String[] args) {
    GTest myWindow = new GTest();
}

I want it to update the graphics on a timer, but I'm not really sure how to do this.

I know that this is a pretty broad question and I would be happy to clarify anything you might want to know.

EDIT:

So I added this bit:

String[] letters = new String[10];
float fontsize = Toolkit.getDefaultToolkit().getScreenSize().width / 30;

public void paint(Graphics g) {

    g.setColor(textColor);
    setFont(getFont().deriveFont(fontsize));
    for(int i = 0; i < 10; i++){
        if((int) (Math.random() * 100) > 97){
            letters[i] = "w";
            textColor = new Color(0, 0, 100);

        }else{
            letters[i] = "l";
            textColor = new Color(0, 100, 0);
        }
        g.drawString(letters[i], i * 3, 10);
    }

But now it doesn't display at all. I added a sysout after the g.drawString and it performed it so I'm not sure what the problem is.

like image 301
Sam Avatar asked Dec 11 '25 08:12

Sam


2 Answers

When doing anything based on a timer in Swing, the javax.swing.Timer class is your best friend.

It's JavaDocs explains its usage pretty well, so here's an example.

public class GTest extends JFrame implements ActionListener {
    private Color textColor = Color.BLACK;
    private Random random = new Random();

    @Override
    public void paint(Graphics g) {
        super.paint(g);
        g.setColor(textColor);
        g.drawString("[Game goes here]", 100, 150);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        textColor = new Color(random.nextInt(0x00ffffff));
        repaint();
    }

    public GTest() {
        setSize(Toolkit.getDefaultToolkit().getScreenSize().width / 3,
                Toolkit.getDefaultToolkit().getScreenSize().width / 3 + 50);
        setDefaultCloseOperation(EXIT_ON_CLOSE);

        Timer timer = new Timer(500, this);
        timer.setInitialDelay(0);
        timer.start();

        setVisible(true);
    }

    public static void main(String[] args) {
        GTest myWindow = new GTest();
    }
}

It's your GTest class once again, but this time the text color changes automatically every 0.5 seconds.

Notice two main changes:

  1. The constructor now sets up a new instance of Timer with no initial delay, period of 500 ms and its listener set up to this. That means that this constructed instance will listen to that timer's ticks.
  2. To do that, we needed to implement the ActionListener interface. This forces us to write the actionPerformed() method which gets called every time the Timer ticks. In this method, we change the textcolor to a random one and call repaint() which subsequently calls our paint() method and gets the text written.

P.S. You don't have to dispose() your Graphics object every time. It's actually said in its JavaDoc, too (emphasize mine):

Graphics objects which are provided as arguments to the paint() and update() methods of components are automatically released by the system when those methods return. For efficiency, programmers should call dispose() when finished using a Graphics object only if it was created directly from a component or another Graphics object.

like image 136
Petr Janeček Avatar answered Dec 12 '25 23:12

Petr Janeček


First of all, if you don't create a copy of the Graphics context, you shouldn't be disposing of it. This could actually prevent other parts of your application form been painted ;)

Second of all. I would avoid extending from a top level container, like JFrame, apart from allowing you to draw under the frame/border decoration of the window, they aren't double buffered.

Instead, I'd use something like a JPanel instead and override its paintComponent method. This will provide you with automatic double buffering.

Because Swing is a single threaded framework, it is expected that all updates to the UI be executed within the context of the Event Diapatching Thread.

This makes live a little difficult when it comes to try to do things like waiting and synchronizing paint updates.

Luckly, Swing provides a javax.swing.Timer which allows you schedule an event for some time in the future. This can also be setup to repeat and regular intervals.

Timer timer = new Timer(40, new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        // perform your required actions here
    }
});

Now, beware, the actionPerformed method is being executed with the context of the EDT, this means, that any long running/time consuming processing you do here may cause you UI to stop painting

Take a look at

  • Performing Custom Painting
  • Intial Threads
  • Concurrency in Swing

For more details...

like image 20
MadProgrammer Avatar answered Dec 13 '25 00:12

MadProgrammer



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!