В настоящее время я работаю над программой, для которой требуются настраиваемые кнопки (например, простоя, наведение и графика нажатия). Я попытался создать собственный класс кнопки как подкласс 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