简体   繁体   中英

How to draw over a GLCanvas?

I wish to draw an HUD of sorts over a 3D OpenGL view, but it seems any drawing done in my panel will be overlooked, although it is done.

Here's some barebones code.

MyFrame;

public class MyFrame extends JFrame{
    private static final long serialVersionUID = 1L;
    public MyFrame(Labyrinth l){
        super();
        this.setTitle("My Frame");
        this.setSize(512, 384);
        this.setContentPane(new MyPanel());
        //this.setVisible(true);//If needed here.
    }
}

MyPanel;

public class MyPanel extends JPanel {
    private static final long serialVersionUID = 1L;
    public MyPanel(){
        super();
        this.setLayout(new BorderLayout());
        MyCanvas mc=new MyCanvas(l);
        mc.setFocusable(false);
        this.add(this.mc, BorderLayout.CENTER);
        //this.revalidate();//Doesn't seem needed in the instanciation.
    }
    public void paintComponent(Graphics g){
        super.paintComponent(g);
        this.mc.repaint();
        g.setColor(new Color(128,128,128));
        g.fillRect(0, 0, this.getWidth()/2,this.getHeight()/2); 
        //top-left quarter should be greyed away.
    }
}

MyCanvas;

public class MyCanvas extends GLCanvas{
    private static final long serialVersionUID = 1L;
    public MyCanvas(){
        super(new GLCapabilities(GLProfile.getDefault()));
    }
}

The painting takes place, but isn't shown in the view. I've tried overriding repaint(), paint(Graphics), paintComponent(Graphics) and update(). I've been said that painting over "heavyweight" components was complicated, and that I should either paint directly in the component or use another type. I obviously need the GLCanvas to show a 3D render, and at the same time it does not seem to provide tools to draw an overlay. Someone told me to simply do my drawing in the JFrame's glassPane however that seems rather overkill, and I've been told never to play around the glassPane so I'm not planning on doing that.

I've seen many topics on the paintings call order but I cannot establish which would be correct while overriding such or such method, and I don't even know if or which method I should override. Is there an obvious way I'd have missed to have my simple JPanel paintings shown over its GLCanvas component?

First of all, I really wouldn't recommend getting a HUD through those means. As I can only imagine this hurting performance a lot. Granted I have never tried mixing Java, OpenGL and AWT's Graphics like that.

Now instead of using holding those classes together with duct tape , consider using JLayeredPane .

JLayeredPane layeredPane = new JLayeredPane();

layeredPane.add(new MyCanvas());
layeredPane.add(new MyPanel());

frame.add(layeredPane);

Now the important part is that you must manually set the bounds of both components:

canvas.setBounds(x, y, width, height);
panel.setBounds(x, y, width, height);

If not you'll end up with the same problem as before:

The painting takes place, but isn't shown in the view

To demonstrate it working I created this small TestPanel class similar to your MyPanel .

public static class TestPanel extends JPanel {
    private Color color;

    public TestPanel(Color color) {
        this.color = color;
    }

    @Override
    public void paintComponent(Graphics g) {
        g.setColor(color);
        g.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
    }
}

Then creating two instances like this:

JPanel panel1 = new TestPanel(new Color(255, 0, 0));
panel1.setBounds(25, 25, 100, 100);

JPanel panel2 = new TestPanel(new Color(0, 0, 255));
panel2.setBounds(75, 75, 100, 100);

Then adding them to a JLayeredPane and adding that to a JFrame and we see this:

I found using the JFrame glass-panel to be a good solution, I use it to draw debugging text on top of 3D graphics, I haven't experienced any problems with it. Using the glass-panel method is more convenient than using a JLayeredPane because the resizing of the 3D panel will be handled for you. Note the 3D graphics must be drawn in a GLJPanel component or the layering won't work (as opposed to GLCanvas which is not a Swing component). The paintComponent(Graphics g) will be called at the same rate as the frame-rate of the GLJPanel. Note also, the glass-pane is hidden by default so setVisible(true) must be called on it.

import javax.swing.JFrame;
import com.jogamp.opengl.awt.GLJPanel;
// ...

public class ApplicationWindow extends JFrame {
  public ApplicationWindow(String title) {
    super(title);    
    GLCapabilities gl_profile = new GLCapabilities(GLProfile.getDefault());
    GLJPanel gl_canvas = new GLJPanel(gl_profile);
    // ... code here to draw the graphics (supply a GLEventListener to gl_canvas)

    setContentPane(gl_canvas);
    StatusTextOverlayPanel myGlassPane = new StatusTextOverlayPanel();
    setGlassPane(myGlassPane);
    myGlassPane.setVisible(true);
    setVisible(true);
  }

  class StatusTextOverlayPanel extends JComponent {
    @Override
    public void paintComponent(Graphics g) {
      super.paintComponent(g);
      Graphics2D g2d = (Graphics2D) g;
      g2d.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 14));
      g2d.setPaint(Color.BLACK);
      String statusText = String.format("C-elev: %.2f S-view %.2f D-view %.2f", 1459.0, 17.0, 2.574691);
      g2d.drawString(statusText, 10, 20);
    }
  }
}

Here is an example of what it could look like (You'll need additional code to draw the axis and the square shown)

带有叠加文本的Java 3D图形示例

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM