Почему прозрачный JButton показывает изображения кадра при добавлении прозрачности? - PullRequest
1 голос
/ 26 июня 2019

Я разрабатываю графический интерфейс для приложения Java и хочу иметь фоновое изображение. Проблема в том, что у меня есть тип «ящика», заполненного кнопками, у которого кнопки выделены красным, когда они выбраны.

Я использую метод buttonName.setBackground (новый цвет (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

На этом изображении вы можете видеть 3 вида ошибок, которые у меня есть, в первом вы можете видеть, как есть еще одна кнопка на заднем плане и полоса прокрутки слева от кнопка. Во втором это заголовок панели навигации. В третьем я несколько раз провел мышью по выбранной кнопке, и она превратилась в сплошной цвет вместо прозрачного.

EDIT:

Я решил проверить, сохранилась ли ошибка, если я применил ее к панели навигации, потому что она будет прозрачной и после завершения приложения. Поэтому я добавил следующие строки кода в строки 82 и 83 кода выше:

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

В этом другом изображении Я применил прозрачность ко всей панели навигации, которая является JLabel. На первом изображении показано, что появляется, когда отображается рамка, есть даже части рамки, отображаемые под панелью навигации. Во втором показано, что происходит, когда я использую полосу прокрутки один раз.

РЕДАКТИРОВАТЬ 2: Я заменил все JLabel, которые использовались в качестве JPanel для реальной JPanel. К сожалению, ошибка сохранилась. Я добавил дополнительную кнопку в основной JPanel, я сделал это, потому что я думал, что ошибка возникла из-за добавления кнопок в JScrollPane. Но, похоже, проблема заключается в том, как я реализую метод buttonName.setBackground ().

Вот новая версия кода: https://drive.google.com/file/d/1PuHMkEYNbBoafqs5XiyUaeCkIyXfnHFJ/view?usp=sharing

1 Ответ

1 голос
/ 27 июня 2019

Любые проблемы, подобные той, которую вы видите в примере приложения, которое вы опубликовали в 99% случаев, происходят из-за неправильного смешивания непрозрачных и / или непрозрачных компонентов.

Как видно из кода - вы используете setOpaque(...) для изменения непрозрачности различных компонентов, но это довольно хаотично.Вкратце, что делает свойство opaque - оно влияет на то, как Swing перерисовывает определенный элемент пользовательского интерфейса (панель / метка / кнопка / и т. Д.) Всякий раз, когда требуется визуальное обновление для этого элемента.

Например, при наведении курсора на кнопку мыши - может потребоваться перекрасить, если у нее другое состояние наведения, будь то просто значок или немного / совсем другой стиль.Именно здесь в игру вступает непрозрачность - opaque=true компоненты никогда не передадут вызовы перерисовки «под себя» (другими словами, в свои родительские компоненты).Это означает, что если у вас есть непрозрачная кнопка на панели, и она должна быть перекрашена, когда она переходит в состояние «зависания» - эта кнопка будет единственным компонентом, который нужно перекрасить, поскольку нет никаких причин перерисовывать что-либо под ней, потому что онанепрозрачный, вы буквально не должны видеть его, поэтому ожидается, что графика заполнит все пиксели в пределах этой кнопки непрозрачными цветами.

Теоретически.На практике, если вы устанавливаете кнопку в непрозрачное состояние, но сохраняете ее графический контент прозрачным или полупрозрачным (что, очевидно, является ошибкой, но Swing никогда не скажет вам об этом) - вы в конечном итоге увидите различные визуальные артефакты, такие каквы видите в вашем приложении.Это происходит из-за того, что реализация Graphics2D часто выполняет различные операции рисования с координатами (0,0) для оптимизации их скорости - это не очень важно знать, но отчасти поэтому вы можете видеть, как другие компоненты компонента смешиваются в вашем компонентеграницы, когда это прозрачно.Это немного сложнее, чем это, но это не должно иметь большого значения, поскольку это просто внутренняя оптимизация Swing.

Подобные визуальные проблемы могут быть вызваны смешиванием компонентов opaque=true и opaque=false ната же схемаСкорее всего, это относится и к вашей проблеме.Я быстро попытался установить все в вашей демонстрации на opaque=false, и это действительно решило проблему, но это не совсем правильный способ исправить это, особенно если вы хотите, чтобы некоторые компоненты оставались непрозрачными.Это просто означает, что проблема заключается где-то в смешивании компонентов с различными типами непрозрачности друг над другом в одном контейнере.

Моя личная рекомендация - никогда не смешивайте непрозрачные и непрозрачные компоненты в одном макете, если естьдаже небольшая вероятность того, что они будут перекрываться (то есть их границы будут пересекаться в макете).Или даже лучше - никогда не накладывайте компоненты друг на друга в одном контейнере.Используйте несколько вложенных контейнеров с соответствующими ненулевыми макетами, это также поможет вам в будущем легко изменить ваш пользовательский интерфейс.

Я могу привести простой пример, который может продемонстрировать, почему это плохо:

/**
 * @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, но я настоятельно рекомендую полностью понять, почему и как подобные вещи происходят, иначе это станет огромной проблемой для вас в будущем, как только ваше приложение станет больше.

...