界面开发是软件开发中的一项重要工作,且界面可以作为计算机用户和计算机系统交互的接口,我们以画一个五子棋界面为例,给出具体的开发过程和相关代码。整篇文章分成两个部分,第一部分介绍五子棋界面的绘制;第二部分介绍一些界面上常用的组件。
假设说我们是一个刚入门的小白,对 JAVA 并不熟悉,但是又想开发一个五子棋程序,那只需要抓住核心部分代码 即可,首先 new 一个 class,我们把他命名为 FiveChessUI:
import java.awt.FlowLayout;
import java.awt.Graphics;
import javax.swing.JFrame;
public class FiveChessUI implements Config{
public static void main(String[] args) {
new FiveChessUI().initUI();
}
public void initUI() {
MyFrame jf=new MyFrame();
jf.setSize(2*X0+SIZE*(LINE-1),Y0+X0+SIZE*(LINE-1)); //设置尺寸
jf.setTitle("五子棋-创意画板"); //设置标题
jf.setLocationRelativeTo(null); //设置居中
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //设置关闭进程
FlowLayout flow = new FlowLayout(); //布局方式为流式布局
jf.setLayout(flow);
jf.setVisible(true); //设置窗体可见
//this 表示当前类的对象
Graphics gr=jf.getGraphics();
System.out.println("gr = "+gr);
DrawQZ mouse=new DrawQZ();
jf.addMouseListener(mouse);
mouse.g = gr;
jf.css=mouse.css;
}
}
在上述代码中,我们注意到 implements 了一个接口 Config,其主要目的是为了实现软编码,通俗的说,就是为了方便修改代码中的相关参数,例如:需要修改五子棋棋盘的大小,棋盘的起始位置,棋子的大小时,都可以在 Config 类中修改,Config 类中的代码如下:
public interface Config {
public static final int X0=50;
public static final int Y0=100;
public static final int SIZE=50;
public static final int LINE=15;
public static final int CHESS=50;
}
有了这个 Config 类,如果需要修改相关参数就变得容易了很多,不必到涉及该参数的每一个类中去修改。
为了后期能够在棋盘上相应位置点击就能下棋子,即在点击处画一个黑色或者白色的实心圆,我们需要加一个监听器类:
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class DrawQZ extends MouseAdapter implements Config{
public Graphics g = null;
public int count = 0;
public QiZi[] css = new QiZi[LINE*LINE];
public int index,m,n;
public String name = "";
boolean flag = true;
public void mouseReleased(MouseEvent e) {
int x = e.getX();
int y = e.getY();
if(count%2 == 1) {
name = "黑子";
}
else {
name = "白子";
}
if ((x > (X0 - SIZE / 2)) && (x < (X0 - SIZE / 2 + SIZE * LINE)) &&
(y > (Y0 - SIZE / 2)) && (y < (Y0 - SIZE / 2 + SIZE * LINE))) {
m = (x - X0 + SIZE / 2) / SIZE;
n = (y - Y0 + SIZE / 2) / SIZE;
QiZi qz = new QiZi();
qz.name = name;
qz.x = m*SIZE + X0 - SIZE/2;
qz.y = n*SIZE + Y0 - SIZE/2;
css[index++] = qz;
qz.drawqz(g);
count++;
}else {
System.out.println("点击超出范围");
}
}
}
在上述监听器类中,通过 getX 和 getY 获得鼠标点击位置的坐标,并用 count 来计数,如 count 为奇数时,下黑子,count 为偶数时,下白子;
由于在下棋过程中,点击位置可能不在棋盘线的交点处,因此需要对点击位置做处理,使棋子落到合适的位置上;
同时,在五子棋界面改变大小或者最小化时,由于会重新调用 paint 函数,即重绘,我们希望棋子和棋盘在重绘之后仍然原封不动显示在界面上,那么需要把棋谱每一条线的参数和棋子的位置记录下来,因此创建了一个数组 css ,把棋子的颜色颜色位置都记录下来,并重写 paint 函数:
import java.awt.Graphics;
import javax.swing.JFrame;
public class MyFrame extends JFrame implements Config{
public QiZi[] css;
public void paint(Graphics gr) {
super.paint(gr);
drawChessTable(gr);
System.out.println("size = "+css.length);
for(int i=0;i
到目前为止,看似一切都写的差不多了,但还缺少一个重要的部分,我们在上面代码中多次提到了 drawqz 函数,但该函数我们还没有具体写明:
import java.awt.Color;
import java.awt.Graphics;
public class QiZi implements Config{
public int x,y;
public String name="";
public void drawqz(Graphics gr) {
switch(name) {
case"黑子":
gr.setColor(Color.BLACK);
gr.fillOval(x, y, CHESS, CHESS);
break;
case"白子":
gr.setColor(Color.WHITE);
gr.fillOval(x, y, CHESS, CHESS);
break;
}
}
}
把上述代码放在一个包下运行后的效果如下图:
一个五子棋的界面就做好啦,当然,如果要真正想实现完善五子棋这个小游戏,还需加上输赢判断,悔棋,人机模式等功能,这些功能会在下一篇文章具体描述,下面介绍几个界面中常用的组件:
简简单单一个空白界面看上去显得有点单调,且无法实现需要的功能,当在开发其他功能的界面时,可能需要用到一些组件,例如,加几个按钮,代码如下:
private void addButton(MyFrame jf, ActionListener al) {
String[] btnstrs = new String[]{"开始游戏","重新开始","认输结束","悔棋一步",
" 模式 ","人人对战","人机对战"," 颜色 ","我要黑棋","我要白棋",
" 顺序 ","黑棋先行","白棋先行"};
for (int i = 0; i < btnstrs.length; i++){
JButton btn = new JButton(btnstrs[i]);
Dimension dim = new Dimension(120,40);
btn.setPreferredSize(dim);
btn.setFont(new Font("黑体",1,20));
btn.setBackground(Color.WHITE);
btn.addActionListener(al);
jf.add(btn);
}
}
在上述代码中,依次将 btnstrs 数组中相关名字的按钮添加到了界面上,同时设置了按钮的尺寸大小,按钮中的字体类型、大小,以及按钮的背景色,然后,给按钮添加了监听器ActionListener,最重要的是,在最后的最后,一定要把按钮添加到窗体上,即 jf.add(btn); 如果缺少最后这行代码,按钮将不会显示出来。
当然,上述代码创建出来的按钮是一个紧挨着一个的,但如果有强迫症的伙伴看了可能想把按钮之间的距离调大一点,那么,在按钮之间添加一个空的标签就可以了,代码如下:
JLabel j0 = new JLabel(" ");
jf.add(j0);
再进一步,在有的窗体上,如果想创建一个滑块,并且可以实时获得滑块的值,那么可以写如下的代码:
public void creatJSlider(MyFrame jf) {
jSlider = new JSlider(0,100);
Dimension dm = new Dimension(600,80); //设置按钮尺寸
jSlider.setPreferredSize (dm);
jSlider.setFont (new Font ("黑体",1,15));
jSlider.setMajorTickSpacing(20);
jSlider.setMinorTickSpacing(5);
jSlider.setPaintLabels(true);//确定是否在滑块上绘制标签
jSlider.setPaintTicks(true);//确定是否在滑块上绘制刻度标记
jSlider.setPaintTrack(true);//确定是否在滑块上绘制滑道
jSlider.setSnapToTicks(true);//指定为 true,则滑块(及其所表示的值)解析为最靠近用户放置滑块处的刻度标记的值
jSlider.setOpaque(false);
jf.add(jSlider);
jSlider.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
System.out.println("当前值: " + jSlider.getValue());
p = jSlider.getValue();
System.out.println("p= " + p);
}
});
}
上述代码便可将滑块上的值实时显示出来了。
在上述的五子棋代码中,我们把所有的按钮等组件,以及需要绘制的图形都放在了一个 JFrame 里,难以管理,那么可以在这个 JFrame 里放几个 JPanel ,把绘图区和按钮放到不同的 jps 里,即把各个功能区分开来:
private JPanel[] addPanel(JFrame jf) {
JPanel[] jps = new JPanel[2];
String[] layoustrs = {BorderLayout.CENTER,BorderLayout.EAST};
imgPanel.setBackground(Color.LIGHT_GRAY);
jf.add(imgPanel,layoustrs[0]);
jps[0] = imgPanel;
Dimension dim = new Dimension(200,0);
JPanel jp_s = new JPanel();
jp_s.setBackground(Color.ORANGE);
jp_s.setPreferredSize(dim);
jf.add(jp_s,layoustrs[1]);
jps[1] = jp_s;
return jps;
}