Java Компонент AWT / Swing мерцает при перерисовке () - PullRequest
0 голосов
/ 05 августа 2020

В настоящее время я работаю над программой, для которой требуются настраиваемые кнопки (например, простоя, наведение и графика нажатия). Я попытался создать собственный класс кнопки как подкласс Component (AWT) / Button (AWT) / JComponent (Swing) / JButton (Swing) и переопределить их методы paint (AWT) / paintComponent (Swing) для рисования изображений. Но независимо от того, какой класс я использовал, у меня всегда было непоследовательное мерцание при наведении / нажатии на пользовательские кнопки. Я искал это, и все, что я нашел, были сообщениями, в которых говорилось, что нужно только переопределить paintComponent и всегда использовать super.paintComponent внутри, но я сделал все это, и это вообще не изменилось. Также включение setDoubleBuffered (true) не имело никакого значения. Вот код моей пользовательской кнопки:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.JComponent;


public abstract class CustomButton extends JComponent implements MouseListener
{

    private Image   image , hoverImage , clickImage;
    private String  displayText;
    private Font    font;
    private Color   textColor;
    private boolean hovered = false , pressed = false;

    public CustomButton( final Image img , final Image hoverImg , final Image clickImg )
    {

        super();
        setImages( img , hoverImg , clickImg );
        addMouseListener( this );
        setFocusable( false );
        setSize( getPreferredSize() );

    } // End of constructor

    public CustomButton( final String text , final Font font , final Color textColor , final Image img , final Image hoverImg , final Image clickImg )
    {

        this( img , hoverImg , clickImg );
        setText( text , font , textColor );

    } // End of constructor

    public void setText( final String text , final Font font , final Color textColor )
    {

        displayText = text;

        if( text != null && font == null )
            throw new IllegalArgumentException( "Font type of a button can't be null if text has to be displayed." );
        this.font = font;
        if( font == null )
            this.textColor = null;
        else if( textColor == null )
            throw new IllegalArgumentException( "Font color of a button can't be null if font type isn't null." );
        else
            this.textColor = textColor;

        repaint();

    } // End of setText( final String text , final Font font , final Color textColor )

    public void setText( final String text )
    {

        if( text != null && ( font == null || textColor == null ) )
            throw new IllegalArgumentException( "Text of a button can't be changed without assigning a proper colour and font type." );

        displayText = text;
        repaint();

    } // End of setText( final String text )

    public void setImages( final Image img , final Image hoverImg , final Image clickImg )
    {

        if( img == null )
            throw new IllegalArgumentException( "Background image of a button can't be null." );

        if( hoverImg != null && ( img.getWidth( this ) != hoverImg.getWidth( this ) || img.getHeight( this ) != hoverImg.getHeight( this ) ) )
            throw new IllegalArgumentException( "Background image and hover image can't have different sizes." );

        if( clickImg != null && ( img.getWidth( this ) != clickImg.getWidth( this ) || img.getHeight( this ) != clickImg.getHeight( this ) ) )
            throw new IllegalArgumentException( "Background image and click image can't have different sizes." );

        image = img;
        hoverImage = hoverImg;
        clickImage = clickImg;

        repaint();

    } // End of setImages( final ImageIcon img , final ImageIcon hoverImg , final ImageIcon clickImg )

    @Override
    public void mousePressed( MouseEvent e )
    {

        pressed = true;
        repaint();

    } // End of mousePressed( MouseEvent e )

    @Override
    public void mouseReleased( MouseEvent e )
    {

        pressed = false;
        repaint();

    } // End of mouseReleased( MouseEvent e )

    @Override
    public void mouseEntered( MouseEvent e )
    {

        hovered = true;

        if( pressed )
            return;

        repaint();

    } // End of mouseEntered( MouseEvent e )

    @Override
    public void mouseExited( MouseEvent e )
    {

        hovered = false;

        if( pressed )
            return;

        repaint();

    } // End of mouseExited( MouseEvent e )

    @Override
    public Dimension getPreferredSize()
    {

        return new Dimension( image.getWidth( this ) , image.getHeight( this ) );

    } // End of getPreferredSize()

    @Override
    public Dimension getMaximumSize()
    {

        return getPreferredSize();

    } // End of getMaximumSize()

    @Override
    public Dimension getMinimumSize()
    {

        return getPreferredSize();

    } // End of getMinimumSize()

    @Override
    public void paintComponent( Graphics g )
    {

        super.paintComponent( g );

        if( pressed )
            g.drawImage( clickImage , 0 , 0 , this );
        else if( hovered )
            g.drawImage( hoverImage , 0 , 0 , this );
        else
            g.drawImage( image , 0 , 0 , this );

    } // End of paint( Graphics g )

} // End of class

Два других класса для MRE:

import java.awt.Panel;

import javax.swing.JFrame;


public class MainFrame extends JFrame
{

    private Panel mainPanel;

    public MainFrame()
    {

        setResizable( false );
        setDefaultCloseOperation( EXIT_ON_CLOSE );
        setBounds( 0 , 0 , 1920 , 1080 );
        setUndecorated( true );
        setVisible( true );

        enterMainMenuState();

    }// End of constructor

    public void enterMainMenuState()
    {

        getContentPane().removeAll();

        mainPanel = new MainMenuPanel();

        setContentPane( mainPanel );

        revalidate();

    }// End of enterMainMenuState()

    public static void main( String [] args )
    {

        // Hardware acceleration
        System.setProperty( "sun.java2d.opengl" , "true" );

        new MainFrame();

    }

} // End of class

и:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.Image;
import java.awt.Panel;
import java.awt.Toolkit;
import java.awt.event.MouseEvent;

import javax.swing.Box;
import javax.swing.BoxLayout;


public class MainMenuPanel extends Panel
{

    private final Image btnIdlImg   = Toolkit.getDefaultToolkit().getImage( "src/MainmenuButtonIdle.png" );
    private final Image btnHvrImg   = Toolkit.getDefaultToolkit().getImage( "src/MainmenuButtonHover.png" );
    private final Image btnPrsImg   = Toolkit.getDefaultToolkit().getImage( "src/MainmenuButtonPress.png" );
    private final Color buttonColor = Color.WHITE;
    private final Font  buttonFont  = new Font( "Arial" , Font.PLAIN , 36 );

    private Panel buttonPanel = new Panel();

    private MainMenuButton  buttonContinue  = new MainMenuButton( "CONTINUE_LAST_SAVE" , buttonFont , buttonColor , btnIdlImg , btnHvrImg , btnPrsImg );
    private MainMenuButton  buttonNew       = new MainMenuButton( "NEW_GAME" , buttonFont , buttonColor , btnIdlImg , btnHvrImg , btnPrsImg );
    private MainMenuButton  buttonLoad      = new MainMenuButton( "LOAD_GAME" , buttonFont , buttonColor , btnIdlImg , btnHvrImg , btnPrsImg );
    private MainMenuButton  buttonSettings  = new MainMenuButton( "OPTIONS" , buttonFont , buttonColor , btnIdlImg , btnHvrImg , btnPrsImg );
    private MainMenuButton  buttonCredits   = new MainMenuButton( "CREDITS" , buttonFont , buttonColor , btnIdlImg , btnHvrImg , btnPrsImg );
    private MainMenuButton  buttonClose     = new MainMenuButton( "CLOSE_BUTTON" , buttonFont , buttonColor , btnIdlImg , btnHvrImg , btnPrsImg );

    public MainMenuPanel()
    {

        // Hintergrundfarbe festlegen
        setBackground( Color.BLACK );

        setLayout( new BorderLayout() );

        buttonPanel.setLayout( new BoxLayout( buttonPanel , BoxLayout.Y_AXIS ) );

        buttonPanel.add( buttonContinue );
        buttonPanel.add( Box.createVerticalStrut( 50 ) );
        buttonPanel.add( buttonNew );
        buttonPanel.add( Box.createVerticalStrut( 50 ) );
        buttonPanel.add( buttonLoad );
        buttonPanel.add( Box.createVerticalStrut( 50 ) );
        buttonPanel.add( buttonSettings );
        buttonPanel.add( Box.createVerticalStrut( 50 ) );
        buttonPanel.add( buttonCredits );
        buttonPanel.add( Box.createVerticalStrut( 50 ) );
        buttonPanel.add( buttonClose );

        add( buttonPanel , BorderLayout.CENTER );

    } // End of constructor

    private class MainMenuButton extends CustomButton
    {

        public MainMenuButton( final String text , final Font font , final Color textColor , final Image img , final Image hoverImg , final Image clickImg )
        {

            super( text , font , textColor , img , hoverImg , clickImg );

        } // End of constructor

        @Override
        public void mouseClicked( MouseEvent e )
        {

            // TODO

        } // End of mouseClicked( MouseEvent e )

    } // End of class

} // End of class
...