【问题标题】:setOpaque() in javajava中的setOpaque()
【发布时间】:2011-05-04 15:12:45
【问题描述】:

谁能解释为什么 Nimbius 对待 setOpaque() 的方式与其他 java LaF 不同。它破坏了我的代码,因为通常透明的组件不再是。

编辑:问题似乎只涉及 JTextAreas(这是我需要的)或类似组件。

EDIT EDIT:这是实际应用程序的屏幕。在应用垃圾神解决方案时,背景仍然没有显示出来。

EDIT EDIT EDIT:
我尝试了trashgod 的建议来覆盖paint()。我为此辛勤工作了几个小时,但无法让它工作。我能够让背景显示出来,但 JinternalFrame 无法移动、调整大小和选择其文本。调用 super.paint(g) 未能解决解决方案。有没有一种我可能会错过的简单方法来做到这一点?
我对此采取了新的方法。 JInternalFrame 内部是一个 JLayeredPane。
第 0 层 - JLabel
第 1 层 - JTextArea

当 JInternalFrame 被移动或调整大小时:

  1. 使自己不可见
  2. 截取它在容器中所在位置的屏幕截图
  3. 用它拍摄的图像绘制 JLabel
  4. 让自己再次可见。

因为我根本无法让 JInternalFrame 透明。我模拟了它的透明度。唯一的问题是,与此相关的开销很大。有什么想法吗?

package newpackage; import java.awt.Color; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; import java.awt.Graphics2D; import java.awt.Rectangle; import java.awt.image.BufferedImage; import javax.swing.ImageIcon; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JInternalFrame; import javax.swing.JLayeredPane; import javax.swing.JPanel; import javax.swing.UIManager; /** * Example of how to create a transparent internal frame. * @author dvargo */ public class TransparentInternalFrame extends JInternalFrame { JLayeredPane container; /** * Defualt constructor to set the frame up * @param container The container for the frame * @param opacity The opacity of the frame */ public TransparentInternalFrame(JLayeredPane container, int opacity) { super("", true, true, true, true); this.container = container; initComponents(); setSize(200, 200); putClientProperty("JInternalFrame.isPalette", Boolean.TRUE); scrollPane.setBackground(new Color(0, 0, 0, opacity)); scrollPane.getViewport().setBackground(new Color(0, 0, 0, opacity)); textArea.setBackground(new Color(0, 0, 0, opacity)); setBG(); } /** * Builds the GUI */ private void initComponents() { layeredPane = new javax.swing.JLayeredPane(); imageLabel = new javax.swing.JLabel(); scrollPane = new javax.swing.JScrollPane(); textArea = new javax.swing.JTextArea(); imageLabel.setBounds(0, 0, 360, 260); layeredPane.add(imageLabel, javax.swing.JLayeredPane.DEFAULT_LAYER); scrollPane.setBorder(null); textArea.setColumns(20); textArea.setRows(5); textArea.addKeyListener(new java.awt.event.KeyAdapter() { public void keyPressed(java.awt.event.KeyEvent evt) { textAreaKeyPressed(evt); } public void keyReleased(java.awt.event.KeyEvent evt) { textAreaKeyReleased(evt); } public void keyTyped(java.awt.event.KeyEvent evt) { textAreaKeyTyped(evt); } }); addComponentListener(new java.awt.event.ComponentAdapter() { public void componentMoved(java.awt.event.ComponentEvent evt) { frameMoved(); } public void componentResized(java.awt.event.ComponentEvent evt) { frameResized(); } }); scrollPane.setViewportView(textArea); scrollPane.setBounds(0, 0, 360, 260); layeredPane.add(scrollPane, javax.swing.JLayeredPane.PALETTE_LAYER); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addComponent(layeredPane, javax.swing.GroupLayout.PREFERRED_SIZE, 362, javax.swing.GroupLayout.PREFERRED_SIZE)); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addComponent(layeredPane, javax.swing.GroupLayout.PREFERRED_SIZE, 261, javax.swing.GroupLayout.PREFERRED_SIZE)); } /** * The text will be blurred with out this * @param evt */ private void textAreaKeyTyped(java.awt.event.KeyEvent evt) { repaintAll(); } /** * The text will be blurred with out this * @param evt */ private void textAreaKeyPressed(java.awt.event.KeyEvent evt) { repaintAll(); } /** * The text will be blurred with out this * @param evt */ private void textAreaKeyReleased(java.awt.event.KeyEvent evt) { repaintAll(); } /** * Capture whats behind the frame and paint it to the image label */ private void setBG() { setVisible(false); Rectangle location = new Rectangle(this.getX() + container.getX(), this.getY() + container.getY(), (int) this.getSize().getWidth() + 8 + ((javax.swing.plaf.basic.BasicInternalFrameUI) getUI()).getNorthPane().getWidth(), (int) this.getSize().getHeight() + ((javax.swing.plaf.basic.BasicInternalFrameUI) getUI()).getNorthPane().getHeight() + 4); ImageIcon newIcon = new ImageIcon(createImage((JComponent) container, location)); setVisible(true); imageLabel.setIcon(newIcon); repaint(); } /** * Only need to update the image label if the frame is moved or resized */ private void frameResized() { setBG(); textArea.repaint(); } /** * Only need to update the image label if the frame is moved or resized */ private void frameMoved() { setBG(); for(Component x : container.getComponents()) { //see if its a jinternalframe if(x.getClass().getName().equals(this.getClass().getName())) { //cast it TransparentInternalFrame temp = (TransparentInternalFrame)x; //make sure its not the same one as this if(x.getBounds().equals(this.getBounds())) { return; } //if they intersect if(x.getBounds().intersects(this.getBounds())) { this.setVisible(false); temp.setBG(); this.setVisible(true); } } } textArea.repaint(); } private void repaintAll() { textArea.repaint(); imageLabel.repaint(); layeredPane.repaint(); scrollPane.repaint(); scrollPane.getViewport().repaint(); textArea.repaint(); repaint(); } /** * Create a BufferedImage for Swing components. * All or part of the component can be captured to an image. * * @param component Swing component to create image from * @param region The region of the component to be captured to an image * @return image the image for the given region */ public static BufferedImage createImage(JComponent component, Rectangle region) { // Make sure the component has a size and has been layed out. // (necessary check for components not added to a realized frame) if (!component.isDisplayable()) { Dimension d = component.getSize(); if (d.width == 0 || d.height == 0) { d = component.getPreferredSize(); component.setSize(d); } layoutComponent(component); } BufferedImage image = new BufferedImage(region.width, region.height, BufferedImage.TYPE_INT_RGB); Graphics2D g2d = image.createGraphics(); // Paint a background for non-opaque components, // otherwise the background will be black if (!component.isOpaque()) { g2d.setColor(component.getBackground()); g2d.fillRect(region.x, region.y, region.width, region.height); } g2d.translate(-region.x, -region.y); component.paint(g2d); g2d.dispose(); return image; } public static void layoutComponent(Component component) { synchronized (component.getTreeLock()) { component.doLayout(); if (component instanceof Container) { for (Component child : ((Container) component).getComponents()) { layoutComponent(child); } } } } private javax.swing.JLabel imageLabel; private javax.swing.JScrollPane scrollPane; private javax.swing.JLayeredPane layeredPane; private javax.swing.JTextArea textArea; public static void main(String args[]) { try { UIManager.setLookAndFeel( "com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel"); } catch (Exception e) { e.printStackTrace(); } JFrame container = new JFrame(); container.setSize(800, 800); JLayeredPane layerPanel = new JLayeredPane(); layerPanel.setSize(800, 800); container.getContentPane().add(layerPanel); layerPanel.setVisible(true); JPanel colorPanel = new JPanel(); colorPanel.setSize(800,800); colorPanel.setBackground(Color.red); layerPanel.add(colorPanel); layerPanel.setLayer(colorPanel, JLayeredPane.DEFAULT_LAYER); TransparentInternalFrame frameA = new TransparentInternalFrame(layerPanel,0); frameA.setVisible(true); layerPanel.add(frameA); layerPanel.setLayer(frameA, 1); frameA.setSize(282,282); TransparentInternalFrame frameB = new TransparentInternalFrame(layerPanel, 0); frameB.setVisible(true); layerPanel.add(frameB); layerPanel.add(frameB,1); frameB.setLocation(300, 300); frameB.setSize(282,282); container.repaint(); container.setVisible(true); } }

【问题讨论】:

  • 重新格式化的代码;如果不正确,请恢复。

标签: java swing look-and-feel nimbus


【解决方案1】:

您可以从文章Painting in AWT and Swing 中的Opacity 部分获得一些见解。特别是,设置 opaque 属性并不意味着“使组件的背景透明”。证明问题的sscce 也可能有成果。

附录:简化您的示例,看起来文本区域本身可以透明,但 Nimbus defaults 正在影响区域的边界。您可以尝试相应地更改它们。

关于您的代码的几点说明:

  • 始终在事件调度线程上构建 GUI。
  • 不要从其他线程中提取。
  • 不要吞下异常。

附录:查看对create() 的更改。

附录:您可能也想查看isPalette 属性

jif.putClientProperty("JInternalFrame.isPalette", Boolean.TRUE);

import java.awt.Color;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import javax.swing.JInternalFrame;
import java.awt.Font;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.UIManager;

public class TransparentTextArea extends JTextArea {

    int alpha;

    public TransparentTextArea(int alpha) {
        super(4, 16);
        this.alpha = alpha;
        this.setBackground(new Color(0, 0, 0, alpha));
        this.setFont(new Font("Serif", Font.ITALIC, 24));
        this.setEditable(false);
        this.setText("Twas brillig and the slithy toves,\n"
            + "Did gyre and gimble in the wabe;\n"
            + "All mimsy were the borogoves,\n"
            + "And the mome raths outgrabe.");
    }

    private static void create() {
        JFrame f = new JFrame();
        f.setLayout(new FlowLayout());
        f.getContentPane().setBackground(new Color(0xffffc0));
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JInternalFrame jif = new JInternalFrame();
        JPanel panel = new JPanel();
        panel.setBackground(new Color(0xffffc0));
        panel.add(new TransparentTextArea(0));
        jif.add(panel);
        jif.setVisible(true);

        f.add(jif);
        f.pack();
        f.setVisible(true);
    }

    public static void main(String[] args) {

        try {
            UIManager.setLookAndFeel(
                "com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
        } catch (Exception e) {
            e.printStackTrace();
        }

        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                create();
            }
        });
    }
}

【讨论】:

  • 谢谢,这非常有用。我尝试不依赖 setOpaque() 使组件透明,而是使组件的背景具有 0 alpha 值。我添加了一个 sscce。
  • 感谢简化代码。这很好用。对于我的特定问题,TransparentTextArea 将包含在 JInternalFrame 中。我尝试将透明文本区域添加到 JInternalFrame,将背景设置为具有 0 alpha 值和/或 setOpaque(false) 的颜色,但在这种情况下,背景不会显示出来。关于修改代码以使其与 JInternalFrame 一起工作的任何建议?再次感谢您的帮助。
  • @user489041:当我将面板添加到create() 的内部框架时,它似乎可以工作。抱歉延迟回复。
  • @trashgod:感谢您的回复。在您更新的代码中,JPanel 被添加到 JInternalFrame。然后将 JPanel 的背景设置为与 JFrame 相同的颜色。但是,显示出来的不是 JFrame 的背景,而是 JPanel。我需要 JInternalFrame 完全透明,只显示文本和 JFrame 的背景。我尝试更改 JPanel 的颜色,但没有影响。我仍然无法显示 JInternalFrame 后面的图像。我添加了一张我的实际应用程序的图片来显示这个问题。有什么想法吗?
  • @user489041:啊,我认为只是 JTextArea 需要透明。要使JInternalFrame 透明,您可以继承InternalFrameUI 并覆盖paint()。
【解决方案2】:

正如here 解释的那样,setOpaque 并没有像你想象的那样做,而且在 Nimbus 中失败是显而易见的。引用 alpha 颜色的另一个答案是完成您想要的正确方法。

【讨论】:

  • 当我将 JInternalFrame 的背景 alpha 颜色设置为 0 时,它不会让 JFrames 背景显示出来。对上面的 sscce 代码有什么建议吗?
  • 在这里试试代码:webcache.googleusercontent.com/…
猜你喜欢
  • 1970-01-01
  • 2016-06-23
  • 1970-01-01
  • 2015-03-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多