添加透明度后,为什么透明JButton会显示框架图像?

时间:2019-06-26 15:47:51

标签: java swing jbutton transparency

我正在为Java应用程序开发GUI,并且想要背景图像。问题是我有一种填充有按钮的“抽屉”,当选中按钮时,该按钮以红色突出显示。

我使用方法buttonName.setBackground(new Color(255,102,102,200));同时设置高亮按钮和透明度。问题是,尽管该方法有效并且透明了按钮,但是透明显示按钮后面框架的随机部分,出现在标题,另一个按钮,按钮所在的JScrollPane的滚动条上,等等。该按钮仍然会显示,并且该按钮可以工作,但是背景会显示其他按钮或框架部分的文字。

此外,我意识到,如果我单击一个按钮并将鼠标多次移到所选按钮上,则透明度开始累积,直至变成纯色。

package buttonsbug;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import javax.imageio.ImageIO;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;

/**
 *
 * @author F&H
 */
public class ButtonsBug extends JFrame implements ActionListener {

    private ArrayList<JButton> botones;
    private JLabel panelPrin, panelNav, panelUser, panelImgUser, nombre, puesto;
    private JButton logout, planDis, consuEmpleados, funConsultarPiezas, btnCalidad, compraMat, soySuper, histProy, crearProyecto, clientes, adminConsProye;
    private JPanel buttonScroll;
    private JScrollPane navScroll;
    private BufferedImage img;
    private Dimension screenSize;

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    new ButtonsBug().setVisible(true);
                } catch (Exception e) {
                    System.out.println(e.getMessage());
                    System.exit(0);
                }
            }
        });
    }

    public ButtonsBug() {
        botones = new ArrayList<>();

        screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
        setSize(ajustarDimensiones(1400), ajustarDimensiones(800));

        setContentPane(panelPrin = new JLabel());
        panelPrin.setSize(ajustarDimensiones(1400), ajustarDimensiones(800));
        try {
            img = ImageIO.read(new File("src/tw3.png"));
            Image dimg1 = img.getScaledInstance(panelPrin.getWidth(), panelPrin.getHeight(), Image.SCALE_SMOOTH);
            ImageIcon imageIcon = new ImageIcon(dimg1);
            panelPrin.setIcon(imageIcon);
        } catch (IOException z) {
            System.out.println(z.getMessage());
            JOptionPane.showMessageDialog(this, "¡Error en la lectura de imagen!", "Error", JOptionPane.ERROR_MESSAGE);
        }

        panelPrin.setBackground(java.awt.Color.white);
        panelPrin.add(panelNav = new JLabel());
//        panelPrin.setOpaque(true);

//        panelNav.setOpaque(true);
        panelNav.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
//        panelNav.setBackground(new Color(0, 0, 0, 150));
        panelNav.setBounds(0, 0, ajustarDimensiones(305), ajustarDimensiones(771));
        panelNav.add(panelUser = new JLabel());
        panelNav.add(logout = new JButton());
        logout.setContentAreaFilled(false);
//        logout.setOpaque(true);

//        panelUser.setOpaque(true);
        panelUser.setBounds(ajustarDimensiones(1), ajustarDimensiones(1), ajustarDimensiones(303), ajustarDimensiones(88));
        panelUser.add(panelImgUser = new JLabel());
        panelUser.add(nombre = new JLabel());
        panelUser.add(puesto = new JLabel());
        nombre.setText("Wil Fonseca");
        puesto.setText("Production manager");

        nombre.setBounds(ajustarDimensiones(55), ajustarDimensiones(25), ajustarDimensiones(245), ajustarDimensiones(20));
        puesto.setBounds(ajustarDimensiones(55), ajustarDimensiones(45), ajustarDimensiones(245), ajustarDimensiones(20));
        nombre.setFont(new java.awt.Font("Arial", 1, ajustarDimensiones(14)));
        puesto.setFont(new java.awt.Font("Arial", 1, ajustarDimensiones(12)));
        nombre.setForeground(Color.white);
        puesto.setForeground(Color.white);

        logout.setText("Logout");
        logout.setFont(new java.awt.Font("Arial", 1, ajustarDimensiones(34)));
        logout.setBounds(ajustarDimensiones(1), ajustarDimensiones(691), ajustarDimensiones(303), ajustarDimensiones(88));
        logout.setBackground(Color.white);
        logout.setForeground(Color.red);
        logout.addActionListener(this);
        logout.setBorder(null);
        logout.setBorderPainted(false);
        logout.setFocusPainted(false);

        panelImgUser.setBounds(ajustarDimensiones(3), ajustarDimensiones(24), ajustarDimensiones(40), ajustarDimensiones(40));

        try {
            img = ImageIO.read(new File("src/Usuario.png"));
            Image dimg1 = img.getScaledInstance(panelImgUser.getWidth(), panelImgUser.getHeight(), Image.SCALE_SMOOTH);
            ImageIcon imageIcon = new ImageIcon(dimg1);
            panelImgUser.setIcon(imageIcon);
        } catch (IOException z) {
            System.out.println(z.getMessage());
        }

        setTitle("ButtonsBug");
        setLocationRelativeTo(null);
        setResizable(false);
        setVisible(true);

        buttonGenerator();

    }

    public int ajustarDimensiones(int coo) {
        int newC = 0;
        double res = (screenSize.getHeight());
        float newRes;
        if (res < 1080) {
            if (coo == 1400) {
                return 1208;
            } else if (coo == 800) {
                return 680;
            }
        }
        if (coo == 0) {
            return newC;
        } else {
            if (res < 1080) {
                newRes = (918f / 1080f);
                if (coo == 305) {
                    newC = (int) (newRes * coo) - 1;
                } else if (coo == 90) {
                    newC = (int) (newRes * coo) - 1;
                } else if (coo == 224) {
                    newC = (int) (newRes * coo) - 1;
                } else if (coo == 601) {
                    newC = (int) (newRes * coo) + 3;
                } else if (coo == 1066) {
                    newC = (int) (newRes * coo) - 1;
                } else if (coo == 1474 || coo == 1576) {
                    newC = (int) (newRes * coo) + 1;
                } else if (coo == 1059) {
                    newC = (int) (newRes * coo) - 10;
                } else if (coo == 1095) {
                    newC = (int) (newRes * coo) + 14;
                } else {
                    newC = (int) (newRes * coo);
                }
            } else {
                newRes = (float) (res / 1080f);
                newC = (int) (newRes * coo);
            }
            if (newC < 0) {
                newC = 1;
            }

        }

        return newC;
    }

    public void buttonGenerator() {

        int y = 0;
        panelNav.add(navScroll = new JScrollPane(buttonScroll = new JPanel(), JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER));
        navScroll.setBorder(BorderFactory.createEmptyBorder());
        navScroll.setBounds(ajustarDimensiones(1), ajustarDimensiones(90), ajustarDimensiones(303), ajustarDimensiones(600));
//        navScroll.setBackground(Color.white);
        navScroll.setOpaque(false);

        navScroll.getVerticalScrollBar().setUnitIncrement(30);
        navScroll.setPreferredSize(new Dimension(ajustarDimensiones(305), ajustarDimensiones(601)));
//        buttonScroll.setBackground(Color.white);
        buttonScroll.setPreferredSize(new Dimension(ajustarDimensiones(305), ajustarDimensiones(601)));
        buttonScroll.setLayout(null);
        navScroll.setViewportView(buttonScroll);
        buttonScroll.setOpaque(false);
        navScroll.getViewport().setOpaque(false);

        buttonScroll.add(funConsultarPiezas = new JButton());
        funConsultarPiezas.setContentAreaFilled(false);
        //           funConsultarPiezas.setOpaque(true);
        funConsultarPiezas.setText("Consultar pieza");
        funConsultarPiezas.setFont(new java.awt.Font("Arial", 1, ajustarDimensiones(30)));
        funConsultarPiezas.setBounds(ajustarDimensiones(1), ajustarDimensiones(0), ajustarDimensiones(301), ajustarDimensiones(80));
        //        funConsultarPiezas.setBackground(java.awt.Color.white);
        funConsultarPiezas.setForeground(Color.white);
        funConsultarPiezas.addActionListener(this);
        funConsultarPiezas.setBorder(null);
        funConsultarPiezas.setBorderPainted(false);
        funConsultarPiezas.setFocusPainted(false);
        botones.add(funConsultarPiezas);

        y += 81;

        buttonScroll.add(btnCalidad = new JButton());
        btnCalidad.setContentAreaFilled(false);
        //     btnCalidad.setOpaque(true);
        btnCalidad.setText("Quality Check");
        btnCalidad.setBounds(ajustarDimensiones(1), ajustarDimensiones(y), ajustarDimensiones(301), ajustarDimensiones(80));
        btnCalidad.setFont(new java.awt.Font("Arial", 1, ajustarDimensiones(30)));
        //        btnCalidad.setBackground(Color.white);
        btnCalidad.setForeground(Color.white);
        btnCalidad.addActionListener(this);
        btnCalidad.setBorder(null);
        btnCalidad.setBorderPainted(false);
        btnCalidad.setFocusPainted(false);
        botones.add(btnCalidad);

        y += 81;
        buttonScroll.add(planDis = new JButton());
        planDis.setContentAreaFilled(false);
        //       planDis.setOpaque(true);
        planDis.setText("Diseño y planear");
        planDis.setBounds(ajustarDimensiones(1), ajustarDimensiones(y), ajustarDimensiones(301), ajustarDimensiones(80));
        planDis.setFont(new java.awt.Font("Arial", 1, ajustarDimensiones(30)));
        //         planDis.setBackground(Color.white);
        planDis.setForeground(Color.white);
        planDis.addActionListener(this);
        planDis.setBorder(null);
        planDis.setBorderPainted(false);
        planDis.setFocusPainted(false);
        botones.add(planDis);

        y += 81;

        buttonScroll.add(compraMat = new JButton());
        compraMat.setContentAreaFilled(false);
//            compraMat.setOpaque(true);
        compraMat.setText("Compra Material");
        compraMat.setBounds(ajustarDimensiones(1), ajustarDimensiones(y), ajustarDimensiones(301), ajustarDimensiones(80));
        compraMat.setFont(new java.awt.Font("Arial", 1, ajustarDimensiones(30)));
        //compraMat.setBackground(Color.white);
        compraMat.setForeground(Color.white);
        compraMat.addActionListener(this);
        compraMat.setBorder(null);
        compraMat.setBorderPainted(false);
        compraMat.setFocusPainted(false);
        botones.add(compraMat);

        y += 81;

        buttonScroll.add(soySuper = new JButton());
        soySuper.setContentAreaFilled(false);
//            soySuper.setOpaque(true);
        soySuper.setText("Liberar piezas");
        soySuper.setBounds(ajustarDimensiones(1), ajustarDimensiones(y), ajustarDimensiones(301), ajustarDimensiones(80));
        soySuper.setFont(new java.awt.Font("Arial", 1, ajustarDimensiones(30)));
        //soySuper.setBackground(Color.white);
        soySuper.setForeground(Color.white);
        soySuper.addActionListener(this);
        soySuper.setBorder(null);
        soySuper.setBorderPainted(false);
        soySuper.setFocusPainted(false);
        botones.add(soySuper);

        y += 81;

        buttonScroll.add(crearProyecto = new JButton());
        crearProyecto.setContentAreaFilled(false);
//            crearProyecto.setOpaque(true);
        crearProyecto.setText("Crear proyecto");
        crearProyecto.setBounds(ajustarDimensiones(1), ajustarDimensiones(y), ajustarDimensiones(301), ajustarDimensiones(80));
        crearProyecto.setFont(new java.awt.Font("Arial", 1, ajustarDimensiones(30)));
        //crearProyecto.setBackground(Color.white);
        crearProyecto.setForeground(Color.white);
        crearProyecto.addActionListener(this);
        crearProyecto.setBorder(null);
        crearProyecto.setBorderPainted(false);
        crearProyecto.setFocusPainted(false);
        botones.add(crearProyecto);

        y += 81;

        buttonScroll.add(clientes = new JButton());
        clientes.setContentAreaFilled(false);
//            clientes.setOpaque(true);
        clientes.setText("Clientes");
        clientes.setBounds(ajustarDimensiones(1), ajustarDimensiones(y), ajustarDimensiones(301), ajustarDimensiones(80));
        clientes.setFont(new java.awt.Font("Arial", 1, ajustarDimensiones(30)));
        //clientes.setBackground(Color.white);
        clientes.setForeground(Color.white);
        clientes.addActionListener(this);
        clientes.setBorder(null);
        clientes.setBorderPainted(false);
        clientes.setFocusPainted(false);
        botones.add(clientes);

        y += 81;

        buttonScroll.add(adminConsProye = new JButton());
        adminConsProye.setContentAreaFilled(false);
//            adminConsProye.setOpaque(true);
        adminConsProye.setText("Consultar proyectos");
        adminConsProye.setBounds(ajustarDimensiones(1), ajustarDimensiones(y), ajustarDimensiones(301), ajustarDimensiones(80));
        adminConsProye.setFont(new java.awt.Font("Arial", 1, ajustarDimensiones(26)));
        //adminConsProye.setBackground(Color.white);
        adminConsProye.setForeground(Color.white);
        adminConsProye.addActionListener(this);
        adminConsProye.setBorder(null);
        adminConsProye.setBorderPainted(false);
        adminConsProye.setFocusPainted(false);
        botones.add(adminConsProye);

        y += 81;

        buttonScroll.add(histProy = new JButton());
        histProy.setText("Historial");
        histProy.setContentAreaFilled(false);
//            histProy.setOpaque(true);
        histProy.setBounds(ajustarDimensiones(1), ajustarDimensiones(y), ajustarDimensiones(301), ajustarDimensiones(80));
        histProy.setFont(new java.awt.Font("Arial", 1, ajustarDimensiones(30)));
        //histProy.setBackground(Color.white);
        histProy.setForeground(Color.white);
        histProy.addActionListener(this);
        histProy.setBorder(null);
        histProy.setBorderPainted(false);
        histProy.setFocusPainted(false);
        botones.add(histProy);

        y += 81;

        buttonScroll.add(consuEmpleados = new JButton());
        consuEmpleados.setText("Trabajadores");
        consuEmpleados.setContentAreaFilled(false);
//            consuEmpleados.setOpaque(true);
        consuEmpleados.setBounds(ajustarDimensiones(1), ajustarDimensiones(y), ajustarDimensiones(301), ajustarDimensiones(80));
        consuEmpleados.setFont(new java.awt.Font("Arial", 1, ajustarDimensiones(30)));
        //consuEmpleados.setBackground(Color.white);
        consuEmpleados.setForeground(Color.white);
        consuEmpleados.addActionListener(this);
        consuEmpleados.setBorder(null);
        consuEmpleados.setBorderPainted(false);
        consuEmpleados.setFocusPainted(false);
        botones.add(consuEmpleados);

        y += 81;

        buttonScroll.setPreferredSize(new Dimension(ajustarDimensiones(305), ajustarDimensiones(y)));
    }

    public void botonSeleccionado(JButton but) {
        for (JButton b : botones) {
            if (b.getText().equalsIgnoreCase(but.getText())) {
                b.setOpaque(true);
                b.setBackground(new Color(255, 102, 102, 200));
                b.setForeground(Color.white);
            } else {
                b.setOpaque(false);
                //b.setBackground(Color.white);
                b.setForeground(Color.white);
            }
            b.revalidate();
            b.repaint();
        }
    }

    @Override
    public void actionPerformed(ActionEvent ae) {
        JButton obj = (JButton) ae.getSource();
        if (obj != logout) {
            botonSeleccionado(obj);
        }
    }

}

如果有人知道如何制作一个透明的透明按钮,我将非常感谢您的帮助。

我将源代码和我正在使用的测试图像留在这里。 https://drive.google.com/file/d/1l8R52WTDyP93L0UhTNd3oorD7Qhv-TcP/view?usp=sharing

在此image中,您可以看到我遇到的3种错误,在第一个错误中,您可以看到背景中如何有另一个按钮,并且滚动条显示在按钮的左侧。在第二个中,它是导航面板的标题。在第三个窗口中,我多次将鼠标移过带孔的按钮,它变成了纯色,而不是透明的。

编辑:

我决定将Bug应用于导航面板后,是否仍然存在该错误,因为完成应用程序后,该bug也必须是透明的。因此,我在上面的代码的第82和83行中添加了以下代码行:

        panelNav.setBackground(new Color(0, 0, 0, 200));
        panelNav.setOpaque(true);

在另外一个image中,我将透明度应用于整个导航面板,这是一个JLabel。在第一个图像中显示了显示框架时显示的内容,甚至在导航面板下方显示了框架的某些部分。在第二个示例中,显示了一次使用滚动条会发生什么情况。

编辑2: 我替换了所有用作实际JPanel的JPanel的JLabel。可悲的是,该错误仍然存​​在。我在主JPanel中添加了一个额外的按钮,之所以这样做,是因为我认为错误的根源在于向JScrollPane添加按钮。但是似乎问题出在我如何实现方法buttonName.setBackground()上。

这是代码的新版本: https://drive.google.com/file/d/1PuHMkEYNbBoafqs5XiyUaeCkIyXfnHFJ/view?usp=sharing

1 个答案:

答案 0 :(得分:1)

在99%的情况下,您在示例应用程序中看到的问题都会由于不透明和/或不透明组件的不正确混合而发生。

从代码中可以看到-您正在使用setOpaque(...)来更改各种组件的不透明度,但这非常混乱。不久之后,opaque属性的作用-每当需要对该元素进行视觉更新时,它都会影响Swing重绘特定UI元素(面板/标签/按钮/等)的方式。

例如,当您用鼠标悬停一个按钮时-如果它具有不同的悬停状态(可能只是图标还是稍微/完全不同的样式),则可能需要重新绘制。这就是不透明性发挥作用的地方-opaque=true组件永远不会将重绘调用传递给它们自己的父组件(在其他/适当的术语下)。这意味着,如果面板上有一个不透明按钮,并且当按钮变为“悬停”状态时必须重新绘制按钮-该按钮将是唯一要重新绘制的组件,因为没有理由重新绘制下面的任何东西,因为它是不透明的,从字面上看您应该无法看穿它,因此,期望图形使用不透明的颜色填充该按钮范围内的所有像素。

从理论上讲。在实践中,如果将按钮设置为不透明状态,但将其图形内容保持透明或半透明(这显然是一个错误,但是Swing永远不会告诉您)-您最终将看到各种视觉效果,例如您会在应用程序中看到。发生这种情况是由于Graphics2D实现经常在(0,0)坐标上执行不同的绘制操作以优化其速度-知道这并不是很重要,但这部分地就是为什么您可能会看到其他组件“部分”混合在一起的原因您的组件在透明时会边界。比这复杂一点,但是它根本就不重要,因为它只是内部的Swing优化。

相似的视觉问题也可能是由于在同一布局上混合opaque=trueopaque=false组件而引起的。您的问题也很可能也是这种情况。我确实很快尝试将演示中的所有内容都设置为opaque=false,但确实解决了该问题,但这并不是真正的正确解决方法,尤其是当您想使某些组件不透明时。这仅表示问题出在某种程度上,即在单个容器中将具有不同不透明度类型的组件彼此叠加在一起。

我的个人建议-切勿在一个布局中混合不透明和非不透明的组件,即使它们有很小的机会重叠(这意味着它们的边界将在布局内相交)。甚至更好-绝不要在单个容器中将组件彼此重叠。使用具有适当的非null布局的多个嵌套容器,这还将在将来帮助您轻松修改UI。

我可以举一个简单的例子,说明它为什么不好:

/**
 * @author Mikle Garin
 */
public class OpacityGlitch
{
    public static void main ( String[] args )
    {
        SwingUtilities.invokeLater ( () -> {
            final JFrame frame = new JFrame ( "Opacity glitch sample" );

            // Opaque by default
            final JPanel panel = new JPanel ( null );

            // Opaque by default, but might vary with L&F
            final JButton button1 = new JButton ( "1111111" );
            panel.add ( button1 );

            // Non-opaque to demonstrate the problem
            final JButton button2 = new JButton ( "2222222" );
            panel.add ( button2 );

            // Intersecting buttons
            button1.setBounds ( 100, 100, 150, 30 );
            button2.setBounds ( 130, 115, 150, 30 );

            frame.getContentPane ().add ( panel );

            frame.setDefaultCloseOperation ( JFrame.EXIT_ON_CLOSE );
            frame.setSize ( 500, 500 );
            frame.setLocationRelativeTo ( null );
            frame.setVisible ( true );
        } );
    }
}

理论上,您应该得到的是button1始终在最上面(由于它是较早添加的并且在容器上最后被涂漆),但是在实践中-哪个按钮是完全可见的并且在另一个按钮之上如果您尝试将两个按钮中的任何一个都悬停,它将改变。发生这种情况的原因是两个按钮都是不透明的,并且重新绘制调用不会越过按钮组件到达它们的容器,并且任何东西都与它们相交。要解决此特殊情况,使button2不透明就足够了,因为它应始终保持在button1以下,如果不透明,它将安全地至少将重绘调用传递给它的容器:

button2.setOpaque ( false );

尽管我个人建议在这种情况下使所有涉及的组件不透明,以避免将来如果组件顺序可能更改或由于任何用户交互而更改其他可能出现的问题-例如,应用程序中的滚动条就是最好的例子。容器不一定非不透明,因为它可以正确地在放置于其中的组件之间传递重绘调用,也可以正确地重绘自身。

将按钮从上面的示例更改为不透明后,由于正确处理了重新绘制的问题,该问题将消失。

对于Swing初学者来说,这可能是一个复杂的话题,但是我强烈建议您完全了解这种情况的发生原因和发生方式,否则,一旦您的应用程序变得更大,它将对您来说成为一个巨大的问题。 / p>