tags:

views:

78

answers:

4

Hello, everyone, I'm a High School AP Computer Science student doing an independent study project in Java. I have chosen to write an application for beginning piano students in which the computer displays a picture of the keyboard with a note highlighted. The user then selects the name of the note that corresponds to the highlighted key, with a timer that counts to zero and then reports the user's score.

My view is almost finished, but I am having trouble displaying my timer on the screen.

The timer is created by the model and runs in a separate thread, every second instructing the controller to update the timer, which calls a method in view, which in turn sets a value in the object TimerUpdateComponent and then validates to display the new text.

At least, that's the theory. The timer works perfectly - prints to the console every second, just like I asked - but when I run the view, nothing appears. So, thinking I would do what the master does and figure out the difference, I copied this code directly from Horstmann and Cornell's [I]Core Java - Volume I[/I], which should display the string "Hello, World!" in the center of the panel:

public void paintComponent(Graphics g){<br>
        Graphics2D g2 = (Graphics2D) g;<br>
        String message = "Hello, World!";<br>
        Font f = new Font("Serif",Font.BOLD,36);<br>
        g2.setFont(f);

        //measure the size of the message
        FontRenderContext context = g2.getFontRenderContext();
        Rectangle2D bounds = f.getStringBounds(message, context);

        //set (x,y) to top-left corner of text
        double x = (getWidth() - bounds.getWidth())/2;
        double y = (getHeight() - bounds.getHeight())/2;

        //add ascent to y to reach the baseline
        double ascent = -bounds.getY();
        double baseY = y + ascent;

        //draw the message
        g2.drawString(message, (int)x, (int)y);
        g2.setPaint(Color.LIGHT_GRAY);

        //draw the baseline
        g2.draw(new Line2D.Double(x, baseY,x - bounds.getWidth(), baseY));

        //draw the enclosing rectangle
        Rectangle2D rect = new Rectangle2D.Double(x,y,bounds.getWidth(), bounds.getHeight());
        g2.draw(rect);
    }
}

To my astonishment, this code didn't display the string either! I thought the string might have been too big for the rather small panel, so it was only showing the white space, but I tried changing the type size to 10, and that didn't work either.

So now I'm really :chomp: ing. The only thing I can think of is that the book is out of date (Did Sun change the way Swing works since 2008? I doubt it.) or made an egregious coding error (in its eighth edition?) So I created a separate file and copied the entire .java file from the book, and it worked just fine.

Please help me!

Also, here's my original method body in case you want to look at that:

    String message = time/60+":"+time%60;<br>
    Graphics2D g2 = (Graphics2D) g;<br>
    FontRenderContext context = g2.getFontRenderContext();<br>
    Rectangle2D bounds = g2.getFont().getStringBounds(message, context);<br>
    double x = (getWidth() - bounds.getWidth()) / 2;<br>
    double y = (getHeight() - bounds.getHeight() / 2);<br>
    g2.drawString(message,(int)x,(int)y);<br>
A: 

You should probably set the paint of the text before drawing the text. Also make sure to call repaint on the component on each update using SwingUtilities.invokeLater()

Jay Askren
+1  A: 

After the first repaint you're painting gray text on a gray background.

But why not just use a JLabel and call setText every time the timer fires, rather doing all this yourself?

Dan Dyer
+1 for using a JLabel if possible.
PSpeed
I changed the paint color to red, and still got no result.I'm not using a JLabel because I may wish to format text, change the size, color, etc. and JLabels are too restricting.
ILikeFood
A: 

The key phrase is

the timer runs on a separate thread.

You can only update a Swing GUI from the Event Dispatch Thread, the one that works the GUI.

The solution is to run your update code using SwingUtilities.invokeLater().

Carl Smotricz
A: 

One convenient feature of javax.swing.Timer is that the action event handler executes on the event dispatching thread (EDT). Sun's tutorial discusses How to Use Timers in this manner, and other examples abound.

trashgod