3

When I run the applet whose code is listed below, the text of the JLabel does not draw properly. There are extra garbage characters superimposed on top of the label text.

If I omit the call to setFont(), I don't see any rendering problems.

The applet runs fine in the appletviewer, but has these rendering artifacts in Chrome, Firefox, and IE 8. I'm running the latest version of Java 6 (rev. 25) on Windows XP. The problem seems to always occur in Chrome, and be intermittent in Firefox.

Do you have any ideas about what could be causing this? I suppose I'm doing something stupid.

I've posted the compiled applet here: http://evanmallory.com/bug-demo/.

package com.evanmallory;

import java.awt.*;
import javax.swing.*;

public class TellTime extends JApplet {

    private JLabel mMessage;

    public TellTime() {
        mMessage = new JLabel("Set the clock to the given time.",
            SwingConstants.CENTER);
        mMessage.setFont(new Font("Serif", Font.PLAIN, 36));
        getContentPane().add(mMessage);
    }

}

Here's a screenshot of what it looks like for me:

enter image description here

Roman C
  • 49,761
  • 33
  • 66
  • 176
Evan
  • 2,282
  • 2
  • 19
  • 21
  • +1 for hosting the applet. Note that `JLabel` is typically not [opaque](http://java.sun.com/products/jfc/tsc/articles/painting/#props). – trashgod May 27 '11 at 02:20
  • BTW - Will this BIG label occur in a GUI with other components? If so it might require a call to `revalidate()`. Is it necessary to increase the `Font` size of multiple instances of `JLabel`? Look into the [UIManager Defaults](http://tips4java.wordpress.com/2008/10/09/uimanager-defaults/) - there might be a setting there for label `Font` size. – Andrew Thompson May 27 '11 at 03:32

2 Answers2

2

Make sure Swing GUI components are created & updated on the EDT.

E.G. 1 (untested)

package com.evanmallory;

import java.awt.*;
import javax.swing.*;

public class TellTime extends JApplet {

    private JLabel mMessage;

    public TellTime() {
        SwingUtilities.invokeLater( new Runnable() {
            public void run() {
                mMessage = new JLabel("Set the clock to the given time.",
                    SwingConstants.CENTER);
                mMessage.setFont(new Font("Serif", Font.PLAIN, 36));
                getContentPane().add(mMessage);
            }
        });
    }
}

E.G. 2 (untested in anything but applet viewer)

Based on (ripped from) camickr's example, but with a call to setFont() wrapped in a Timer that fires every half second, and a subsequent call to repaint().

// <applet code="AppletBasic" width="300" height="100"></applet>
// The above line makes it easy to test the applet from the command line by using:
// appletviewer AppletBasic.java

import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Random;

public class AppletBasic extends JApplet
{
    Timer timer;

    /**
     * Create the GUI. For thread safety, this method should
     * be invoked from the event-dispatching thread.
     */
    private void createGUI()
    {
        final JLabel appletLabel = new JLabel( "I'm a Swing Applet" );
        appletLabel.setHorizontalAlignment( JLabel.CENTER );

        ActionListener listener = new ActionListener() {
            Random random = new Random();
            public void actionPerformed(ActionEvent ae) {
                // determine a size between 12 & 36.
                int size = random.nextInt(24)+12;
                appletLabel.setFont(new Font("Serif", Font.PLAIN, size));
                // tell the applet to repaint
                repaint();
            }
        };
        timer = new Timer(500, listener);
        timer.start();

        add( appletLabel );
    }

    public void init()
    {
        try
        {
            SwingUtilities.invokeAndWait(new Runnable()
            {
                public void run()
                {
                    createGUI();
                }
            });
        }
        catch (Exception e)
        {
            System.err.println("createGUI didn't successfully complete: " + e);
        }
    }
}

And since I'm here.

<html>
<body>
<applet codebase="classes" code="com.evanmallory.TellTime.class"
  width=800 height=500>
    <param name="level" value="1"/>
    <param name="topic" value="TellTime"/>
    <param name="host" value="http://localhost:8080"/>
  </applet>
  </body>
</html>
  1. The codebase="classes" looks suspicious. If this were on a Java based server, the /classes (and /lib) directory would be for the exclusive use of the server, and would not be accessible to an applet.
  2. The code attribute should be the fully qualified name of the cass, so com.evanmallory.TellTime.class should be com.evanmallory.TellTime.
  3. <param name="host" value="http://localhost:8080"/> I am prepared to make a WAG that that value is either unnecessary or wrong for time of deployment. It is better to determine at run-time using Applet.getDocumentBase() or Applet.getCodeBase().

BTW - The applet worked fine in my recent FF running a recent Oracle Java. But EDT problems are non determinate (random), so that does not mean much.

Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
  • 2
    +1 Yep, applets too. See also [Initial Threads](http://download.oracle.com/javase/tutorial/uiswing/concurrency/initial.html) – trashgod May 27 '11 at 02:12
  • @trashgod: I have to admit that I am very absent minded about implementing that advice in applets. If you notice me not doing it properly, could you give me a nudge? – Andrew Thompson May 27 '11 at 02:16
  • Humbly, I will. As such bugs are notoriously elusive, I find the picture especially compelling. – trashgod May 27 '11 at 02:29
  • Thanks, Andrew. Between Java plugin and browser caching I can't be 100% sure, but I don't think that using invokeLater() made any difference, although it certainly is good advice. Thanks for the tips on the HTML as well! – Evan May 27 '11 at 02:31
  • @Evan: To clear the browser cache, pop the Java Console and type 'x' before doing an `F5` on the page. Have you uploaded the altered applet, or are you just testing it locally? – Andrew Thompson May 27 '11 at 02:43
  • @Andrew: I'm just testing locally. I'm quite sure it's not cached, but after long enough I think I might be going crazy, you know :) – Evan May 27 '11 at 02:49
  • @Evan: "..after long enough I think I might be going crazy.." Oh no, the OP is afflicted with 'debugging applets fever'. Run for your lives! ;) Applets can drive you barmy. :( Note that it is uncommon to use a public no-args constructor for an applet. It would usually be done in the `init()` method. I did not mention that at first since I did not believe it was the source of the problem. OTOH you might *try* moving the code into `init()` and removing the constructor. – Andrew Thompson May 27 '11 at 02:56
  • @Andrew: E.G. 2 still exhibits issues. I tweaked it to increase the font size by 2 each time it is called, and it draws correctly for font sizes <= 20, and incorrectly for sizes >= 22. So, that's something to think about. – Evan May 27 '11 at 03:23
1

The Swing tutorial always creates the GUI components in the init() method:

// <applet code="AppletBasic.class" width="400" height="400"></applet>
// The above line makes it easy to test the applet from the command line by using:
// appletviewer AppletBasic.java

import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;

public class AppletBasic extends JApplet
{
    /**
     * Create the GUI. For thread safety, this method should
     * be invoked from the event-dispatching thread.
     */
    private void createGUI()
    {
        JLabel appletLabel = new JLabel( "I'm a Swing Applet" );
        appletLabel.setHorizontalAlignment( JLabel.CENTER );
        add( appletLabel );
    }

    public void init()
    {
        try
        {
            SwingUtilities.invokeAndWait(new Runnable()
            {
                public void run()
                {
                    createGUI();
                }
            });
        }
        catch (Exception e)
        {
            System.err.println("createGUI didn't successfully complete: " + e);
        }
    }

}

See: How to Make Applets

camickr
  • 321,443
  • 19
  • 166
  • 288
  • If I take your example and add the line `appletLabel.setFont(new Font("Serif", Font.PLAIN, 36));`, the text appears garbled for me. – Evan May 27 '11 at 02:49
  • @Evan: Try calling `repaint()` (on the applet or content pane) after the label font size is changed, or move the call to set the font before a call to set text. – Andrew Thompson May 27 '11 at 03:01
  • All I can guess is that as you suspect it is a version issue. This is as simple as an applet gets and it follows the tutorial example for creating the GUI on the EDT. – camickr May 27 '11 at 03:26