Painting a Canvas in an Applet

2019-07-26 17:28发布

问题:

I currently have a small Java program which I would like to run both on the desktop (ie in a JFrame) and in an applet. Currently all of the drawing and logic are handled by a class extending Canvas. This gives me a very nice main method for the Desktop application:

public static void main(String[] args) {
    MyCanvas canvas = new MyCanvas();
    JFrame frame = MyCanvas.frameCanvas(canvas);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    canvas.loop();
}

Can I do something similar for the applet? Ideally MyCanvas would remain the same for both cases.

Not sure if its important but I am drawing using BufferStrategy with setIgnoreRepaint(true).

Edit: To clarify, my issue seems to be painting the canvas -- since all the painting is being done from the canvas.loop() call.

回答1:

Applet is a Container, just add your Canvas there.



回答2:

Generally, the way you would have an application that is also an applet is to have your entry point class extend Applet, and have its setup add the Canvas to itself, etc. etc.

Then, in the main method version, you just instantiate your Applet class and add it to a new Frame (or JApplet / JFrame, etc.).

See here and here for examples of the technique, which essentially boils down to (from the first example):

  public static void main(String args[])
  {
    Applet applet = new AppletApplication();
    Frame frame = new Frame();
    frame.addWindowListener(new WindowAdapter()
    {
      public void windowClosing(WindowEvent e)
      {
        System.exit(0);
      }
    });

    frame.add(applet);
    frame.setSize(IDEAL_WIDTH,IDEAL_HEIGHT);
    frame.show();
  }


回答3:

Canvas is inappropriate for adding to Swing components. Use JComponent instead (and setOpaque(true)).

Swing components should always be manipulated on the AWT Event Dispatch Thread (EDT). Use java.awt.EventQueue.invokeLater (invokeAndWait for applets). You shouldn't do any blocking operations from the EDT, so start your own threads for that. By default you are running in the main thread (or applet thread for applets), which is quite separate from the EDT.

I suggest removing any dependence from your MyCanvas to JFrame. I also suggest keeping code for applications using frame separate from that using applets. Adding a component to a JApplet is the same as for JFrame (in both cases there is shenanigans where actually what happens is that add actually calls getContentPane().add which can cause some unnecessary confusion). The main difference is that you can't pack an applet.