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

时间:2015-04-27 19:11:56

标签: java swing jframe jbutton repaint

我试图通过透明按钮为游戏开发菜单。 我的问题是,每次我徘徊时,按钮堆积起来。 所以我添加了一个执行myJFrame.repaint()的MouseListener;每次我徘徊他们。 问题是,重新绘制如此缓慢,这会扰乱用户。 我希望有人知道更好的方式。

对不起,如果有错误,我的英语不是最好的。

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

4 个答案:

答案 0 :(得分:1)

如果您从半透明/透明度获取工件,请尝试在按钮上调用setOpaque(false)。它可以帮助您获得预期的结果,而无需在父组件上调用重绘。在窗帘后面摆动,可能会重新绘制第一个不透明的父母,但只有所需的区域。

答案 1 :(得分:1)

我很遗憾地说,但是你的代码在很多方面都失败了。您尝试重新绘制的尝试只是其他一些问题的解决方法。如果您知道正确的提示,则代码变得相当容易。但是,相反解释所有出错的细节,我只是将整个固定代码放在这里,其中包含有关重要事项的评论。

Main.java拥有主类。它只是打开并配置主窗口。 (菜单本身位于另一个名为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是最大的文件。

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

答案 2 :(得分:0)

当然,

repaint(x ,y ,width, height);

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

答案 3 :(得分:0)

调用任何repaint()方法只是将组件排队,以便稍后重新绘制。如果在RepaintManager实际重新绘制Component之前多次调用repaint(),则只需将它们组合成一个重绘操作。

您应该尝试使用其中一个paintImmediately()方法,因为这些方法会立即执行重绘(假设您无法从名称中猜出)。

有关其他信息,请阅读: Painting in AWT and Swing