在定制JPanel上动态更改图像的最佳解决方案

时间:2016-08-04 17:16:49

标签: java swing

所以让我们从一点背景开始吧。我正在研究JAVA中的个人项目,主要是为了试验Java GUI,总体而言,了解更多。该项目包含一个菜单GUI,类似于视频游戏。例如,主菜单有它的按钮和背景图像,但是当点击选项按钮时,选项菜单“替换”主菜单,但没有关闭任何东西,更改背景图像(或至少有可能做so)以及可能存在的按钮和其他组件。

现在,只需将所有JButton和JLabel以及所有内容放在不同的JPanel中并简单地使用setVisible(Boolean)即可轻松完成,事情是,我还希望拥有一个自动的实际背景图像当用户改变菜单窗口的大小时缩放本身,因此我不能使用JLabel作为图像,并且在搜索之后我发现了一个带有特殊“JBackgroundPanel”的类(见下文)我已经简化了一下符合我的需求(主要采取一些方法)

这是JBackgroundPanel类(原始链接位于public class JBackgroundPanel ...顶部的注释中):

import javax.swing.JPanel;
import java.awt.Image;
import javax.swing.JComponent;
import java.awt.Dimension;
import java.awt.BorderLayout;
import java.awt.Paint;
import java.awt.Rectangle;
import javax.swing.JScrollPane;
import javax.swing.JViewport;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;

/**
 * @author Rob Camick
 * @Date 12/10/2008
 * @Credits Here are the credits to the person that actually created this class.
 * {@code} http://www.camick.com/java/source/BackgroundPanel.java
 * {@link} https://tips4java.wordpress.com/2008/10/12/background-panel/
 * 
 *
 */

public class JBackgroundPanel extends JPanel    {

private Paint P;
private Image image;
private float xAlign = 0.5f;
private float yAlign = 0.5f;
private boolean isTransparentAdd = true;

public JBackgroundPanel(Image image)
{
    setImage(image);
    setLayout(new BorderLayout());
}

public JBackgroundPanel(Image image, float xAlign, float yAlign)
{
    setImage(image);
    setImageAlignX(xAlign);
    setImageAlignY(yAlign);
    setLayout(new BorderLayout());
}

public JBackgroundPanel(Paint P)
{
    setPaint( P);
    setLayout(new BorderLayout());
}

public void setImage(Image image)
{
    this.image = image;
    repaint();
}

public Image getImage(){

    return this.image;

}

public void setPaint(Paint P)
{
    this.P = P;
    repaint();
}

public void setImageAlignX(float xAlign)
{
    this.xAlign = xAlign > 1.0f ? 1.0f : xAlign < 0.0f ? 0.0f : xAlign;
    repaint();
}

public void setImageAlignY(float yAlign)
{
    this.yAlign = yAlign > 1.0f ? 1.0f : yAlign < 0.0f ? 0.0f : yAlign;
    repaint();
}

public void add(JComponent component)
{
    add(component, null);
}

public Dimension getPreferredSize()
{
    if (image == null)
        return super.getPreferredSize();
    else
        return new Dimension(image.getWidth(null), image.getHeight(null));
}

public void add(JComponent component, Object constraints)
{
    if (isTransparentAdd)
    {
        makeComponentTransparent(component);
    }

    super.add(component, constraints);
}

public void setTransparentAdd(boolean isTransparentAdd)
{
    this.isTransparentAdd = isTransparentAdd;
}

private void makeComponentTransparent(JComponent component)
{
    component.setOpaque( false );

    if (component instanceof JScrollPane)
    {
        JScrollPane scrollPane = (JScrollPane)component;
        JViewport viewport = scrollPane.getViewport();
        viewport.setOpaque( false );
        Component c = viewport.getView();

        if (c instanceof JComponent)
        {
            ((JComponent)c).setOpaque( false );
        }
    }
}

@Override
protected void paintComponent(Graphics g)
{
    super.paintComponent(g);


    if (P != null)
    {
        Dimension d = getSize();
        Graphics2D G = (Graphics2D) g;
        G.setPaint(P);
        G.fill( new Rectangle(0, 0, d.width, d.height) );
    }

    if (image == null ) return;

    draw(g);


}

private void draw(Graphics g)
    {
        Dimension d = getSize();
        g.drawImage(image, 0, 0, d.width, d.height, null);
    }





}

本守则完美无缺。现在,我认为你也应该有我的代码。见下文:

import java.awt.Container;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import javax.imageio.ImageIO;
import JBackgroundPanel;
import javax.swing.JFrame;
import javax.swing.JPanel;



public class MainUI extends JFrame implements /*ActionListener*/    {

private Container cont = this.getContentPane();
private JBackgroundPanel bgPanel;
private Image bgImg;


private enum GState{

    GMenuOne,
    GMenuTwo,

};

private GState MENU_STATE = GState.GMenuOne;

public MainUI() {

    this.setPreferredSize(this.getMaximumSize());
    this.setResizable(true);
    this.setSize(this.getMaximumSize());
    this.setUndecorated(false);
    this.setDefaultCloseOperation(EXIT_ON_CLOSE);
    this.initComponents();
    this.reload();
    this.setVisible(true);

    this.MENU_STATE = GState.GMenuOne;
    this.reload();

}

public void reload()    {

    if(this.MENU_STATE.equals(GState.GMenuOne) )    {

        this.loadBackground("MenuOne"/*LOAD MAIN MENU*/);
        this.repaint();

    }   else if(this.MENU_STATE.equals(GState.GMenuTwo))    {

        this.loadBackground("MenuTwo");
        repaint();

        }   

    }

public boolean loadBackground(String Bg)     {

    try {


            bgImg = ImageIO.read(new File("src/resImg/" + Bg + ".png"));
            bgPanel = new JBackgroundPanel(bgImg, 1.0f, 0.5f);
            System.out.println("Image Was Successfully Loaded");


        return true;

    }catch(Exception ex) {

        System.out.println("IMAGE WITH ID " + Bg + " COULD NOT BE FOUND");
        ex.printStackTrace();
        return false;


    }

}


private void initComponents()   {

    this.reload();
    this.add(bgPanel);


}



}

现在您已经拥有了我可以提供的所有背景信息,让我们明白这一点。

我知道如果我创建新的JBackgroundPanels,或者甚至可能只调用this.loadBackground("IMAGE");(并在最后添加this.add(bgPanel);),据我所知,正在创建一个新的bgPanel实例,所以它没有还没有添加到GUI中,每次我们在更改状态后调用this.reload()方法时,它都会显示下一个图像。

所以我的问题是:它不会更好/更优化只是以某种方式更改图像,而不创建JBackgroundPanel的新实例?如果它是,或者不是,请解释(所以我可以理解我的逻辑是错误的还是正确的,因为对我来说这是最有意义的),你会怎么做呢? (即使它不是最佳的做法)

跑步课程可以在这里看到:

public class RunningClass {

public static void main(String[] argv)  {


    MainUI ui = new MainUI();


}

}

非常感谢!

0 个答案:

没有答案