首先,要摆脱它,我绝对需要在Swing应用程序中使用重量级的AWT组件。我需要它们都具有的功能。
任务很简单-渲染一个重量级的AWT画布(或任何其他元素),直接在其上渲染OpenGL场景,然后在其上方为用户界面显示Swing按钮。
我的问题是,它只能中途工作。我似乎对Z排序没有问题。我正在使用jLayeredPanes,并且可以在各层之间移动Canvas,并且可以正常工作,在其他元素的上方或下方弹出。
问题在于透明度。关键是,Swing元素具有Opaque参数,并且将其设置为false(非不透明)时-它基本上应该是透明的,并且您应该看到它下面的下一个元素。但是,就我而言,AWT画布将被忽略,而您只能看到下一个基础SWING元素。
这里有几个屏幕截图。它们来自我的一个独立测试项目。画布被拉伸到框架的大小,并且在左上角有一个JLayeredPane虚拟元素,它是菜单的简化版本。
在first屏幕截图上,JLayeredPane的“不透明”设置设置为true,您可以看到其背景属性设置为“蓝色”。
在second屏幕截图上,所有内容都完全相同,但是Opaque设置为false。而不显示画布上的内容,而是在空的灰色jFrame背景中绘制内容。
最后,在第三屏幕截图中,我将Canvas放入jPanel中,而不是单独保留它。如您所见,通过透明的jLayeredPane可以看到面板的橙色,但是Canvas仍然被隐藏了。
这是框架布局的代码。我现在不会发布渲染/上下文代码
frame = new JFrame("AWT test");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.setPreferredSize(new Dimension(width, height));
canvas = new Canvas();
canvas.setSize(width,height);
//this part exists only in the third example
JPanel p = new JPanel();
p.setSize(width,height);
p.setBackground(Color.orange);
p.add(canvas);
// third example end
JLayeredPane pane = new JLayeredPane();
JLayeredPane paneMenu = new JLayeredPane();
JButton button = new JButton();
button.setSize(20,20);
paneMenu.setSize(200,200);
paneMenu.add(button, new Integer(1));
paneMenu.setBackground(Color.BLUE);
paneMenu.setOpaque(false); //True for the first example
pane.add(p, new Integer(1)); // canvas for the first two examples
pane.add(paneMenu, new Integer(2));
pane.setOpaque(false);
frame.add(pane);
frame.pack();
frame.setVisible(true);
frame.transferFocus();
任何人都可以向我解释发生了什么以及如何做我需要做的事情。我将再次重复-我必须使用重量级组件作为渲染目标。我知道像JOGL的GLPanel这样的解决方案,它是与Swing兼容的轻型组件。但是我尝试了该方法,并且性能确实很慢,因为它不是直接将其呈现为上下文目标,而是从内存中读取FrameBuffer并将其翻转,然后将其绘制为BufferedImage。该路径不适合我将要在其上运行的嵌入式系统的有限资源。
c0der说:请发布最小的可复制示例Errrrm ....不是吗?在这里,您可以根据需要以完整的Java类形式使用它,但是我确实从字面上更改了一些常量变量。
import javax.swing.*;
import java.awt.*;
public class Main
{
public static void main(String[] args)
{
JFrame frame = new JFrame("AWT test");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.setPreferredSize(new Dimension(500, 500));
Canvas canvas = new Canvas();
canvas.setSize(500,500);
canvas.setBackground(Color.RED);
//this part exists only in the third example
JPanel p = new JPanel();
p.setSize(500,500);
p.setBackground(Color.orange);
p.add(canvas);
// third example end
JLayeredPane pane = new JLayeredPane();
JLayeredPane paneMenu = new JLayeredPane();
JButton button = new JButton();
button.setSize(20,20);
paneMenu.setSize(200,200);
paneMenu.add(button, new Integer(1));
paneMenu.setBackground(Color.BLUE);
paneMenu.setOpaque(false); //True for the first example
pane.add(p, new Integer(1)); // canvas for the first two examples
pane.add(paneMenu, new Integer(2));
pane.setOpaque(false);
frame.add(pane);
frame.pack();
frame.setVisible(true);
frame.transferFocus();
}
}
小更新:
我最初怀疑是因为Swing元素将所有图形委托给底层的重量级元素(在我的情况下为JFrame),所以发生的情况是,框架为其自身生成了一个frameBuffer,然后显示在Canvas的顶部。画布本身在这一代中没有得到处理,因此框架“覆盖”了画布。
似乎并非如此。我尝试使JFrame保持未装饰状态,所有面板均不透明,并显示图片。结果-画布仍处于“剪切”状态,通过该孔您可以看到基础的IDE菜单。这使我认为,在绘制过程中的某个位置,画布本身会检测到它被另一个元素遮盖了,并且不需要绘制该区域。因此,它自身会“优化”,并且不会更新这些像素。
也许我错了。但是,这是另一个屏幕截图。这是与以前相同的示例,但是我取出了3d渲染,只是试图在背景设置为红色的情况下显示Canvas。
再次,请回答我自己的问题。
原来我需要做
setComponentCutoutShape(paneMenu,new Rectangle());
对于位于按钮下方的菜单窗格。从本质上讲,这告诉Java不要从重量级基础组件中删除该元素。