Java 如何更新JFrame比使用repaint()更快;

Java 如何更新JFrame比使用repaint()更快;,java,swing,jframe,jbutton,repaint,Java,Swing,Jframe,Jbutton,Repaint,我正在尝试为游戏开发一个带有透明按钮的菜单。 我的问题是,每次我悬停按钮时,它们都会堆积起来。 因此,我添加了一个执行myJFrame.repaint()的MouseStener;每次我在它们上面盘旋。 问题是,重新绘制的速度太慢,用户感到不安。 我希望有人知道更好的方法 如果有错误,我很抱歉,我的英语不是最好的 public class Hauptmenue extends javax.swing.JFrame implements ActionListener { private stati

我正在尝试为游戏开发一个带有透明按钮的菜单。 我的问题是,每次我悬停按钮时,它们都会堆积起来。 因此,我添加了一个执行myJFrame.repaint()的MouseStener;每次我在它们上面盘旋。 问题是,重新绘制的速度太慢,用户感到不安。 我希望有人知道更好的方法

如果有错误,我很抱歉,我的英语不是最好的

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();
}}
我还对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
}}
当然

将只重新绘制这些边界,加快它们的速度,并省略不必要的工作。

调用任何repaint()方法只是将组件排队等待稍后重新绘制。如果在RepaitManager实际重新绘制组件之前多次调用Repait(),则它们将简单地合并到一个重新绘制操作中

您应该尝试使用其中一个paintInstance()方法,因为这些方法会立即执行重新绘制(我打赌您无法从名称中猜到)

欲了解更多信息,请阅读:

如果您从半透明/透明中获得瑕疵,请尝试在按钮上调用
setOpaque(false)
。它可以帮助您获得预期的结果,而无需调用父组件上的重绘。在courtains后面的Swing可能会重新绘制第一个不透明的父对象,但只需要绘制所需的区域。

很抱歉,您的代码在很多方面都失败了。您尝试重新绘制只是解决其他一些问题的一种方法。如果您知道正确的提示,代码就会变得相当简单。但是,我没有解释所有出错的小细节,而是将整个固定代码放在这里,其中包含有关重要内容的注释

Main.java
持有主类。它只是打开并配置主窗口。(菜单本身在另一个名为
MainMenu
的类中)

main menu.java
是最大的文件

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!
    }
}
最后,但并非最不重要的是,半透明按钮的代码:

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!
    }
}

不要覆盖
paint()
,而要覆盖
paintComponent()
。不要忘记调用
super.paintComponent(g)
您不应该在
paint
中手动绘制子组件(按钮)。这是自动完成的,因为它们是主
JFrame
的子对象!还有:不要处理你没有创建的
图形
对象!
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!
    }
}
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!
    }
}