发一个以前写的UI代码吧, 一个可以表现目录树结构的java代码, 当然标题说是实现J2ME中的二级树目录意思是比较适合用在J2ME方面,因为J2ME没有提供这种UI组件形式,但实际应用开发中,这类界面用途很广。 下面我简单介绍一下设计思路。
首先我们要实现树型目录就要定义一个Tree的主干,也就是Tree类,然后在Tree上面安放节点(Node类)。每个节点下面就是分类的内容项目。 这样就是个二级树结构了。在实现上,我们把每个节点下包含的内容称作Member,让Member和Node都属于一种类型,我给它起名叫做Element。 我这样设计有它的一个好处,就是在界面上比较好表现出来,通过看代码就可以发现了。
下面是Element类的实现,我们把Element定义为抽象类。
以下是JAVA代码:【复制】
Code:package tree;
/** *//**
*@author K7sem
*/
public abstract class Element {
protected String label;
protected boolean selected = false;
public Element(String str) {
label = str;
}
public Element() {
}
public String getLabel() {
return label;
}
public void setLabel(String s) {
label = s;
}
public boolean isSelected() {
return selected;
}
public void setSelected(boolean b) {
selected = b;
}
}
Element类中有两个成员变量,分别表示一个元素的名称和选中的状态, 当然这只是我的假设,我们还可以更改Element类,让它具备更多的特性,前提是这些属性要被Node和Member共用。
下面是Member类的实现:
以下是JAVA代码:【复制】
Code:package tree;
/** *//**
*@author: k7sem
*/
public class Member extends Element{
public Member(String s) {
super(s);
}
}
Member类可以什么都没有吗? 当然可以,因为如果它不需要额外的特性,比如带一个图标。 那么它可是不增加任何成员,只要实现一个构造器,然后去掉用一下父类的构造就OK了。
下面是Node类的实现:
以下是JAVA代码:【复制】
Code:package tree;
import java.util.Vector;
/** *//**
*@author: k7sem
*/
public class Node extends Element{
private boolean expand = false;
private Vector members = new Vector();
public Node(String s) {
super(s);
}
public void addMember(Member m) {
members.addElement(m);
}
public void removeMember(Member m) {
members.removeElement(m);
}
public Vector getMembers() {
return members;
}
public void setExpand(boolean b) {
expand = b;
}
public boolean isExpanded() {
return expand;
}
}
Node类看起来比Member类稍微多了一些代码,expand表示这个界面展开和收起的状态,members是一个Vector类对象,用来存储在这个节点下的所有成员。 当然它需要实现一些必要的方法才能完善这些功能,比如addMember和removeMember。
好了,下面是我们的主角,Tree类的实现部分:
以下是JAVA代码:【复制】
Code:package tree;
import java.util.Vector;
/** *//**
*@author: k7sem
*/
public class Tree {
private int maxSize = 0;
private Vector elements = new Vector();
private Vector displayList = new Vector();
private Vector dynamicList = null;
private int beginIndex = 0;
private int endIndex = 0;
private int index = 0;
private String name = null;
private int uiIndex = 0;
public Tree(String n, int max) {
name = n;
maxSize = max;
}
public Tree() {
}
public void setName(String str) {
name = str;
}
public String getName() {
return name;
}
public int getIndex() {
return index;
}
/** *//**
* 添加节点
* @param n
*/
public void addNode(Node n) {
elements.addElement(n);
refreshList();
}
/** *//**
* 删除节点
* @param n
*/
public void removeNode(Node n) {
elements.removeElement(n);
refreshList();
}
/** *//**
* 获得当前选中的元素
* @return
*/
public Element getSelectedElement() {
if (dynamicList == null || index < 0 || index > dynamicList.size() - 1) {
return null;
}
return (Element) dynamicList.elementAt(index);
}
/** *//**
* 设置对大显示数
* @param i
*/
public void setDisplaySize(int i) {
maxSize = i;
}
// 得到最大显示数
public int getDisplaySize() {
return maxSize;
}
// 得到界面上用到的index
public int getUiIndex() {
return uiIndex;
}
/** *//**
* 得到可显示的List
* @return
*/
public Vector getDisplayElements() {
return displayList;
}
/** *//**
* 移动在整个动态List中的index
* @param over
*/
public void moveIndexUp(boolean over) {
if (over) {
if (beginIndex > 0) {
index--;
beginIndex--;
if (beginIndex >= 0) {
if ((dynamicList.size() - beginIndex) <= maxSize) {
endIndex = dynamicList.size();
} else {
endIndex--;
}
} else {
endIndex--;
}
refreshDisplayList();
}
} else {
index--;
moveUiIndexUp();
}
}
/** *//**
* 移动在整个动态List中的index
* @param over
*/
public void moveIndexDown(boolean over) {
if (over) {
if (endIndex < dynamicList.size()) {
index++;
endIndex++;
beginIndex++;
refreshDisplayList();
}
} else {
index++;
moveUiIndexDown();
}
}
// 移动界面上的index
private void moveUiIndexUp() {
uiIndex--;
}
// 移动界面上的index
private void moveUiIndexDown() {
uiIndex++;
}
/**//*
*更新可显示的List
*/
private void refreshDisplayList() {
displayList.removeAllElements();
for (int x = beginIndex; x < endIndex; x++) {
displayList.addElement(dynamicList.elementAt(x));
}
}
/** *//**
*
*@更新动态List
*/
public synchronized void refreshList() {
if (elements.size() == 0) {
return;
}
if (beginIndex < 0) {
beginIndex = 0;
}
Vector te = new Vector();
for (int i = 0; i < elements.size(); i++) {
Element e = (Element) elements.elementAt(i);
if (e instanceof Node) {
Node node = (Node) e;
Vector me = node.getMembers();
if (node.isExpanded() && me.size() > 0) {
te.addElement(node);
for (int z = 0; z < me.size(); z++) {
te.addElement(me.elementAt(z));
}
} else {
te.addElement(node);
}
} else {
te.addElement(e);
}
}
dynamicList = te;
if (maxSize > te.size()) {
endIndex = te.size();
} else {
endIndex = maxSize + beginIndex;
}
if (beginIndex > 0) {
if ((te.size() - beginIndex) < maxSize) {
endIndex = te.size();
}
}
if (index < beginIndex) {
index = 0;
}
if (index > endIndex - 1) {
index = endIndex - 1;
}
displayList.removeAllElements();
for (int x = beginIndex; x < endIndex; x++) {
displayList.addElement(te.elementAt(x));
}
}
}
Tree类有点长, 毕竟它要实现作为Tree的一些操作逻辑。思路是这样的,把Tree想象成为一个List, 所有的节点,节点下面的成员都是这个List里的元素,这样这个Tree就是一个很长的List,如果你有很多节点,并且节点下面很多成员的话。 因为这是一个可伸缩的,不定长的Tree. 那么它显示在界面上的元素可多,可少。 这就需要它还要保存一份可供显示的List,每当界面有变化时, 比如打开了一个节点, 它就返回一个当前状态下的一个List。 这样我需要三个Vector来保存这些状态, 第一个Vector保存所有的元素,包括Node和Node下的Member, 第二个保存当界面发生改变是的一个动态List, 这个List不关心可显示的项目多少,只是负责按照界面的变化来更新,比如节点打开和关闭,相应的就会增加一些元素和减少一些元素, 最后一个是按照最大显示条目提供显示的List。 这个可显示的List会像一个滑动窗口一样的滑动,窗口的大小适中就是最大的可以实现条目, 这样就实现了在界面上的滚动。
我最初的设计是这个树不但可以添加节点,而且还可以直接添加成员Member对象,所以里面可能还残留一些这样的判断。 后来我为了精简代码把这个功能去掉了。添加的话也很简单。
下面是一个最小巧的J2ME低级界面实现, 注意paint()方法的代码,和keyReleased()中的代码。可以直接像这样用,改改颜色和字体就行了。
以下是JAVA代码:【复制】
Code:import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import tree.*;
import java.util.Vector;
public class Main extends MIDlet {
public Main() {
}
public void startApp() {
Display.getDisplay(this).setCurrent(new TC());
}
public void pauseApp() {
}
public void destroyApp(boolean un) {
}
class TC extends Canvas implements Runnable {
Tree tree;
public TC() {
// 初始化
initTree();
// 初始化重绘线程
new Thread(this).start();
}
// 初始化Tree的数据,为了方便,我们设置三个节点,每个节点上三个成员
// 名称都是按顺序指定
private void initTree() {
tree = new Tree();
tree.setDisplaySize(20);
Node n0 = new Node("节点一");
Node n1 = new Node("节点二");
Node n2 = new Node("节点三");
for (int i = 0; i < 3; i++) {
n0.addMember(new Member(n0.getLabel() + "-" + "成员" + i));
n1.addMember(new Member(n1.getLabel() + "-" + "成员" + i));
n2.addMember(new Member(n2.getLabel() + "-" + "成员" + i));
}
tree.addNode(n0);
tree.addNode(n1);
tree.addNode(n2);
}
int listX = 10, listY = 10;
Font listFont = Font.getDefaultFont();
public void paint(Graphics g)
{
g.setColor(0xCCCCCC);
g.fillRect(0,0,getWidth(),getHeight());
Vector elements = tree.getDisplayElements();
int ly = listY;
for (int e = 0; e < elements.size(); e++) {
Element emen = (Element) elements.elementAt(e);
if (e == tree.getUiIndex()) {
g.setColor(0xFFFF00);
g.drawRect(listX, ly, getWidth(), listFont.getHeight() + 2);
g.setColor(0x1BEDEF);
g.fillRect(listX + 1, ly + 1, getWidth() - 1, listFont.getHeight() + 1);
}
if (emen instanceof Node) {
Node node = (Node) emen;
if (node.isExpanded()) {
// 当节点打开时,显示一种展开的图标
//drawExpandIcon(g, listX, ly, true);
} else {
// 当节点收起时,显示一种收起的图标
//drawExpandIcon(g, listX, ly, false);
}
g.setColor(0x453514);
g.drawString(node.getLabel(), listX + 15, ly + 2, 0);
}
if (emen instanceof Member) {
Member member = (Member) emen;
g.setColor(0x453514);
g.drawString(member.getLabel(), listX + 25, ly, 0);
}
ly += listFont.getHeight() + 2;
}
}
protected void keyPressed(int keyCode)
{
}
protected void keyReleased(int keyCode)
{
// 我们把按键事件写在按键释放时处理
int action = getGameAction(keyCode);
if (action == Canvas.UP) {
Vector v = tree.getDisplayElements();
if (tree.getUiIndex() > 0) {
tree.moveIndexUp(false);
} else {
tree.moveIndexUp(true);
}
}
if (action == Canvas.DOWN) {
Vector v = tree.getDisplayElements();
if (tree.getUiIndex() < v.size() - 1) {
tree.moveIndexDown(false);
} else {
tree.moveIndexDown(true);
}
}
if (action == Canvas.FIRE) {
Element e = tree.getSelectedElement();
if (e instanceof Node) {
Node d = (Node) e;
if (d.isExpanded()) {
d.setExpand(false);
} else {
d.setExpand(true);
}
tree.refreshList();
}
if (e instanceof Member) {
Member m = (Member) e;
// 当选择了一个成员时,要做什么
}
}
}
public void run()
{
while (true) {
try {
Thread.sleep(100L);
repaint();
} catch (Exception e){e.printStackTrace();}
}
}
}
}
以上代码在WTK中新建个项目,然后放进去,指定好MIDlet类名,就可以运行了。