1

I'm trying to develope an menue with transparent buttons for a game. My problem was, that the buttons piled up with every time I hovered them. So I added an MouseListener which executes myJFrame.repaint(); every time I hover them. The problem is, the repainting so slow, that disturbs the user. I hope that someone knows a better way.

I'm sorry if there are mistakes, my english is not the best.

public class Hauptmenue extends javax.swing.JFrame implements ActionListener {
private static final long serialVersionUID = 8132389688291883346L;

//Toolkit für das Freie Skalieren des Hauptmenüs
private Toolkit t;
//variablen für das Fenster
private int x, y, width, height;

//variablen für die Köpfe
private int kx, kwidth, kheight;

//Variablen für die Knöpfe im Hauptmenü:
private JButton2 single;
private JButton2 multi;
private JButton2 einstellungen;
private JButton2 info;
private JButton2 ende;

//Hintergrund des Hauptmenüs
Image background;

public Hauptmenue(){
    //Bildschirmgröße messen:
    t = Toolkit.getDefaultToolkit();
    Dimension d = t.getScreenSize();
    width = (int)(d.getWidth() * 0.23);
    height = (int)(d.getHeight() * 0.5);
    x = (int)((d.getWidth() - width) * 0.5);
    y = (int)((d.getHeight() - height) * 0.5);

    setTitle("Hauptmenü");
    setBounds(x, y, width, height);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setLayout(null);
    setBackground(null);


    //Hintergrnd Bild
    //setFocusable(true);
    File pfad = new File("res/Images/Hintergrund_1.png");
    ImageIcon u = new ImageIcon(pfad.getPath());
    background = u.getImage();
    //background = background.getScaledInstance(width, height, Image.SCALE_DEFAULT);

    //sorgt dafür, dass das Menü keinen Rahmen hat
    setUndecorated(true); 

    //knopfpositionen und Größen berechnen
    kwidth = (int)(width * 0.8);
    kheight = (int)(height * 0.125);
    kx = (int)(width - kwidth) / 2;

    //die Knöpfe:
    single = new JButton2("Singelplayer");
    single.setBounds(kx, (kheight * 1), kwidth, kheight);
    single.addActionListener(this);
    single.addMouseListener(new java.awt.event.MouseAdapter() {
        public void mouseEntered(java.awt.event.MouseEvent evt) {
            JFrame frme = (JFrame) info.getParent().getParent().getParent().getParent();
            frme.repaint();
        }

        public void mouseExited(java.awt.event.MouseEvent evt) {
            JFrame frme = (JFrame) info.getParent().getParent().getParent().getParent();
            frme.repaint();
        }
    });
    add(single);

    multi = new JButton2("Multiplayer");
    multi.setBounds(kx, (int)(kheight * 2.25), kwidth, kheight);
    multi.addActionListener(this);
    multi.addMouseListener(new java.awt.event.MouseAdapter() {
        public void mouseEntered(java.awt.event.MouseEvent evt) {
            JFrame frme = (JFrame) info.getParent().getParent().getParent().getParent();
            frme.repaint();
        }

        public void mouseExited(java.awt.event.MouseEvent evt) {
            JFrame frme = (JFrame) info.getParent().getParent().getParent().getParent();
            frme.repaint();
        }
    });
    add(multi);

    einstellungen = new JButton2("Einstellungen");
    einstellungen.setBounds(kx, (int)(kheight * 3.5), kwidth, kheight);
    einstellungen.addActionListener(this);
    einstellungen.addMouseListener(new java.awt.event.MouseAdapter() {
        public void mouseEntered(java.awt.event.MouseEvent evt) {
            JFrame frme = (JFrame) info.getParent().getParent().getParent().getParent();
            frme.repaint(1);
        }

        public void mouseExited(java.awt.event.MouseEvent evt) {
            JFrame frme = (JFrame) info.getParent().getParent().getParent().getParent();
            frme.repaint(1);
        }
    });
    add(einstellungen);

    info = new JButton2("Info");
    info.setBounds(kx, (int)(kheight * 4.75), kwidth, kheight);
    info.addActionListener(this);
    info.addMouseListener(new java.awt.event.MouseAdapter() {
        public void mouseEntered(java.awt.event.MouseEvent evt) {
            JFrame frme = (JFrame) info.getParent().getParent().getParent().getParent();
            frme.repaint();
        }

        public void mouseExited(java.awt.event.MouseEvent evt) {
            JFrame frme = (JFrame) info.getParent().getParent().getParent().getParent();
            frme.repaint();
        }
    });
    add(info);

    ende = new JButton2("Beenden");
    ende.setBounds(kx, (kheight * 6), kwidth, kheight);
    ende.addActionListener(this);
    ende.addMouseListener(new java.awt.event.MouseAdapter() {
        public void mouseEntered(java.awt.event.MouseEvent evt) {
            JFrame frme = (JFrame) info.getParent().getParent().getParent().getParent();
            frme.repaint();
        }

        public void mouseExited(java.awt.event.MouseEvent evt) {
            JFrame frme = (JFrame) info.getParent().getParent().getParent().getParent();
            frme.repaint();
        }
    });
    add(ende);



    setVisible(true);
}

//der Hintergrund:


//zum Zeichnen des Hintergrundes:
public void paint(Graphics g){
    super.paint(g);
    Graphics2D f2 = (Graphics2D)g;
    f2.drawImage(background, 0, 0, width, height, null);

    //Knöpfe in den Vordergrund holen
    this.single.paint(this.single.getGraphics());
    this.multi.paint(this.multi.getGraphics());
    this.einstellungen.paint(this.einstellungen.getGraphics());
    this.info.paint(this.info.getGraphics());
    this.ende.paint(this.ende.getGraphics());

    g.dispose();
}

//Funktionen hinter den Knöpfen:
private void Singleplayer(){

}

private void Multiplayer(){

}

private void Einstellungen(){
    new Einstellungsfenster();
}

private void Info(){
    new Infofenster();
}

private void Beenden(){
    System.exit(0);
}

//Reaktionen auf die Knopfdrücke:
public void actionPerformed (ActionEvent e){
    if(e.getSource() == single){
        Singleplayer();
    }
    if(e.getSource() == multi){
        Multiplayer();
    }
    if(e.getSource() == einstellungen){
        Einstellungen();
    }
    if(e.getSource() == info){
        Info();
    }
    if(e.getSource() == ende){
        Beenden();
    }
}

//Programmstart
public static void main(String[]args){
    //das Hauptmenü wird erzeugt
    new Hauptmenue();
}}

Also I made a few changes for the JButton:

public class JButton2 extends JButton {
private static final long serialVersionUID = 5193885870007603559L;


public JButton2(){

}

public JButton2(String text){
    this.setText(text);
    //this.setOpaque(false);
    //this.setContentAreaFilled(false);
    //this.setBackground(null);
}

@Override
public void paint(Graphics g){
    //super.paint(g);
    Graphics2D g2 = (Graphics2D) g.create();
    g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, (float) 0.8));
    super.paint(g2);    
    g.dispose();
    g2.dispose();
}

//@Override
public void repaint(){
    //hier passiert nichts
}}

4 Answers4

1

If you are getting artifacts from translucency/transparency, try to call setOpaque(false) on your buttons. It might help you getting the expected result without resorting to call the repaint on the parent component. Swing, behind the courtains, will probably repaint the first opaque parent, but only the region needed.

Renatols
  • 388
  • 1
  • 8
1

I'm sorry to say that, but your code fails in so many ways. Your attempts to do repainting is just a workaround for some other issues. If you knew the right hints, the code gets rather easy. But instead explaining all the minor details that went wrong, I just put the entire fixed code here, which contains comments about important things.

Main.java holds the main class. It just opens and configures the main window. (The menu itself is in another class called MainMenu).

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Toolkit;

import javax.swing.JFrame;

/**
 * Main class
 */
public class Main {
    /**
     * Create the GUI and show it. For thread safety, this method should be
     * invoked from the event-dispatching thread.
     */
    private static void createAndShowGUI() {
        // Create and set up the window.
        JFrame frame = new JFrame("Game");
        frame.setUndecorated(true);

        // Center on screen
        Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
        int width = (int) (d.getWidth() * 0.23);
        int height = (int) (d.getHeight() * 0.5);
        int x = (int) ((d.getWidth() - width) * 0.5);
        int y = (int) ((d.getHeight() - height) * 0.5);
        frame.setBounds(x, y, width, height);

        // Set the menu bar and add the label to the content pane.
        MainMenu menu = new MainMenu();

        // We only add components to the content pane, NEVER directly via
        // add(...)!!!
        frame.getContentPane().add(menu, BorderLayout.CENTER);

        // Display the window.
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        // Schedule a job for the event-dispatching thread:
        // creating and showing this application's GUI.
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });
    }
}

MainMenu.java is the largest file.

import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.image.BufferedImage;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;

/**
 * Main menu is a JPanel.
 */
public class MainMenu extends JPanel {
    private JButton single;
    private JButton multi;
    private JButton settings;
    private JButton info;
    private JButton exit;
    private BufferedImage background;

    public MainMenu() {
        super();

        // We use a layout manager to do all layouting for us
        // So we can lean back and do not have to do odd maths
        GridLayout layout = new GridLayout(5, 1);
        layout.setVgap(20);
        setLayout(layout);

        // An empty border to ensure distance form the bounds of the panel
        setBorder(new EmptyBorder(50, 30, 50, 30));

        single = new AlphaButton("Single", 0.8f);
        multi = new AlphaButton("Multi", 0.8f);
        settings = new AlphaButton("Settings", 0.8f);
        info = new AlphaButton("Info", 0.8f);
        exit = new AlphaButton("Exit", 0.8f);
        exit.addActionListener(evt -> System.exit(0));

        // Add the buttons to this panel.
        // It will take care of the rest (repainting etc.)
        add(single); add(multi); add(settings); add(info); add(exit);

        try {
            // load background image
            background = ImageIO.read(
                getClass().getResource("res/Images/Hintergrund_1.png"));
        } catch (IOException e) {
            // TODO exception handling
            e.printStackTrace();
        }
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        // Here, we just draw the background. Nothing else!
        // Use this as image observer so repainting occurs if the image changes
        // (which doesn't happen here, but we want to do it right).
        g.drawImage(background, 0, 0, getWidth(), getHeight(), this);

        // DO NOT DISPOSE g - you did not create it!
    }
}

Last, but not least, the code for the translucent button:

import java.awt.AlphaComposite;
import java.awt.Composite;
import java.awt.Graphics;
import java.awt.Graphics2D;

import javax.swing.JButton;

/**
 * Semi-transparent {@link JButton}.
 */
public class AlphaButton extends JButton {
    private float alpha;

    public AlphaButton(String text, float alpha) {
        super(text);
        this.alpha = alpha;
        // This is important! It tells the painting system that the underlying
        // pixels may shine through, so it must always paint the background
        // before this component can be painted.
        setOpaque(false);
    }

    @Override
    protected void paintComponent(Graphics g) {
        Graphics2D g2 = (Graphics2D) g;

        Composite old = g2.getComposite(); // remember old composite
        g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha));
        super.paintComponent(g2);
        g2.setComposite(old); // restore old composite

        // DO NOT DISPOSE g (or g2) - you did not create it!
    }
}
isnot2bad
  • 24,105
  • 2
  • 29
  • 50
0

Sure,

repaint(x ,y ,width, height);

Would repaint just these boundaries, speeding them up, and omitting unnecessary work.

Mordechai
  • 15,437
  • 2
  • 41
  • 82
0

Calling any of the repaint() methods just queues the Component to be repainted at some later time. If you call repaint() multiple times before the Component is actually repainted by the RepaintManager they are simply combined into one repaint operation.

You should try using one of the paintImmediately() methods as these perform the repaint immediately (bet you couldn't guess that from the name).

For additional information read: Painting in AWT and Swing

Jesse Craig
  • 560
  • 5
  • 18