13

在 Java2D 中,当您使用 setOpaque 时,我对 true 和 false 的作用有点困惑。

例如,我知道在 Swing 中不透明意味着在绘制 Swing 时不会绘制组件后面的内容。或者这是倒退?哪一个?

谢谢

4

3 回答 3

51

对您的问题的简短回答是,“不透明”在英语中被定义为完全不透明。因此,不透明组件是绘制其整个矩形的组件,并且每个像素在任何程度上都不是半透明的。

然而,Swing 组件 opacity API 是那些设计错误的 API 之一,因此经常被误用。

重要的是要理解这isOpaque是Swing 系统和特定组件之间的合同。如果它返回 true,则组件保证不透明地绘制其矩形区域的每个像素。这个 API应该是抽象的,以强制所有组件编写者考虑它。Swing 的绘制系统使用该isOpaqueAPI 来确定是否必须为给​​定组件所覆盖的区域绘制与它重叠的组件和在它后面的组件,包括组件的容器和祖先。如果组件向该 API 返回 true,则 Swing 系统可能会优化绘制,以便在调用特定组件的绘制方法之前不绘制该区域的任何内容。

由于 的合同含义isOpaque,APIsetOpaque 不应该存在,因为调用任何外部的东西实际上是不正确的,setOpaque因为反过来,外部的东西不知道有问题的组件是否会(甚至可以)尊重它。相反, isOpaque 应该被每个具体组件覆盖,以返回它是否实际上是不透明的,事实上,给定其当前属性。

因为setOpaqueAPI确实存在,所以许多组件错误地实现了它(很容易理解)来决定它们是否会绘制它们的“背景”(例如 JLabel 和 JPanel 填充它们的背景颜色)。这样做的效果是让 API 的用户产生一种印象,让他们认为这setOpaque决定了该背景是否应该绘制,但事实并非如此。

此外,例如,如果您希望绘制具有半透明背景的 JLabel,则需要设置具有 alpha 值的背景颜色,然后执行setOpaque(true),但它实际上不是不透明的 - 它是半透明的;它后面的组件仍然需要绘制才能使组件正确呈现。

Java 6 的新 Nimbus Look & Feel 显着暴露了这个问题。有许多关于针对 Nimbus 提交的透明组件的错误报告(请参阅堆栈溢出问题Java Nimbus LAF with transparent text fields)。Nimbus 开发团队的回应是这样的:

这是 Swing 的原始设计中的一个问题,并且多年来一直令人困惑。问题是 setOpaque(false) 在 [existing] LAF 中产生了副作用,即隐藏背景,而这并不是它 [意味着] 的真正用途。[意思是]说组件可能有透明部分,[Swing]应该在它后面绘制父组件。

所以,总而言之,你不应该使用setOpaque. 如果您确实使用它,请记住某些外观和某些组件的组合可能会做“令人惊讶”的事情。而且,最终,实际上并没有正确的答案。

于 2010-03-16T05:55:49.947 回答
1

javadoc说:如果为 true,则组件绘制其边界内的每个像素。否则,组件可能不会绘制其部分或全部像素,从而允许底层像素显示出来。

也试试这个示例程序...... http://www.java2s.com/Code/JavaAPI/javax.swing/JPanelsetOpaquebooleanisOpaque.htm

于 2010-03-16T03:46:10.333 回答
0

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

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

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

在 Swing 中,不透明组件在其矩形边界内绘制每个像素。非透明组件仅绘制其像素的子集或根本不绘制,从而允许其下方的像素显示出来。opaque 属性是出于效率原因而设置的;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 opacity");
        JLabel lbl2 = new JLabel("Swing opaque");

        DrawingPanel dpanel = new DrawingPanel();

        MyLabel mylbl = new MyLabel("isOpaque()");
        mylbl.setBackground(Color.decode("#A9A9A9"));

        createLayout(lbl1, lbl2, dpanel, mylbl);

        setTitle("Opaque");
        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()方法来设置灰色背景。

不透明的解释

于 2015-03-07T10:32:11.783 回答