【问题标题】:How to draw over a GLCanvas?如何在 GLCanvas 上绘图?
【发布时间】:2017-08-07 01:51:49
【问题描述】:

我希望在 3D OpenGL 视图上绘制各种 HUD,但似乎在我的面板中完成的任何绘制都会被忽略,尽管它已完成。

这是一些准系统代码。

我的框架;

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.
    }
}

我的面板;

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.
    }
}

我的画布;

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

绘画发生了,但没有显示在视图中。我尝试过覆盖 repaint()、paint(Graphics)、paintComponent(Graphics) 和 update()。有人说在“重量级”组件上绘画很复杂,我应该直接在组件中绘画或使用其他类型。我显然需要 GLCanvas 来显示 3D 渲染,同时它似乎没有提供绘制叠加层的工具。有人告诉我只需在 JFrame 的 glassPane 中进行绘图,但这似乎有点过头了,而且我被告知永远不要在 glassPane 周围玩耍,所以我不打算这样做。

我已经看到很多关于绘画调用顺序的主题,但我无法确定在覆盖这样或那样的方法时哪个是正确的,我什至不知道我是否应该或者应该覆盖哪个方法。是否有一种明显的方式让我错过了在其 GLCanvas 组件上显示我的简单 JPanel 绘画?

【问题讨论】:

    标签: java swing opengl jpanel awt


    【解决方案1】:

    首先,我真的不建议通过这些方式获得 HUD。我只能想象这种伤害性的表现。当然,我从来没有尝试过像这样混合 Java、OpenGL 和 AWT 的图形。

    现在不要使用用胶带将这些类固定在一起,考虑使用JLayeredPane

    JLayeredPane layeredPane = new JLayeredPane();
    
    layeredPane.add(new MyCanvas());
    layeredPane.add(new MyPanel());
    
    frame.add(layeredPane);
    

    现在重要的部分是您必须手动设置两个组件的边界:

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

    否则,您最终会遇到与以前相同的问题:

    绘画发生,但未显示在视图中

    为了演示它的工作原理,我创建了这个类似于您的 MyPanel 的小型 TestPanel 类。

    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);
        }
    }
    

    然后像这样创建两个实例:

    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);
    

    然后将它们添加到JLayeredPane 并将其添加到JFrame,我们会看到:

    【讨论】:

    • 是否可以让子面板沿 layeredPane 调整大小?我猜想当尺寸改变可以工作时,覆盖 LP 的重绘方法来为其组件设置标志。无论如何,这就是我想要的,谢谢。
    • 不过,我还有一个问题要问你,它不会成为另一个话题;我怎样才能看穿顶部 JPanel 的未上漆部分?现在,当我尝试仅在 GLCanvas 上方绘制面板的左上角四分之一时,我得到类似 http://imgur.com/a/7m65O 的信息。这很好,但还不够。 (编辑:它与 setOpaque(false); 在面板实例化上)
    • 要调整大小,您可以使用ComponentListener 并调整componentResized 中子面板的大小。对于透明度问题,鉴于您覆盖 paintComponent 并且不调用 super.paintComponent 并且不使用颜色清除面板,那么该问题不应该存在。
    • 我已经以任何和所有形式覆盖了所有绘制方法,包括有和没有超级调用,但无济于事。我已经切换到 GLJPanel 而不是 GLCanvas 并且它立即起作用,虽然我不知道为什么我不打算质疑它。 componentListener 可以工作,但是有延迟(带有错误大小的组件的窗口闪烁),因为在调整大小时,绘画是在处理事件之前完成的,我会像往常一样简单地做,并在调整大小时设置我自己的标志被检测到。谢谢你的回答。
    • 另外需要注意的是,我捕获的灰色默认背景颜色来自包含画布的面板,而不是我绘制的面板。改变画布面板的背景也改变了它;我绘制的面板确实是透明的,但下面的面板无法更新完全隐藏在透明面板后面的画布部分。
    【解决方案2】:

    我发现使用JFrame glass-panel 是一个很好的解决方案,我用它在 3D 图形上绘制调试文本,我没有遇到任何问题。使用玻璃面板方法比使用JLayeredPane 更方便,因为将为您处理 3D 面板的大小调整。请注意,3D 图形必须在GLJPanel 组件中绘制,否则分层将不起作用(与不是 Swing 组件的 GLCanvas 不同)。 paintComponent(Graphics g) 将以与 GLJPanel 的帧速率相同的速率被调用。另请注意,默认情况下,玻璃窗格是隐藏的,因此必须在其上调用 setVisible(true)

    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);
        }
      }
    }
    

    这是它的外观示例(您需要额外的代码来绘制轴和显示的正方形)

    【讨论】:

      猜你喜欢
      • 2017-06-29
      • 1970-01-01
      • 2010-10-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-21
      • 2018-10-16
      • 1970-01-01
      相关资源
      最近更新 更多