正在从另一个类更新GUI



我正在使用NetBeans作为IDE,用Swing在Java中构建一个Snake and Ladders游戏。问题是,当我在另一个类的主类之外编写一个处理GUI某些方面的函数(例如,设置标签图标(时,应用程序会运行,但使用该函数中的代码必须进行的更改不适用。

import javax.swing.JLabel;
import javax.swing.JOptionPane;
public class Game extends javax.swing.JFrame
{
protected javax.swing.JLabel diceLabel;
private static final Dice diceObj = new Dice();
protected int diceNumber;
private void dicePlayer1ButtonActionPerformed(java.awt.event.ActionEvent evt) {
diceObj.setDiceIMG(diceNumber);
}
public static void main(String args[]){
java.awt.EventQueue.invokeLater(new Runnable()
{
public void run()
{
new Game().setVisible(true);    
}
});
}
}
class Dice extends Game
{
public void setDiceIMG(int dice)
{
if(dice == 1)
{
diceLabel.setIcon(new javax.swing.ImageIcon("D:\dice\dice11.jpg"));
}
else if(dice == 2)
{
diceLabel.setIcon(new javax.swing.ImageIcon("D:\dice\dice22.jpg"));
}
else
{
diceLabel.setIcon(new javax.swing.ImageIcon("D:\dice\dice66.jpg"));
}
} 
}

如果我运行这个代码,图像不会被设置在标签上,但如果我在Game类中创建setDiceIMG函数,它就可以完美地工作。任何有关这方面的信息都会有所帮助。

MadProgrammer评论的基本解决方案或"新手方法"是将diceLabel的引用路径到Dice构造函数或setDiceIMG方法,如以下mre所示:

import java.awt.BorderLayout;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Random;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingConstants;
public class Game extends JFrame
{
protected JLabel diceLabel;
private final Dice diceObj; //should not be static
protected int diceNumber;
Game() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
diceLabel = new JLabel();
diceLabel.setHorizontalAlignment(SwingConstants.CENTER);
JButton changeIcon = new JButton("Change Icon");
changeIcon.addActionListener(e -> changeLabelIcon());
diceObj = new Dice(diceLabel); //path a reference of the lable to Dice
changeLabelIcon();
add(diceLabel, BorderLayout.NORTH);
add(changeIcon, BorderLayout.SOUTH);
pack();
}
private void changeLabelIcon() {
diceNumber = new Random().nextInt(3);
diceObj.setDiceIMG(diceNumber);
}
public static void main(String args[]){
java.awt.EventQueue.invokeLater(() -> new Game().setVisible(true));
}
}
class Dice //   no need to extend Game
{
//use web resources to make code mre
private static final String[] CIRCLES_64 = {
"https://cdn3.iconfinder.com/data/icons/softwaredemo/PNG/64x64/Circle_Green.png",
"https://cdn3.iconfinder.com/data/icons/softwaredemo/PNG/64x64/Circle_Red.png",
"https://cdn3.iconfinder.com/data/icons/softwaredemo/PNG/64x64/Circle_Yellow.png",
};
private final JLabel diceLabel;
Dice(JLabel diceLabel) {
this.diceLabel = diceLabel;
}
public void setDiceIMG(int dice)
{
try {
if(dice == 1)
{
diceLabel.setIcon(new ImageIcon(new URL(CIRCLES_64[0])));
}
else if(dice == 2)
{
diceLabel.setIcon(new ImageIcon(new URL(CIRCLES_64[1])));
}
else
{
diceLabel.setIcon(new ImageIcon(new URL(CIRCLES_64[2])));
}
} catch (MalformedURLException ex) {
ex.printStackTrace();
}
}
}

通过引入视图和Dice:之间共享的模型,可以实现更好的设计

public class Game extends JFrame
{
protected JLabel diceLabel;
private final Dice diceObj; //should not be static
private final DiceModel model;
Game() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
diceLabel = new JLabel();
diceLabel.setHorizontalAlignment(SwingConstants.CENTER);
JButton changeIcon = new JButton("Change Icon");
changeIcon.addActionListener(e -> changeLabelIcon());
model = new DiceModel(4);
diceObj = new Dice(model);
changeLabelIcon();
add(diceLabel, BorderLayout.NORTH);
add(changeIcon, BorderLayout.SOUTH);
pack();
}
private void changeLabelIcon() {
model.rollDice();
diceLabel.setIcon(new ImageIcon(diceObj.imageURL()));
}
public static void main(String args[]){
java.awt.EventQueue.invokeLater(() -> new Game().setVisible(true));
}
}
class DiceModel {
private int diceNumber;
private final int max;
private final Random rnd;
DiceModel(int max) {
this.max = max;
rnd = new Random();
diceNumber = 0;
}
void rollDice() {
diceNumber = rnd.nextInt(max+1);
}
int getDiceNumber(){
return diceNumber;
}
}
class Dice
{
//use web resources to make code mre
private static final String[] CIRCLES_64 = {
"https://cdn3.iconfinder.com/data/icons/softwaredemo/PNG/64x64/Circle_Green.png",
"https://cdn3.iconfinder.com/data/icons/softwaredemo/PNG/64x64/Circle_Red.png",
"https://cdn3.iconfinder.com/data/icons/softwaredemo/PNG/64x64/Circle_Yellow.png",
};
private final DiceModel model;
Dice(DiceModel model) {
this.model = model;
}
URL imageURL()
{
try {
if(model.getDiceNumber() <= CIRCLES_64.length && model.getDiceNumber() > 0)
return new URL(CIRCLES_64[model.getDiceNumber()-1]);
else
return new URL(CIRCLES_64[0]);
} catch (MalformedURLException ex) {
ex.printStackTrace();
}
return null;
}
}

下一个改进可能是重构代码,添加一个遵循MVC设计模式的控制器:

import java.awt.BorderLayout;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Random;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingConstants;
import javax.swing.event.ChangeListener;
public class Game //acts as game controller
{
Game() {
DiceModel model = new DiceModel();
View view = new View(model);
view.update();//initialize icon 
model.setListener(e->view.update());//respond to model changes 
view.setVisible(true);
}
public static void main(String args[]){
java.awt.EventQueue.invokeLater(() -> new Game());
}
}
class View{
private final JLabel diceLabel;
private final DiceModel model;
private final JFrame frame;
View(DiceModel model) {
this.model = model;
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
diceLabel = new JLabel();
diceLabel.setHorizontalAlignment(SwingConstants.CENTER);
JButton changeIcon = new JButton("Roll Dice");
changeIcon.addActionListener(e -> model.rollDice()); //change model 
frame.add(diceLabel, BorderLayout.NORTH);
frame.add(changeIcon, BorderLayout.SOUTH);
}
void setVisible(boolean visible){
frame.pack();
frame.setVisible(visible);
}
void update() { 
diceLabel.setIcon(new ImageIcon(model.imageURL()));
}
}
class DiceModel {
//use web resources to make code mre
private static final String[] CIRCLES_64 = {
"https://cdn3.iconfinder.com/data/icons/softwaredemo/PNG/64x64/Circle_Green.png",
"https://cdn3.iconfinder.com/data/icons/softwaredemo/PNG/64x64/Circle_Red.png",
"https://cdn3.iconfinder.com/data/icons/softwaredemo/PNG/64x64/Circle_Yellow.png",
"https://cdn3.iconfinder.com/data/icons/softwaredemo/PNG/64x64/Circle_Blue.png",
"https://cdn3.iconfinder.com/data/icons/softwaredemo/PNG/64x64/Circle_Orange.png",
"https://cdn3.iconfinder.com/data/icons/softwaredemo/PNG/64x64/Circle_Grey.png"
};
private int diceNumber;
private final Random rnd;
private ChangeListener listener;
DiceModel() {
rnd = new Random();
diceNumber = 0;
}
void rollDice() {
diceNumber = rnd.nextInt(CIRCLES_64.length);
notifyListener();
}
int getDiceNumber(){
return diceNumber;
}
void notifyListener(){
if(listener != null){
listener.stateChanged(null);
}
}
void setListener(ChangeListener listener) {
this.listener = listener;
}
URL imageURL()
{
try {
return new URL(CIRCLES_64[diceNumber]);
} catch (MalformedURLException ex) {
ex.printStackTrace();
}
return null;
}
}

在线运行。

您绝对可以使用(创建、引用(多个类中的Swing组件。一般来说,只有一个类包含"Hello world"以外的内容是非常不寻常的。

正确的方法是创建自己的专用组件(可能源自JPanel(,创建和管理自己的所有组件(比如对话框及其所有按钮和文本(。将它们专门用于显示数据也是非常好的,而任何逻辑、计算和IO都应该在单独的类中完成。阅读有关模型视图控制器的信息。一些复杂的Swing类,如JTable,已经通过这种方式实现了。

最新更新