前言:本来想这次就把地图导入还有输出就直接做掉的,但是自己起床晚了,后来想想反正JMenu还没说呢,索性就这次添加一个中间的项目,把JMenu加上,不过也没多少内容。上一篇里说道我们要研究下这个地图存储的格式问题的。其实个人感觉考虑哈夫曼(Huffman)树是最好的解决方案,但是对于没有学过《数据结构》的人来说单单这个问题要讲透搞懂就要好久 时间,而且还要专门写关于Huffman的类,而且自己也有点懒惰,嘿嘿。所以这里就用一个简单的方法来说明。这次加图片说明,嘿嘿(做了很烂望包含),好了,说了这么多,看思路吧。
其实一个地图编辑器少不了的就是些添加修改地图的功能,当然最好不要都直接做到按钮去,这样整个程序界面估计会给JButton给占据掉的,所以一个菜单还是必不可少的。这次就讲讲JMenuBar,JMenu和它的Item:JMenuItem。
JMenu,从字面意思就直到是菜单控件,以前做MFC的肯定知道ToolBar,也就是工具栏咯,那么这里的JMenuBar就是菜单栏了,而JMenu是其中的菜单项,而JMenuItem是点击JMenu后的下拉菜单项,那么到底是什么效果呢?
看到了吧,这个就是整个菜单栏,“文件”和“编辑”这两个是JMenu控检,而“载入地图”和“退出”是JMenuItem控件,而有JMenu所在的整个横条就是JMenuBar了,呵呵。
JMenuItem也有其addActionListener的注册方法,而且在响应函数中和JButton的做法和效果是一致的,所以可以看到退出其实可以和下面的OK的JButton响应为同一个System.exit(0)。
下面讲讲具体的添加方法。首先定义一个JMenu,一个JMenuItem,一个JMenuBar,这样是最简陋的,调用JMenu的add方法,把这个JMenuItem加进去,然后再调用JMenuBar的add方法把这个JMenu加进去,最后调用JFrame的setMenuBar(JMenuBar的实例)就可以了。代码最后公布。
现在讲讲地图的问题。我是用Jcreatro Pro做的,而且建立了一个工程,其实没关系的,你用记事本也一样,大不了全编译过来然后对总的class文件进行运行就行了,没什么本质区别。所以下面我的代码是分蛮多java文件的,但是只要你放在同一个文件夹下就没什么问题。
首先讲下下我自己的思路吧,有建议的朋友快M我,不然我就真的照着这个自己的思路发展下去了咯。因为考虑到地形一般不会多于50个,所以用字母就可以表示52个地形,那地图文件里面就都是些字母了,呵呵。(其实这个是手工写地图要考虑的问题,用地图编辑器就不需要知道到底地图文件是怎么表示的)为此我们需要一个放地图图片的数组,还有一个记录地图信息的数据结构。本着OO的思想,我为他们分别做了两个类,一个叫LandStylePic,一个叫MapsConstruction。
先说说MapsConstruction类。它有四个成员变量:
private
int
index;
//
在LandStyle中的地图样式
private
char
mapsMark;
//
存储或者读取时所表示的字符
private
String landStyleName;
//
地形的名字
private
String info;
//
对此地形的描述信息
还有四个方法,分别取得这四个属性:getIndex(),getName(),getInfo(),getMark()。
注意:其实这个(MapsConstruction)可以作为LandStylePic的内部类,本来就是给LandStylePic定义的数据结构。不过为了代码的测试性,我还是分开了他们。
下面给出MapsConstruction的代码:
/** */
/**
* 一个地形存储识别的类
**/
public
class
MapsConstruction
...
{
private int index; // 在LandStyle中的地图样式
private char mapsMark; // 存储或者读取时所表示的字符
private String landStyleName; // 地形的名字
private String info; // 对此地形的描述信息
/** *//**
* Method main
*
*
* @param args
*
*/
public static void main(String[] args) ...{
// TODO: 在这添加你的代码
}
/** *//**
* Method MapsConstruction
*
* @param index, mapsMark, name, info
*
*/
public MapsConstruction(int index, char mapsMark, String name, String info) ...{
// TODO: 在这添加你的代码
this.index = index;
this.mapsMark = mapsMark;
this.landStyleName = name;
this.info = info;
}
/** *//**
* Method getIndex
*
*
* @return
*
*/
public int getIndex() ...{
// TODO: 在这添加你的代码
return index;
}
/** *//**
* Method getMarks
*
*
* @return
*
*/
public char getMarks() ...{
// TODO: 在这添加你的代码
return mapsMark;
}
/** *//**
* Method getName
*
*
* @return
*
*/
public String getName() ...{
// TODO: 在这添加你的代码
return this.landStyleName;
}
/** *//**
* Method getInfo
*
*
* @return
*
*/
public String getInfo() ...{
// TODO: 在这添加你的代码
return this.info;
}
}
LandStylePic中有一个静态的ImageIcon数组,负责存储外部的地图文件。其中有专门负责存储相应的地图信息的MapsConstruction数组,以及两个getIndex的查询方法(考虑到数组不会太大,所以就逐个比较吧),分别对应对地图名字和地图的表示符号的查询返回对应的ImageIcon,前者在手动编辑地图时用到,后者则在读入地图文件以及输出地图文件时极为有用!给出代码
/** */
/**
* 记录地图类型存储的类
*
**/
import
javax.swing.ImageIcon;
import
java.util.
*
;
public
final
class
LandStylePic
...
{
// 存放地形图形的数组
public final static ImageIcon[] LANDSTYLES = ...{
new ImageIcon("../mapResource/water/water_left.PNG"),
new ImageIcon("../mapResource/water/water_middle.PNG"),
new ImageIcon("../mapResource/water/water_right.PNG"),
new ImageIcon("../mapResource/water/water_blue.PNG"),
};
// 存放地形相关信息的数据结构的数组
public final static MapsConstruction[] MAPCONS = ...{
new MapsConstruction(0, 'A', "water_left",
"水地形的左边部分,两栖物种以及飞行物种可登陆"),
new MapsConstruction(1, 'B', "water_middle",
"水地形的中间部分,两栖物种以及飞行物种可登陆"),
new MapsConstruction(2, 'C', "water_right",
"水地形的右边部分,两栖物种以及飞行物种可登陆"),
new MapsConstruction(3, 'D', "water_blue",
"水地形的反光部分,两栖物种以及飞行物种可登陆"),
};
/** *//**
* Method main
*
*
* @param args
*
*/
public static void main(String[] args) ...{
// TODO: 在这添加你的代码
}
/** *//**
* Method getIndex
*
*
* @param name
*
* @return
*
*/
public static int getIndex(String name) ...{
// TODO: 在这添加你的代码
for(int i = 0; i < MAPCONS.length; i++) ...{
if( name.equals( MAPCONS[i].getName() ) )
...{
return MAPCONS[i].getIndex();
}
}
return -1;
}
/** *//**
* Method getIndex
*
*
* @param mark
*
* @return
*
*/
public static int getIndex(char mark) ...{
// TODO: 在这添加你的代码
for(int i = 0; i < MAPCONS.length; i++) ...{
if ( mark == MAPCONS[i].getMarks() ) ...{
return MAPCONS[i].getIndex();
}
}
return -1;
}
}
注意到LANDSTYLES和MAPCON这两个数组是一一对应的,MAPCON的getIndex所得到的就是在LANDSTYLES中的索引。这个文件要自己手动添加。
好了,最后给出主程序的代码。分两个文件,一个是Frame,而另一个是调用这个Frame并且显示,完全可以放到一起来做的。里面的东西大家就自己分析分析看看,然后自己写一个出来,嘿嘿。很有意思的哟~
e.g. :
import
java.awt.
*
;
import
java.awt.event.
*
;
import
javax.swing.
*
;
import
java.util.
*
;
/** */
/**
* Sample application using JFrame.
*
* @author SosoAyaen
* @version 1.00 06/08/10
*/
public
class
MapsEditorFrame
extends
JFrame
implements
ActionListener
...
{
// 容器组件等
private JButton jbOK = null, jbCancel = null, jbIcon = null,
jbSave = null, jbLoadMapFromFile = null;
private JPanel jpCenter = null, jpIcon = null, jpSouth = null,
jpNorth = null, jpEast = null, jpEastCo = null;
private JLabel jlMap = null, jlTitle = null, jlTips = null;
private JMenu jmenu = null;
private JMenuItem jmiExit = null;
private JMenuBar jmb = null;
private JTextField jtf = null;
private int change = 1; // 控制点击同一按钮后控制不同控件
// 临时测试用的地图文件数组
private char[] maps = ...{
'A', 'B', 'C', 'A', 'A', 'A', 'D', 'D', 'B', 'D',
};
// 随机数
private Random rand = new Random();
private final int WIDTH = 12, HEIGHT = 4;
// private Dimension d = null;
/** *//**
* The constructor.
*/
public MapsEditorFrame (String title) ...{
super(title);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// d = new Dimension(11, 20);
// JMenu
JMenu jmFile = new JMenu("文件");
// 临时定义组件
JMenuItem jmiLoad = new JMenuItem("载入地图");
jmiLoad.addActionListener(this);
jmFile.add(jmiLoad);
jmiExit = new JMenuItem("退出");
jmiExit.addActionListener(this);
jmFile.add(jmiExit);
JMenu jmEdit = new JMenu("编辑");
JMenuItem jmiUndo = new JMenuItem("撤销");
jmEdit.add(jmiUndo);
// JMenuBar
jmb = new JMenuBar();
jmb.add(jmFile);
jmb.add(jmEdit);
this.setJMenuBar(jmb);
// JTextField
jtf = new JTextField(10);
jtf.setEditable(false);
// JLabel
// jlMap = new JLabel(mapsWater[0]);
jlTitle = new JLabel("SLG地图编辑器");
jlTips = new JLabel();
// JButton
jbLoadMapFromFile = new JButton("Load Maps");
jbLoadMapFromFile.addActionListener(this);
jbSave = new JButton("Save Maps");
jbSave.addActionListener(this);
jbOK = new JButton("OK");
// jbOK.setMaximumSize(new Dimension(6, 12));
jbOK.addActionListener(this);
// jbOK.setSize(d);
jbCancel = new JButton("Cancel");
jbCancel.setEnabled(false);
jbIcon = new JButton("WaterMiddle",
LandStylePic.LANDSTYLES[LandStylePic.getIndex("water_right")]);
// JPanel
jpSouth = new JPanel(new FlowLayout());
jpSouth.add(jbOK);
jpSouth.add(jbCancel);
jpNorth = new JPanel(new FlowLayout());
jpNorth.add(jlTitle);
jpEast = new JPanel(new GridLayout(0,1));
jpEastCo = new JPanel(new FlowLayout());
jpEastCo.add(jbIcon);
jpEast.add(jpEastCo);
jpEastCo = new JPanel(new FlowLayout());
jpEastCo.add(jbSave);
jpEast.add(jpEastCo);
jpEastCo = new JPanel(new FlowLayout());
jpEastCo.add(jbLoadMapFromFile);
jpEast.add(jpEastCo);
jpEastCo = new JPanel(new FlowLayout());
jpEastCo.add(jtf);
jpEast.add(jpEastCo);
jpEastCo = new JPanel(new FlowLayout());
jpEastCo.add(jlTips);
jpEast.add(jpEastCo);
jpIcon = new JPanel(new GridLayout(HEIGHT,WIDTH,0,0));
/**//*
for(int i = 0, j = 0; i<HEIGHT*WIDTH; i++)
{
j = rand.nextInt(4);
jlMap = new JLabel(LandStylePic.LANDSTYLES[j]);
jpIcon.add(jlMap);
}
//*/
// 按数组内容添加地图图片
for (int i = 0; i < 10; i++) ...{
jlMap = new JLabel( LandStylePic.LANDSTYLES[LandStylePic.getIndex(maps[i])] );
jpIcon.add(jlMap);
}
// 保证jpIcon内的JLabel不会因为外部窗口的拉伸而走样
jpCenter = new JPanel(new FlowLayout());
jpCenter.add(jpIcon);
// JFrame
this.setLayout(new BorderLayout());
this.setSize(500, 400);
this.setResizable(false);
this.add(BorderLayout.NORTH, jpNorth);
this.add(BorderLayout.SOUTH, jpSouth);
this.add(BorderLayout.CENTER, jpCenter);
this.add(BorderLayout.EAST, jpEast);
}
/** *//**
* Method actionPerformed
*
*
* @param e
*
*/
public void actionPerformed(ActionEvent e) ...{
// TODO: 在这添加你的代码
if (e.getActionCommand().equals("OK"))
...{
System.exit(0);
}
else if(e.getActionCommand().equals("Save Maps"))
...{
change *= -1;
if(change > 0)
...{
jtf.setText("Text测试……");
jlTips.setText("");
}
else
...{
jlTips.setText("Two pigs");
jtf.setText("");
}
}
else if (e.getActionCommand().equals("Load Maps") || e.getActionCommand().equals("载入地图"))
...{
System.out.println("Map loaded...");
}
else if (e.getActionCommand().equals("退出"))
...{
System.exit(0);
}
}
}
这里对于上次的文件有些许的改动,比如框架被定死了,不能拉伸啊等等,自己去发掘下不同,细细品味下(虽然我编的东西乱七八糟,没什么值得品位的 T-T)。这里定义的char的数组maps就是我们的地图格式,它的符号可以从LandStylePic定义的MapsConstruction类的数组里得到。
再给个对应的效果图:
这样一下后,下次终于可以讲关于文件读取和存储的问题了,要用到IO了哦~(其实这个我还没开始看,慢慢来吧,反正是读书笔记,不急不急)