Java 如何在画布上画画?

Java 如何在画布上画画?,java,swing,opengl,jpanel,awt,Java,Swing,Opengl,Jpanel,Awt,我希望在3D OpenGL视图上绘制某种HUD,但似乎在我的面板中绘制的任何图形都会被忽略,尽管已经完成了 这里有一些简单的代码 我的框架 public class MyFrame extends JFrame{ private static final long serialVersionUID = 1L; public MyFrame(Labyrinth l){ super(); this.setTitle("My Frame");

我希望在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(图形)、paintComponent(图形)和update()。有人说,在“重量级”组件上绘制是复杂的,我应该直接在组件中绘制,或者使用另一种类型。我显然需要GLCanvas来显示3D渲染,同时它似乎没有提供绘制覆盖的工具。有人告诉我只需在JFrame的玻璃窗格中画画,但这似乎有点过分,而且我被告知永远不要在玻璃窗格中玩耍,所以我不打算这样做


我看过很多关于绘画调用顺序的主题,但我无法确定在重写某个或某个方法时哪个是正确的,我甚至不知道是否应该重写,或者应该重写哪个方法。有没有一种明显的方式我会错过在GLCanvas组件上展示我的简单JPanel绘画?

首先,我真的不建议通过这种方式获得HUD。因为我只能想象这种令人痛苦的表演。当然,我从未尝试过像那样混合Java、OpenGL和AWT的图形

现在不要使用管道带来保存这些类,考虑使用<代码> JLAIERDEPANE < /C> > < /P>

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
中,我们可以看到:


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

import javax.swing.JFrame;
导入com.jogamp.opengl.awt.GLJPanel;
// ...
公共类应用程序窗口扩展JFrame{
公共应用程序窗口(字符串标题){
超级(标题);
GLCapabilities gl_profile=新的GLCapabilities(GLProfile.getDefault());
GLJPanel gl_canvas=新的GLJPanel(gl_配置文件);
//…在此处编写代码以绘制图形(为gl_画布提供一个GLEventListener)
setContentPane(gl_画布);
StatusTextOverlyPanel myGlassPane=新的StatusTextOverlyPanel();
setGlassPane(myGlassPane);
myGlassPane.setVisible(true);
setVisible(真);
}
类StatusTextOverlyPanel扩展JComponent{
@凌驾
公共组件(图形g){
超级组件(g);
Graphics2D g2d=(Graphics2D)g;
g2d.setFont(新字体(Font.MONOSPACED,Font.PLAIN,14));
g2d.setPaint(颜色:黑色);
String statusText=String.format(“C-elev:%.2f S-view%.2f D-view%.2f”,1459.0,17.0,2.574691);
g2d.抽绳(statusText,10,20);
}
}
}
下面是一个它可能看起来像什么的示例(您需要额外的代码来绘制所示的轴和正方形)


是否可以沿分层窗格调整子面板的大小?我想当尺寸变化时,重写LP的repaint方法为它的组件设置标志是可行的。不管怎样,这就是我想要的,谢谢你。不过我还有一个问题要问你,这不会成为另一个话题;我怎样才能看穿顶部JPanel的非涂漆部分?现在,当我试图在画布上只绘制面板左上角的四分之一时,我得到了类似的结果。这很好,但还不够。(编辑:使用setOpaque(false);在面板实例上)调整大小可以使用
ComponentListener
并在
componentResized
中调整子面板的大小。对于透明度问题,如果您覆盖了
paintComponent
,并且没有调用
super.paintComponent
,并且没有用颜色清除面板,那么这个问题就不应该存在了。我已经覆盖了所有形式的paint方法,包括使用和不使用super调用,但都没有效果。我已经切换到GLJPanel而不是GLCanvas,它立即起作用了,尽管我不知道为什么我不想质疑它。componentListener thingy可以工作,但会有延迟(组件大小错误的窗口的闪烁),因为在调整大小时,绘制是在处理事件之前完成的,我只需像往常一样,在检测到调整大小时设置自己的标志。谢谢你的回答。同样重要的是要注意,我的截图中显示的灰色默认背景色来自包含画布的面板,而不是我绘制的那个。改变画布面板的背景也改变了它;我画的面板确实是透明的,但是下面的面板无法更新画布上完全隐藏在透明面板后面的部分。