接手项目时对方所提的需求,其实用javaweb来实现的话基本没有难度,但是要用Swing去实现这个功能,还是一件蛮棘手的事情,中间也遇到了好多衍生出来的问题,利用这篇博客做一个记录。 先上一张最后的效果图: 可以根据输入框中文字的改变生成不同的提示,并且
由于作业需要,编写了Nim游戏实现。有些地方不太严谨。 废话不多说直接上代码: MyFrame.Java import java.awt.Color;import java.awt.Container;import java.awt.Cursor;import java.awt.Desktop;import java.awt.Font;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.awt.event.MouseAdapter;import java.awt.event.MouseEvent;import java.awt.event.MouseListener;import java.io.File;import javax.swing.ImageIcon;import javax.swing.JButton;import javax.swing.JComboBox;import javax.swing.JFrame;import javax.swing.JLabel;import javax.swing.JOptionPane;import javax.swing.JPanel;import javax.swing.JScrollPane;import javax.swing.SwingUtilities;import javax.swing.UIManager;import javax.swing.border.LineBorder;import javax.swing.border.SoftBevelBorder;public class MyFrame extends JFrame implements ActionListener, MouseListener {
private static final long serialVersionUID = 1L; // 序列化,保持对象的唯一性
private JLabel manmachine; // 人机对战
private JLabel course; // 新手攻略
private JLabel about; // 关于
private JLabel ppt;
private Container container; // 内容层
private int ratio; // 难度系数
private int judge_total; // 记录总数
// 人机游戏所需要的组件
private JPanel main; // 主面板
private JLabel stack_label; // 堆数标签
private JComboBox stack; // 堆输入框
private JLabel max_label; // 每次拿的上限
private JLabel number_label; // 每堆的数量标签
private JComboBox number; // 每堆的数量
private JComboBox max; // 上限输入框
private JLabel total; // 总棋子数
private int total_number; // 总棋子数
private JButton start; // 开始按钮
private static Font font = new Font("Dialog", 0, 20); // 字体
private Color color = new Color(227, 212, 162); // 颜色
private int sstack; // 获取堆数
private int smax; // 获取上限
private int snumber; // 获取每堆的数量
private MyLabel[][] myLabel; // 棋子标签
private JButton carry; // 拿走按钮
private JLabel[] row; // 行标签
int carry_row; // 记录拿走的行数
private int select; // 记录每次选择的个数
private int[] remainder; // 剩余棋子
public MyFrame() {// 构造函数
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
System.err.println(e);
}
this.setSize(1000, 700); // 设置窗体大小
this.setLocationRelativeTo(null); // 设置窗体位置
this.setVisible(true); // 设置窗体可见
this.setTitle("Nim Game"); // 设置窗体标题
this.setResizable(false); // 设置窗体不可改变大小
this.setLayout(null); // 设置布局管理器为null
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 关闭窗体即退出程序
this.getContentPane().setBackground(color); // 设置背景颜色
container = this.getContentPane(); // 获得JFrame的内容层
init(); // 调用init函数,初始化界面
}
public void init() { // 首页的界面
container.removeAll();
container.repaint();
manmachine = new JLabel("人机对战");
manmachine.addMouseListener(this);
manmachine.setCursor(new Cursor(Cursor.HAND_CURSOR));
manmachine.setFont(font);
manmachine.setBounds(450, 150, 100, 50);
this.add(manmachine);
course = new JLabel("新手攻略");
course.addMouseListener(this);
course.setCursor(new Cursor(Cursor.HAND_CURSOR));
course.setFont(font);
course.setBounds(450, 250, 100, 50);
this.add(course);
ppt = new JLabel("观看PPT");
ppt.addMouseListener(this);
ppt.setCursor(new Cursor(Cursor.HAND_CURSOR));
ppt.setFont(font);
ppt.setBounds(450, 350, 100, 50);
ppt.addMouseListener(this);
this.add(ppt);
about = new JLabel("关于");
about.addMouseListener(this);
about.setCursor(new Cursor(Cursor.HAND_CURSOR));
about.setFont(font);
about.setBounds(470, 450, 100, 50);
this.add(about);
this.validate(); // 刷新内容层
}
public void Game() { // 人机游戏函数,创建UI界面
container.removeAll();
container.repaint();
container.setLayout(null);
final JLabel exit = new JLabel("返回首页");
exit.setFont(font);
exit.setBounds(0, 0, 87, 30);
this.add(exit);
exit.setBorder(new SoftBevelBorder(1, Color.white, Color.black));
exit.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
MyFrame.this.init();
}
public void mouseEntered(MouseEvent e) {
exit.setBorder(null);
exit.setBorder(new SoftBevelBorder(0, Color.white, Color.white));
}
public void mouseExited(MouseEvent e) {
exit.setBorder(null);
exit.setBorder(new SoftBevelBorder(1, Color.white, Color.black));
}
});
stack_label = new JLabel("堆数:");
stack_label.setFont(font);
stack_label.setBounds(100, 0, 60, 30);
this.add(stack_label);
stack = new JComboBox(new String[] { "1", "2", "3", "4", "5", "6", "7", "8", "9" });
stack.setFont(font);
stack.setFocusable(false);
stack.setBackground(color);
stack.setBounds(150, 3, 50, 25);
stack.addActionListener(this);
this.add(stack);
number_label = new JLabel("每堆数量:");
number_label.setFont(font);
number_label.setBounds(250, 0, 150, 30);
this.add(number_label);
number = new JComboBox(
new String[] { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15" });
number.setFont(font);
number.setFocusable(false);
number.setBackground(color);
number.setBounds(340, 3, 50, 26);
this.add(number);
max_label = new JLabel("每次拿取数量的上限:");
max_label.setFont(font);
max_label.setBounds(450, 0, 200, 30);
this.add(max_label);
max = new JComboBox(new String[] { "1", "2", "3", "4", "5", "6" });
max.setFont(font);
max.setFocusable(false);
max.setBackground(color);
max.setBounds(640, 3, 50, 26);
this.add(max);
start = new JButton("开始");
start.addActionListener(this);
start.setFocusable(false);
start.setBackground(color);
start.setBorder(new LineBorder(color, 0));
start.setFont(font);
start.setBounds(720, 3, 70, 28);
this.add(start);
total = new JLabel("剩余棋子:0");
total.setFont(font);
total.setBounds(50, 60, 200, 50);
this.add(total);
carry = new JButton("拿走");
carry.addActionListener(this);
carry.setFocusable(false);
carry.setBackground(color);
carry.setBorder(new LineBorder(color, 0));
carry.setFont(font);
carry.setBounds(880, 70, 70, 28);
this.add(carry);
main = new JPanel(null);
main.setBackground(color);
JScrollPane mainjsp = new JScrollPane(main);
mainjsp.setBounds(50, 100, 900, 500);
mainjsp.setBorder(new LineBorder(Color.black, 0));
mainjsp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
this.add(mainjsp);
this.validate(); // 刷新UI
}
@Override
public void actionPerformed(ActionEvent e) { // 动作监听函数
if (e.getSource() == stack) { // 监听堆
int index = stack.getSelectedIndex();
if (index == 0) {
max_label.setVisible(true);
max.setVisible(true);
} else {
max_label.setVisible(false);
max.setVisible(false);
}
} else if (e.getSource() == start) {// 如果点击了开始按钮
Object[] options = { "容易", "一般", "困难" }; // 选择的难度系数
int response = JOptionPane.showOptionDialog(MyFrame.this, "请选择难度?", "提醒", JOptionPane.YES_NO_CANCEL_OPTION,
JOptionPane.QUESTION_MESSAGE, null, options, options[0]);
if (response == 0 || response == 1 || response == 2) { // 如果做了选择
ratio = response; // 难度系数
start();
}
} else if (e.getSource() == carry) { // 如果点击了拿走按钮
int select_row = -1;
if (myLabel == null) {
JOptionPane.showMessageDialog(MyFrame.this, "请开始游戏", "提示", JOptionPane.CLOSED_OPTION);
return;
}
for (int i = 0; i < myLabel.length; i++) {
for (int j = 0; j < myLabel[i].length; j++) {
if (myLabel[i][j].status == 1) {
if (select_row == -1)
select_row = i; // 定位到第i行
if (select_row != i) { // 如果跨行
JOptionPane.showMessageDialog(MyFrame.this, "选择的棋子不能不在同一行", "提示",
JOptionPane.CLOSED_OPTION);
return;
}
}
}
}
if (select_row == -1)
return;
for (int i = 0; i < myLabel[select_row].length; i++) { // 得到选择的那行
int status = myLabel[select_row][i].status;
if (status == 1) {
ImageIcon iamgeIcon = new ImageIcon("image/black.gif");
myLabel[select_row][i].setIcon(iamgeIcon);
myLabel[select_row][i].status = 2;
}
}
total_number -= select;
total.setText("剩余棋子:" + total_number);
remainder[select_row] -= select;
row[select_row].setText("第" + (select_row + 1) + "行剩余:" + remainder[select_row]);
select = 0;
if (total_number == 0) {
JOptionPane.showMessageDialog(MyFrame.this, "您赢了", "提示", JOptionPane.CLOSED_OPTION);
return;
}
new Thread(new Runnable() {
public void run() {
try {
Thread.sleep(1000);
MyFrame.this.Judge();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
public void Judge() { // 判断难度系数
double rand = Math.random(); // 产生随机数
if (ratio == 0) { // 如果难度系数为容易的时候
if (rand < 0.2) { // 如果产生的随机数小于0.2,则采用最佳策略
Computer();
return;
}
} else if (ratio == 1) {// 如果难度系数为普通
if (rand < 0.4) { // 如果产生的随机数小于0.2,则采用最佳策略
Computer();
return;
}
} else if (ratio == 2) {// 如果难度系数为困难
if (rand < 0.8) {// 如果产生的随机数小于0.8,则采用最佳策略
Computer();
return;
}
}
Bad(); // 如果没有采用最佳策略,则采用随机策略
}
public void Bad() { // 没有胜手的时候,就随机的走
int ln = (int) (Math.random() * 100) % sstack;
int circle = 0;
while (remainder[ln] == 0 && circle < 1000) {
ln = (int) (Math.random() * 100) % sstack;
circle++;
}
if (remainder[ln] == 0) {
JOptionPane.showMessageDialog(MyFrame.this, "您赢了", "提示", JOptionPane.CLOSED_OPTION);
return;
}
int cn = (int) (Math.random() * 100) % remainder[ln] + 1;
if (remainder.length =(原创) 测试代码,解决java gui swing多线程界面假死、僵死问题,实现界面动态刷新,动态更新,同步显示数据 主类: package testguimulitiplethread; /** * * @author Administrator */ public class Main {
/**
* @param args the command line= 1)
cn = (int) (Math.random() * 100) % smax + 1;
for (int i = 0, j = 0; i < snumber; i++) {
if (j >= cn)
break;
if (myLabel[ln][i].status == 0) {
myLabel[ln][i].status = 2;
ImageIcon imageIcon = new ImageIcon("image/black.gif");
myLabel[ln][i].setIcon(imageIcon);
j++;
}
}
remainder[ln] -= cn; // 减少数量
total_number -= cn; // 减少数量
total.setText("剩余棋子:" + total_number);
row[ln].setText("第" + (ln + 1) + "行剩余:" + remainder[ln]);
if (total_number == 0) {
JOptionPane.showMessageDialog(MyFrame.this, "真是遗憾,电脑赢了", "提示", JOptionPane.CLOSED_OPTION);
}
return;
}
public void Computer() { // 计算机行动
int result = 0;
for (int i = 0; i < remainder.length; i++) {
result ^= remainder[i]; // 得到剩余棋子异或的值
}
int high = 0; // 最高位
int temp = result;
int ln = 0; // 最佳策略的堆号
int cn = 0; // 最佳策略对应的数量
while (temp != 0) { // 找到result二进制最高位的位数high
temp /= 2;
high++;
}
if (result == 0) { // 如果没有胜手,则随机产生一个数字
Bad();
return;
}
// 让剩下的异或值为0,得到最佳策略
for (int i = 0; i < remainder.length; i++) {
String com = Integer.toBinaryString(remainder[i]);
char[] chars = com.toCharArray();
if (chars.length >= high) {
if (chars[chars.length - high] == '1') {// 如果high位为1
ln = i; // 堆号
cn = remainder[ln] - (remainder[ln] ^ result); // 数量
break;
}
}
}
if (sstack == 1) {// 如果堆数为1
ln = 0;
cn = remainder[ln] % (smax + 1);
if (cn == 0)
cn = (int) (Math.random() * 100) % smax + 1;
}
// 改变标签的内容
remainder[ln] -= cn; // 减少数量
total_number -= cn; // 减少数量
total.setText("剩余棋子:" + total_number);
row[ln].setText("第" + (ln + 1) + "行剩余:" + remainder[ln]);
// 改变第ln行的状态
for (int j = 0; j < myLabel[ln].length; j++) {
if (cn > 0) {
if (myLabel[ln][j].status == 0) { // 如果该棋子未被拿掉
ImageIcon imageIcon = new ImageIcon("image/black.gif");
myLabel[ln][j].setIcon(imageIcon);
myLabel[ln][j].status = 2;
cn--;
}
}
}
if (total_number == 0) {
JOptionPane.showMessageDialog(MyFrame.this, "真是遗憾,电脑赢了", "提示", JOptionPane.CLOSED_OPTION);
}
}
public void startGame() { // 开始游戏
select = 0;
remainder = new int[sstack];
for (int i = 0; i < remainder.length; i++) {
remainder[i] = snumber; // 剩余棋子
}
total_number = snumber * sstack;
judge_total = total_number;
total.setText("剩余棋子:" + total_number);
if (sstack != 1)
smax = snumber;
row = new JLabel[sstack];
myLabel = new MyLabel[sstack][snumber];
int x = 50, y = 30;
for (int i = 0; i < sstack; i++) {
row[i] = new JLabel("第" + (i + 1) + "行剩余:" + remainder[i]);
row[i].setFont(font);
row[i].setBounds(x, y, 150, 30);
main.add(row[i]);
x = 200;
for (int j = 0; j < snumber; j++) {
myLabel[i][j] = new MyLabel();
myLabel[i][j].setBounds(x, y, 30, 30);
x += 40;
main.add(myLabel[i][j]);
final int tempi = i, tempj = j;
myLabel[i][j].addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
int status = myLabel[tempi][tempj].status;
if (status == 0) {
if (select < smax) {
ImageIcon imageIcon = new ImageIcon("image/yellow.gif");
myLabel[tempi][tempj].setIcon(imageIcon);
myLabel[tempi][tempj].status = 1;
select++;
}
} else if (status == 1) {
ImageIcon imageIcon = new ImageIcon("image/white.gif");
myLabel[tempi][tempj].setIcon(imageIcon);
myLabel[tempi][tempj].status = 0;
select--;
}
}
});
}
x = 50;
y += 50;
}
}
public void start() { // 开始游戏的函数
sstack = Integer.valueOf(stack.getSelectedItem().toString());
smax = Integer.valueOf(max.getSelectedItem().toString());
snumber = Integer.valueOf(number.getSelectedItem().toString());
new Thread(new Runnable() {
public void run() {
// 创建新的线程,用于改变UI
SwingUtilities.invokeLater(new Runnable() {
public void run() {
main.removeAll();
main.updateUI();
main.repaint();
startGame();
}
});
}
}).start(); // 开启游戏
}
public void Course() {
container.removeAll(); // 去除内容
container.repaint();
container.setLayout(null); // 设置为null布局
JLabel title = new JLabel("●游戏规则");
title.setFont(font);
title.setBounds(200, 100, 100, 20);
this.add(title);
JLabel content = new JLabel(
"
你与电脑玩游戏,你每次能拿若干个棋子(至少一个),要求所拿棋子不能跨行。谁拿走最后一颗棋子即获胜。");
content.setFont(new Font("Dialog", 0, 14));
content.setBounds(200, 120, 1000, 100);
this.add(content);
JLabel tips = new JLabel("●温馨提示");
tips.setFont(font);
tips.setBounds(200, 250, 100, 20);
this.add(tips);
JLabel tip = new JLabel("
只要剩余棋子的个数异或值不为0,则存在胜手;若异或值为0,则不存在胜手。");
tip.setFont(new Font("Dialog", 0, 14));
tip.setBounds(200, 270, 1000, 100);
this.add(tip);
JLabel tip1 = new JLabel(
"
旁边剩余棋子分别是3、4、5。3 ^ 4 ^ 5 = 2,不为0,说明存在胜手。而胜手即为让剩余的异或值为0");
tip1.setFont(new Font("Dialog", 0, 14));
tip1.setBounds(200, 400, 1000, 100);
this.add(tip1);
final JLabel startGame = new JLabel("开始游戏");
startGame.setFont(font);
startGame.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
MyFrame.this.Game();
}
public void mouseEntered(MouseEvent e) {
startGame.setBorder(null);
startGame.setBorder(new SoftBevelBorder(0, Color.white, Color.white));
}
public void mouseExited(MouseEvent e) {
startGame.setBorder(null);
startGame.setBorder(new SoftBevelBorder(1, Color.white, Color.black));
}
});
startGame.setBorder(new SoftBevelBorder(1, Color.white, Color.black));
startGame.setBounds(200, 520, 87, 30);
this.add(startGame);
final JLabel exit = new JLabel("返回首页");
exit.setFont(font);
exit.setBounds(400, 520, 87, 30);
this.add(exit);
exit.setBorder(new SoftBevelBorder(1, Color.white, Color.black));
exit.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
MyFrame.this.init();
}
public void mouseEntered(MouseEvent e) {
exit.setBorder(null);
exit.setBorder(new SoftBevelBorder(0, Color.white, Color.white));
}
public void mouseExited(MouseEvent e) {
exit.setBorder(null);
exit.setBorder(new SoftBevelBorder(1, Color.white, Color.black));
}
});
MyLabel[][] my = new MyLabel[3][];
int j = 3;
for (int i = 0; i < my.length; i++) {
my[i] = new MyLabel[j++];
}
int x = 650, y = 150;
for (int i = 0; i < my.length; i++) {
for (j = 0; j < my[i].length; j++) {
my[i][j] = new MyLabel();
my[i][j].setBounds(x, y, 30, 30);
this.add(my[i][j]);
this.validate();
x += 40;
}
x = 650;
y += 80;
}
this.validate();
}
@Override
public void mouseEntered(MouseEvent e) {
} 这里写代码片
@Override
public void mouseExited(MouseEvent e) {
}
@Override
public void mousePressed(MouseEvent e) {
if (e.getSource() == manmachine) {
MyFrame.this.Game();
} else if (e.getSource() == about) {
JOptionPane.showMessageDialog(MyFrame.this, "\t\t\t\t版本:V1.0\n\t\t\t\t请期待下一次更新\n\t\t\t\t© Right By Aiden\n",
"提示", JOptionPane.CLOSED_OPTION);
} else if (e.getSource() == course) {
Course();
} else if (e.getSource() == ppt) {
try {
Desktop desktop = Desktop.getDesktop();
File file = new File("D:\\Aiden\\学习\\大三上\\算法\\汇报PPT\\Nim游戏.pptx");
desktop.open(file);
} catch (Exception e1) {
e1.printStackTrace();
}
}
}
@Override
public void mouseReleased(MouseEvent e) {
}
@Override
public void mouseClicked(MouseEvent e) {
}} Main.java import java.io.IOException;public class Main {
private static void createAndShowGUI() throws IOException {
new MyFrame(); // 新建MyFrame窗体
}
public static void main(String[] args) {
// UI线程安全
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
createAndShowGUI();
} catch (IOException e) {
e.printStackTrace();
}
}
});
}} MyLabel.java import java.awt.Cursor;import java.awt.Dimension;import javax.swing.ImageIcon;import javax.swing.JLabel;// 自定义标签,用于加载图片public class MyLabel extends JLabel {
public int status; // 标记状态
private static final long serialVersionUID = 1L; // 序列化,保持对象的唯一性
public MyLabel() {// 构造函数
status = 0;
ImageIcon imageIcon = new ImageIcon("image/white.gif");
this.setIcon(imageIcon);
this.setCursor((new Cursor(Cursor.HAND_CURSOR)));
this.setPreferredSize(new Dimension(30, 30));
// this.setBorder(new LineBorder(new Color(227, 212, 162), 0));
}
public void setImage(int i) {
if (i == 0) {
status = 0;
ImageIcon imageIcon = new ImageIcon("image/white.gif");
this.setIcon(imageIcon);
} else if (i == 1) {
status = 1;
ImageIcon imageIcon = new ImageIcon("image/yellow.gif");
this.setIcon(imageIcon);
} else if (i == 2) {
status = 2;
ImageIcon imageIcon = new ImageIcon("image/black.gif");
this.setIcon(imageIcon);
}
}} 源码下载地址如下:下载地址