JavaMe开发绘制文本框TextEdit
【问题描述】
textedit是采用gamecanvas绘制的文本编辑器。本文结合实例给出实现的方法。
【原理】
1 运用graphics、gamecanvas绘制文本框和光标。
2 检测到输入事件时,跳转到 高级界面->textbox 。通过系统调用输入法完成输入。
3 将textbox输入的值返回给textedit对象。
【设计模式】
这个过程有点类似装饰模式,实际上,实现输入的还是textbox,只是给textbox装饰了一下,形成了一个漂亮的外观。
【代码清单】
textedit.java package com.token.view.components; import javax.microedition.lcdui.font; import javax.microedition.lcdui.graphics; import javax.microedition.lcdui.game.gamecanvas; public class textedit extends gamecanvas { private font ft; public int width; public int height; public textedit(gamecanvas canvas) { super(false); } //绘制文本框 public void drawtextbox(gamecanvas canvas, graphics graphics, string text, int x, int y, boolean cursorblinkon) { //system.out.println("draw"); int padding = 4; int margin = 2; ft = font.getfont(font.face_proportional,font.style_plain,font.size_medium); graphics.setfont(ft); width = 3*canvas.getwidth()/5+2*padding; height = ft.getheight()+2*padding; graphics.setcolor(color.frame); graphics.fillrect(x+1,y+1,width+margin,height+margin); graphics.setcolor(color.framebg); graphics.drawrect(x, y,width, height); graphics.setcolor(color.background); graphics.fillrect(x+1, y+1,width-1,height-1); graphics.setcolor(color.text); graphics.drawstring(text, x+padding, y+padding, graphics.top|graphics.left); drawcursor(graphics, x+ft.stringwidth(text)+padding, y+padding, 1, ft.getheight(), cursorblinkon); canvas.flushgraphics(x,y,width,height); } //绘制光标 public void drawcursor(graphics graphics, int x, int y, int width, int height, boolean cursorblinkon) { if(cursorblinkon) { ft = font.getfont(font.face_proportional,font.style_plain,font.size_medium); graphics.setfont(ft); graphics.setcolor(0x0,0x0,0x0); graphics.drawline(x+width,y,x+width,y+height); } } } popuptextbox.java package com.token.view; import javax.microedition.lcdui.command; import javax.microedition.lcdui.commandlistener; import javax.microedition.lcdui.displayable; import javax.microedition.lcdui.textbox; import com.token.util.uicontroller; public class popuptextbox extends textbox { private uicontroller controller; protected string canvastext = ""; private command okcommand; private command cancelcommand; private string object_name = null; private string editor = null; private object args_t[]; private object[] args; public popuptextbox(uicontroller control, string title, string text, int maxsize, int constraints) { super(title, text, maxsize, constraints); controller = control; args = new object[6]; okcommand = new command("确定", command.ok, 1); cancelcommand = new command("取消", command.cancel, 1); this.addcommand(okcommand); this.addcommand(cancelcommand); this.setcommandlistener(new textboxlistener()); } public void init(object[] args) { object_name = ((string)args[0]!=null)?(string)args[0]:""; editor = ((string)args[1]!=null)?(string)args[1]:""; //system.out.println(object_name); //system.out.println(editor); args_t = args; this.setstring(""); } protected void closetextbox(boolean update) { if (update) canvastext = this.getstring(); //system.out.println(canvastext); if(object_name.equals("registscreen")) { if(editor.equals("regist_name")) { if(args_t[3]!=""||args_t[3]!=null||args_t[4]!=""||args_t[4]!=null) { args[0] = object_name; args[1] = editor; args[2] = this.canvastext; args[3] = args_t[3]; args[4] = args_t[4]; } controller.handleevent(uicontroller.eventid.event_user_regist_edit_back,args); } else if(editor.equals("regist_passwd")) { if(args_t[2]!=""||args_t[2]!=null||args_t[4]!=""||args_t[4]!=null) { args[0] = object_name; args[1] = editor; args[2] = args_t[2]; args[3] = this.canvastext; args[4] = args_t[4]; } controller.handleevent(uicontroller.eventid.event_user_regist_edit_back,args); } else if(editor.equals("regist_passwd_re")) { if(args_t[2]!=""||args_t[2]!=null||args_t[3]!=""||args_t[3]!=null) { args[0] = object_name; args[1] = editor; args[2] = args_t[2]; args[3] = args_t[3]; args[4] = this.canvastext; } controller.handleevent(uicontroller.eventid.event_user_regist_edit_back,args); } } //... } private class textboxlistener implements commandlistener { public void commandaction(command command, displayable disp) { if(command==okcommand) { closetextbox(true); } else if(command==cancelcommand) { closetextbox(false); } } } } userregist.java package com.token.view; import javax.microedition.lcdui.font; import javax.microedition.lcdui.graphics; import javax.microedition.lcdui.game.gamecanvas; import com.token.model.*; import com.token.util.*; import com.token.view.components.*; public class userregist extends gamecanvas implements runnable { private uicontroller controller; private graphics graphics; private font ft; private menu menu; private head head; private backgroud backgroud; private userdatarecord userrecord; private string title; private textedit textedit_name; private textedit textedit_passwd; private textedit textedit_passwd_re; private int textedit_name_x; private int textedit_name_y; private int textedit_passwd_x; private int textedit_passwd_y; private int textedit_passwd_re_x; private int textedit_passwd_re_y; private int currentlyselectedindex = 0; private string username; private string passwd; private string passwd_re; long caretblinkdelay = 500l; long lastcaretblink = 0; private string object_name; private string editor; private boolean cursorblinkon1; private boolean cursorblinkon2; private boolean cursorblinkon3; private int width; private int height; public userregist(uicontroller control) { super(false); this.controller=control; this.title = "用户注册"; setfullscreenmode(true); graphics = getgraphics(); width = getwidth(); height = getheight(); menu = new menu(this); head = new head(this); backgroud = new backgroud(this); userrecord = new userdatarecord(); textedit_name = new textedit(this); textedit_passwd = new textedit(this); textedit_passwd_re = new textedit(this); } public void show(object[] args) { // todo auto-generated method stub setfullscreenmode(true); object_name = ((string)args[0]!=null)?(string)args[0]:""; editor = ((string)args[1]!=null)?(string)args[1]:""; username = ((string)args[2]!=null)?(string)args[2]:""; passwd = ((string)args[3]!=null)?(string)args[3]:""; passwd_re = ((string)args[4]!=null)?(string)args[4]:""; if(editor.equals("regist_name")) { cursorblinkon1 = true; cursorblinkon2 = false; cursorblinkon3 = false; currentlyselectedindex =0; } else if(editor.equals("regist_passwd")) { cursorblinkon1 = false; cursorblinkon2 = true; cursorblinkon3 = false; currentlyselectedindex =1; } else if(editor.equals("regist_passwd_re")) { cursorblinkon1 = false; cursorblinkon2 = false; cursorblinkon3 = true; currentlyselectedindex =2; } //system.out.println(object_name); //system.out.println(editor); draw(); redraw(); } public void draw() { //clearscreen(); backgroud.drawbackgroud(this, graphics); head.drawhead(this,graphics,this.title); menu.drawmenu(this,graphics,"下一步","退出"); drawbody(); } private void redraw() { switch(currentlyselectedindex) { case 0: { cursorblinkon2 = false; cursorblinkon3 = false; editor = "regist_name"; break; } case 1: { cursorblinkon1 = false; cursorblinkon3 = false; editor = "regist_passwd"; break; } case 2: { cursorblinkon1 = false; cursorblinkon2 = false; editor = "regist_passwd_re"; break; } default:; } textedit_name.drawtextbox(this, graphics, username, textedit_name_x, textedit_name_y, cursorblinkon1); textedit_passwd.drawtextbox(this, graphics, passwd, textedit_passwd_x, textedit_passwd_y, cursorblinkon2); textedit_passwd.drawtextbox(this, graphics, passwd_re, textedit_passwd_re_x, textedit_passwd_re_y, cursorblinkon3); textedit_name.flushgraphics(); } public void drawbody() { int margin =5; ft = font.getfont(font.face_proportional,font.style_bold,font.size_large); string info = "用户名:\n"; string info_wrap1[] = stringdealmethod.format(info, width-10, ft); graphics.setfont(ft); graphics.setcolor(color.text); for(int i=0; i<info_wrap1.length; i++) { graphics.drawstring(info_wrap1[i],5, (i) * ft.getheight()+40, graphics.top|graphics.left); } textedit_name_x = 5; textedit_name_y = info_wrap1.length * ft.getheight()+40; textedit_name.drawtextbox(this, graphics, username, textedit_name_x, textedit_name_y, cursorblinkon1); info = "用户密码:\n"; string info_wrap2[] = stringdealmethod.format(info, width-10, ft); graphics.setfont(ft); graphics.setcolor(color.text); for(int i=0; i<info_wrap2.length; i++) { graphics.drawstring(info_wrap2[i],5, (i+info_wrap1.length) * ft.getheight()+textedit_name.height+margin+40, graphics.top|graphics.left); } textedit_passwd_x = 5; textedit_passwd_y = (info_wrap1.length+info_wrap2.length) * ft.getheight()+textedit_name.height+margin+40; textedit_passwd.drawtextbox(this, graphics, passwd, textedit_passwd_x, textedit_passwd_y, cursorblinkon2); info = "密码确认:\n"; string info_wrap3[] = stringdealmethod.format(info, width-10, ft); graphics.setfont(ft); graphics.setcolor(color.text); for(int i=0; i<info_wrap3.length; i++) { graphics.drawstring(info_wrap3[i],5, (i+info_wrap1.length+info_wrap2.length) * ft.getheight()+textedit_name.height+textedit_passwd.height+2*margin+40, graphics.top|graphics.left); } textedit_passwd_re_x = 5; textedit_passwd_re_y = (info_wrap1.length+info_wrap2.length+info_wrap3.length) * ft.getheight()+textedit_name.height+textedit_passwd.height+2*margin+40; textedit_passwd_re.drawtextbox(this, graphics, passwd_re, textedit_passwd_re_x, textedit_passwd_re_y, cursorblinkon3); } public void clearscreen() { graphics.setcolor(0xff,0xff,0xff); graphics.fillrect(0, 0, width, height); } public void checktimestamp() { long currenttime = system.currenttimemillis(); //system.out.println("1"); if(lastcaretblink + caretblinkdelay < currenttime) { //system.out.println("2"); if(editor.equals("regist_name")) { cursorblinkon1 =! cursorblinkon1; cursorblinkon2 = false; cursorblinkon3 = false; } else if(editor.equals("regist_passwd")) { cursorblinkon1 = false; cursorblinkon2 =! cursorblinkon2; cursorblinkon3 = false; } else if(editor.equals("regist_passwd_re")) { cursorblinkon1 = false; cursorblinkon2 = false; cursorblinkon3 =! cursorblinkon3; } lastcaretblink = currenttime; } } public void run() { //system.out.println("run"); while(true) { checktimestamp(); redraw(); try { synchronized(this) { //system.out.println("3"); wait(50l); } } catch(exception e) { e.printstacktrace(); } } } protected void keypressed(int keycode) { switch(keycode) { case keyid.soft_right: { controller.handleevent(uicontroller.eventid.event_exit,null); break; } case keyid.soft_left: { if(username!="" && passwd!=""&&passwd_re!="") { if(passwd.equals(passwd_re)) { userrecord.db_deleteallrecord(); if(userrecord.db_getrecord(1)==null) { userdataitem useritem = new userdataitem(1,(username+","+passwd).getbytes()); userrecord.db_addrecord(useritem); useritem = null; system.gc(); } string update = "start"; object [] args = {"activescreen", null, update}; controller.handleevent(uicontroller.eventid.event_next_active_token_screen,args); } } break; } case keyid.key_edit: case key_num0: case key_num1: case key_num2: case key_num3: case key_num4: case key_num5: case key_num6: case key_num7: case key_num8: case key_num9: { //system.out.println(editor); object[] args = {object_name,editor,username,passwd,passwd_re}; controller.handleevent(uicontroller.eventid.event_user_regist_edit,args); break; } default:; } keycode = getgameaction(keycode); switch(keycode) { case up: case left: { currentlyselectedindex--; if(currentlyselectedindex<0) { currentlyselectedindex=0; } else { redraw(); } break; } case down: case right: { currentlyselectedindex++; if(currentlyselectedindex>2) { currentlyselectedindex=2; } else { redraw(); } break; } } } }
【分析】
1 文本框的绘制(textedit.java)
需要传递gamecanvas、graphics对象,实现绘图,策略是谁使用,谁传递该参数。此外需要床底文本框左上角坐标(x,y)以及控制光标闪烁的变量cursorblinkon。
public void drawtextbox(gamecanvas canvas, graphics graphics, string text, int x, int y, boolean cursorblinkon) { //system.out.println("draw"); int padding = 4; int margin = 2; ft = font.getfont(font.face_proportional,font.style_plain,font.size_medium); graphics.setfont(ft); width = 3*canvas.getwidth()/5+2*padding; height = ft.getheight()+2*padding; graphics.setcolor(color.frame); graphics.fillrect(x+1,y+1,width+margin,height+margin); graphics.setcolor(color.framebg); graphics.drawrect(x, y,width, height); graphics.setcolor(color.background); graphics.fillrect(x+1, y+1,width-1,height-1); graphics.setcolor(color.text); graphics.drawstring(text, x+padding, y+padding, graphics.top|graphics.left); drawcursor(graphics, x+ft.stringwidth(text)+padding, y+padding, 1, ft.getheight(), cursorblinkon); canvas.flushgraphics(x,y,width,height); }
2 绘制光标(textedit.java)
public void drawcursor(graphics graphics, int x, int y, int width, int height, boolean cursorblinkon) { if(cursorblinkon) { ft = font.getfont(font.face_proportional,font.style_plain,font.size_medium); graphics.setfont(ft); graphics.setcolor(0x0,0x0,0x0); graphics.drawline(x+width,y,x+width,y+height); } }
3 实现光标闪烁
光标闪烁的实现需要用到线程,在uicontroller.java类中,需要绘制文本框的视图类,需要实现线程接口。
uicontroller.java case eventid.event_next_user_regist_screen: case eventid.event_user_regist_edit_back: { reg.show(args); thread thread = new thread(reg); thread.start(); midlet.setcurrent(reg); break; } userregist.java public void checktimestamp() { long currenttime = system.currenttimemillis(); //system.out.println("1"); if(lastcaretblink + caretblinkdelay < currenttime) { //system.out.println("2"); if(editor.equals("regist_name")) { cursorblinkon1 =! cursorblinkon1; cursorblinkon2 = false; cursorblinkon3 = false; } else if(editor.equals("regist_passwd")) { cursorblinkon1 = false; cursorblinkon2 =! cursorblinkon2; cursorblinkon3 = false; } else if(editor.equals("regist_passwd_re")) { cursorblinkon1 = false; cursorblinkon2 = false; cursorblinkon3 =! cursorblinkon3; } lastcaretblink = currenttime; } } public void run() { //system.out.println("run"); while(true) { checktimestamp(); redraw(); try { synchronized(this) { //system.out.println("3"); wait(50l); } } catch(exception e) { e.printstacktrace(); } } }
4 调用高级界面textbox子类popuptextbox
调用时,将调用对象名、编辑对象名、以及编辑框参数传递给popuptextbox对象(一定要有,目的是保存编辑框的值,否则多次调用返回时,不同编辑框的值被刷新为空了)
userregist.java(keypressed) case keyid.key_edit: case key_num0: case key_num1: case key_num2: case key_num3: case key_num4: case key_num5: case key_num6: case key_num7: case key_num8: case key_num9: { //system.out.println(editor); object[] args = {object_name,editor,username,passwd,passwd_re}; controller.handleevent(uicontroller.eventid.event_user_regist_edit,args); break; } uicontroller.java case eventid.event_user_regist_edit: { textbox.init(args); midlet.setcurrent(textbox); break; }
5 popuptextbox参数的接收
public void init(object[] args) { object_name = ((string)args[0]!=null)?(string)args[0]:""; editor = ((string)args[1]!=null)?(string)args[1]:""; //system.out.println(object_name); //system.out.println(editor); args_t = args; this.setstring(""); }
6 popuptextbox返回输入法输入的值
if (update) canvastext = this.getstring();
7 popuptextbox输入值处理
依据调用的对象,以及编辑对象,对输入的值进行处理,传递给父对象编辑框
if(object_name.equals("registscreen")) { if(editor.equals("regist_name")) { if(args_t[3]!=""||args_t[3]!=null||args_t[4]!=""||args_t[4]!=null) { args[0] = object_name; args[1] = editor; args[2] = this.canvastext; args[3] = args_t[3]; args[4] = args_t[4]; } controller.handleevent(uicontroller.eventid.event_user_regist_edit_back,args); } else if(editor.equals("regist_passwd")) { if(args_t[2]!=""||args_t[2]!=null||args_t[4]!=""||args_t[4]!=null) { args[0] = object_name; args[1] = editor; args[2] = args_t[2]; args[3] = this.canvastext; args[4] = args_t[4]; } controller.handleevent(uicontroller.eventid.event_user_regist_edit_back,args); } else if(editor.equals("regist_passwd_re")) { if(args_t[2]!=""||args_t[2]!=null||args_t[3]!=""||args_t[3]!=null) { args[0] = object_name; args[1] = editor; args[2] = args_t[2]; args[3] = args_t[3]; args[4] = this.canvastext; } controller.handleevent(uicontroller.eventid.event_user_regist_edit_back,args); } }
8 输入值的显示
(1) 新建对象
private textedit textedit_name; textedit_name = new textedit(this);
(2) 接受输入的参数
object_name = ((string)args[0]!=null)?(string)args[0]:""; editor = ((string)args[1]!=null)?(string)args[1]:""; username = ((string)args[2]!=null)?(string)args[2]:""; passwd = ((string)args[3]!=null)?(string)args[3]:""; passwd_re = ((string)args[4]!=null)?(string)args[4]:"";
(3) 光标控制,定位到编辑对象,控制编辑对象的光标闪烁(run方法)
private void redraw() { switch(currentlyselectedindex) { case 0: { cursorblinkon2 = false; cursorblinkon3 = false; editor = "regist_name"; break; } case 1: { cursorblinkon1 = false; cursorblinkon3 = false; editor = "regist_passwd"; break; } case 2: { cursorblinkon1 = false; cursorblinkon2 = false; editor = "regist_passwd_re"; break; } default:; } //... }
(4) 编辑框的绘制
private void redraw() { ... textedit_name.drawtextbox(this, graphics, username, textedit_name_x, textedit_name_y, cursorblinkon1); textedit_passwd.drawtextbox(this, graphics, passwd, textedit_passwd_x, textedit_passwd_y, cursorblinkon2); textedit_passwd.drawtextbox(this, graphics, passwd_re, textedit_passwd_re_x, textedit_passwd_re_y, cursorblinkon3); textedit_name.flushgraphics(); }
实现的效果如图1所示: