setOpaque(true/false); Java

13
在Java2D中,当您使用setOpaque时,我对true和false的含义有点困惑。
例如,我知道在Swing中Opaque意味着当绘制时,Swing不会绘制组件后面的内容。或者是相反的吗?哪个是正确的?
谢谢
3个回答

51
你的问题的简短回答是,“opaque”在英语中定义为完全不透明。因此,不透明的组件是指其绘制其整个矩形,并且每个像素对于任何程度都不具备半透明性。
然而,Swing组件的不透明性API是那些设计错误,因此经常被错误使用的API之一。
重要的是要理解的是,isOpaque是Swing系统与特定组件之间的契约。如果它返回true,则该组件保证以非半透明方式绘制其矩形区域的每个像素。这个API应该已经抽象化了,以迫使所有组件编写者考虑它。对于覆盖它并在其后面的组件(包括容器和祖先)来说,Swing的绘画系统使用isOpaque API来确定是否必须绘制给定组件覆盖的区域。如果组件对此API返回true,则Swing系统可以对绘画进行优化,直到调用特定组件的paint方法为止,不需要在该区域内绘制任何内容。
由于isOpaque的契约意义,API setOpaque不应存在,因为对于任何外部调用setOpaque实际上是不正确的,因为外部无法知道涉及的组件是否会(甚至是否可以)遵守该设置。相反,isOpaque应被每个具体组件覆盖以返回它是否实际上是不透明的,考虑其当前属性。
由于setOpaque API确实存在,许多组件已经错误地实现了它(可以理解),以驱动它们是否将“背景”绘制(例如JLabel和JPanel填充其背景颜色)。这样做的效果是给API用户留下印象,即setOpaque驱动是否应该绘制该背景,但实际上并非如此。此外,如果你想要给一个JLabel控件设置半透明背景,你需要设置一个带有alpha值的背景颜色,并且调用setOpaque(true)方法,但它实际上并不是完全不透明的,而是半透明的;它后面的组件仍然需要被绘制才能使组件正确显示。
这个问题在Java 6的新Nimbus外观中被大量暴露出来。有许多针对Nimbus的透明组件的错误报告(参见Stack Overflow问题Java Nimbus LAF with transparent text fields)。Nimbus开发团队的回应是:

这是Swing的原始设计问题,这个问题已经混淆了很多年。问题是setOpaque(false)在现有LAFs中具有隐藏背景的副作用,而这并不是它的真正意图。它的真正意图是表明组件可能有透明部分,Swing应该绘制其后面的父组件。

因此,总的来说,你不应该使用setOpaque方法。如果你确实要使用它,请记住有些外观和一些组件的组合可能会做出“惊奇”的事情。最后,实际上并没有正确答案。

虽然我来晚了,但感谢您解释isOpaque和alpha通道之间的关系。我一直很困惑,因为它们似乎涵盖了相同的领域——知道这是因为isOpaque有点傻瓜化,这很有帮助。 :) - KathyA.
应该将其更改为类似于 setPaintBackground(boolean) 的形式......或者将参数更改为从0到1的浮点因子,以设置不透明度的程度......0表示透明,1表示完全不透明。 - WesternGun
@FaithReaper:该API必须被弃用并用一些经过适当规范和“受保护”的东西来替换。 - Lawrence Dol

1

2
当为真时,其后面的组件不会显示。当为假时,它会显示。我们不需要查看Javadoc,只需要英语词典就足够了 :) :) - raj
是的,那就是我想的,但是在阅读了很多东西后,我感到有些困惑。 - anon235370

0

我认为还需要添加以下内容:

opaque这个术语在Java 2D和Swing中有不同的含义。

在Java 2D中,不透明度是一种渲染概念。它是alpha值和Composite模式的组合。它是正在绘制的像素颜色应与已经存在的像素值混合的程度。例如,我们在现有的椭圆形上绘制一个半透明矩形。因此,椭圆形部分可见。这个概念经常被比作光线穿过玻璃或水。

在Swing中,不透明组件会绘制其矩形边界内的每个像素。非不透明组件只绘制其部分像素或根本不绘制,从而允许其下方的像素显示出来。设置不透明属性是为了提高效率;Swing不必绘制不透明组件后面的区域。

来源:Java文档和《富客户端编程》

package com.zetcode;
import java.awt.AlphaComposite; import java.awt.Color; import java.awt.EventQueue; import java.awt.Graphics; import java.awt.Graphics2D; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import static javax.swing.SwingConstants.CENTER; import net.miginfocom.swing.MigLayout;
class DrawingPanel extends JPanel {
@Override public void paintComponent(Graphics g) { super.paintComponent(g);
doDrawing(g); }
private void doDrawing(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.green); g2d.fillOval(20, 20, 100, 100); g2d.setColor(Color.blue); g2d.setComposite(AlphaComposite.getInstance( AlphaComposite.SRC_OVER, 0.1f)); g2d.fillRect(0, 0, 150, 150); } }
class MyLabel extends JLabel {
public MyLabel(String text) { super(text, null, CENTER); }
@Override public boolean isOpaque() { return true; } } public class OpaqueEx2 extends JFrame {
public OpaqueEx2() { // 初始化用户界面 initUI(); }
private void initUI() {
JLabel lbl1 = new JLabel("Java 2D 不透明度"); JLabel lbl2 = new JLabel("Swing 不透明");
DrawingPanel dpanel = new DrawingPanel();
MyLabel mylbl = new MyLabel("isOpaque()"); mylbl.setBackground(Color.decode("#A9A9A9"));
createLayout(lbl1, lbl2, dpanel, mylbl);
setTitle("不透明"); setLocationRelativeTo(null); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); }
private void createLayout(JComponent... arg) {
JPanel pnl = new JPanel(new MigLayout("ins 10"));
pnl.add(arg[0], "w 150"); pnl.add(arg[1], "w 150, wrap"); pnl.add(arg[2], "w 150, h 150"); pnl.add(arg[3], "w 150, h 150");
add(pnl); pack(); }
public static void main(String[] args) { //使用事件队列来确保应用程序的线程安全 EventQueue.invokeLater(new Runnable() { @Override public void run() { OpaqueEx2 ex = new OpaqueEx2(); ex.setVisible(true); } }); } }
在代码示例中,我们有两个组件。左侧的组件是一个面板,它使用AlphaComposite来绘制一个高度半透明的矩形覆盖在椭圆上。右侧的组件是一个标签。在大多数外观中,标签是非不透明的。我们重写了标签的isOpaque()方法来设置一个灰色背景。

Opaque explained


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接