| |
近日,闲来无事,突然想做一个java版的中文输入法。前天晚上躺在床上整理了一下思路,觉得如果想做成想紫光一样,难度和工作量都比较大,但比较简单的汉字处理编辑器还是可以写一写的,就算是一个小“demo”吧。 在思考如何实现这个“demo”之前,有一个比较棘手的问题以前没有处理过。我最近一年一直都在写web的java程序,swing方面疏远了不少(虽然以前也不是很强,呵呵)。这个问题就是如何实现像紫光输入法一样,在文本编辑器中,弹出一个中文解析窗口。在学校的bbs上问了一下,知道可以用jwindow实现,但知道的时候,我已经用自己一个jframe的子类实现了功能,也就懒得该了。
下面我们来浏览一下程序概要: 1、首先,我要在编辑器中的jtextarea限制输入,对a -- z 的字符进行解析,而不是让其 直接输入jtextarea中。所以,我创建了一个textdocument,该类继承了javax.swing.text.plaindocument, 并重载了insertstring方法。部分代码如下:
/**插入字符串的触发事件,对于任何一个小写的字母,不让输入,以便输入法popupframe进行转换*/ public void insertstring( int offset, string s, attributeset attributeset ) throws badlocationexception { if(s.length() == 0){ return; } string endchar = s.substring(s.length()-1); //如果输入的是 a -- z 的字符,那么需要输入法转换而不是显示,否则可以直接进行显示 if( endchar.compareto("a")>=0 && endchar.compareto("z")<=0){ super.insertstring( offset,s.substring(0,s.length()-1), attributeset ); }else{ super.insertstring( offset,s, attributeset ); } } 2、其次,我创建了一个popupdocument,该类继承了javax.swing.text.plaindocument, 并重载了insertstring方法。部分代码如下:
/**插入字符串的触发事件,对于任何一个小写的字母,不让输入,以便输入法popupframe进行转换*/ public void insertstring( int offset, string s, attributeset attributeset ) throws badlocationexception { if(s.length() == 0){ return; } string endchar = s.substring(s.length()-1); //如果输入的是 a -- z 的字符则显示,否则不能输入 if( endchar.compareto("a")>=0 && endchar.compareto("z")<=0){ super.insertstring( offset,s, attributeset ); }else{ super.insertstring( offset,"", attributeset ); } } 3、编辑器类 -- textframe,里面定义了一个jtextarea对象,为了限制jtextarea 的输 入,初始化时需要有下面的代码:
jtextarea.setdocument(new textdocument()); 然后,就是增加一个键盘的监听事件,代码如下:
void jtextarea_keypressed(keyevent e) { // pop是一个全局变量,定义是popupframe pop; if( pop != null ){ pop.dispose(); pop = null; } char presschar = e.getkeychar(); if(′a′ <=presschar && ′z′>= presschar){ pop = new popupframe(this,presschar); } } 以上的代码执行了这样的功能,即监听jtextarea的输入,如果是a -- z 的字母,那么 就弹出解析窗口。 4、解析器窗口类 -- popupframe,里面定义了两个jtextfield对象,一个用来接受输入字 母(可以编辑),另一用来及时显示输入字母的解析结果(如果在字库里有的话)。下面我 来介绍一下类里具体的方法: loadallinput方法。在初始化时调用,该方法将参数制定的文件读入内存,并将字 符串和对应的解析结果保存到全局变量inputhash。
private void loadallinput(string infile) throws exception{ bufferedreader in = new bufferedreader( new filereader( infile ) ); string inline =""; stringtokenizer token =null; while ( (inline = in.readline()) != null) { token = new stringtokenizer(inline); string noparseword = ""; vector parseword = new vector(); if(token.hasmoretokens()){ noparseword = token.nexttoken(); } while(token.hasmoretokens()){ parseword.add(token.nexttoken()); } this.inputhash.put(noparseword,parseword); } in.close(); } parseinputchars方法。该方法根据输入的字符串,解析输出对应的汉字。代码如下:
private string parseinputchars(string input){ vector parsewords = (vector)inputhash.get(input); string rstring = ""; //处理多页 if (pageno >1){ for (int i = (pageno-1)*9; parsewords !=null && i < parsewords.size(); i++) { rstring += ""+ (i+1-(pageno-1)*9) + parsewords.get(i)+" "; } } //处理单页 else{ for (int i = 0; parsewords !=null && i < parsewords.size() && i< 9; i++) { rstring += ""+ (i+1) + parsewords.get(i)+" "; } } return rstring; } getselectwords方法。该方法在输入1 -- 9时,返回选择的解析结果。 private string getselectwords(char schar,string sstring){ if(sstring ==null){ return ""; } string rstring = ""; vector vector = new vector(); stringtokenizer token = new stringtokenizer(sstring); while(token.hasmoretokens()){ vector.add(token.nexttoken().substring(1)); } rstring = (string)vector.get(integer.parseint(""+schar)-1); return rstring; } inputtextfield_keypressed方法。该方法是键盘监听事件的实现函数。如果键盘输入是a -- z的字母,那么调用parseinputchars,解析结果;如果是1 -- 9的字母,那么除了调用parseinputchars之外,接着需要先调用getselectwords获得选择的解析结果,再把解析结果回写到textframe的jtextarea中。
void inputtextfield_keypressed(keyevent e) { string parsewords = ""; this.showtextfield.settext(""); char presschar = e.getkeychar(); //如果输入的是1 -- 9,那么就应该转入编辑页面,并且将选择相应编号的汉字输入到编辑页面,否则继续解析输入 if(′1′ ==presschar || ′2′== presschar || ′3′== presschar || ′4′== presschar || ′5′== presschar || ′6′== presschar || ′7′== presschar || ′8′== presschar || ′9′== presschar ){// system.out.println("presschar"+presschar); parsewords = this.parseinputchars(inputtextfield.gettext());// system.out.println("old:"+this.textframe.getjtextarea().gettext());// system.out.println("add:"+parsewords); string result = getselectwords(presschar,parsewords); this.textframe.getjtextarea().settext(this.textframe.getjtextarea().gettext()+result); this.textframe.repaint(); this.textframe.getjtextarea().requestfocusinwindow(); this.dispose(); } else if (keyevent.vk_enter == presschar){ this.pageno = 1; string result = this.inputtextfield.gettext(); system.out.println("*************"+result); system.out.println("*****************"+this.textframe.getjtextarea().gettext()+result); this.textframe.getjtextarea().settext(this.textframe.getjtextarea().gettext()+result); this.textframe.repaint(); this.textframe.getjtextarea().requestfocusinwindow(); this.dispose(); } else if(keyevent.vk_back_space == presschar){ this.pageno = 1;// system.out.println("back space:"+// inputtextfield.gettext().substring(0,// inputtextfield.gettext().length()-1)); parsewords = this.parseinputchars(inputtextfield.gettext(). substring(0,inputtextfield.gettext().length()-1)); } else if(′,′ == presschar){// system.out.println("*********************in ,,,,,,,,,,,"); this.pageno = this.pageno==1?1:pageno-1;// system.out.println(inputtextfield.gettext()); parsewords = this.parseinputchars(inputtextfield.gettext()); } else if(′.′ == presschar){// system.out.println("**********************in ............"); this.pageno = pageno + 1;// system.out.println("pageno:"+pageno); parsewords = this.parseinputchars(inputtextfield.gettext()); } else{ this.pageno = 1; parsewords = this.parseinputchars(inputtextfield.gettext() +e.getkeychar()); } if(parsewords !=null){ this.showtextfield.settext(parsewords); } this.repaint(); } 如果有兴趣,可以发mail给我要全部程序,欢迎和我联系交流指导。 注释:运行我的程序后,可以在编辑器中输入a -- z的字母,这时屏幕的左上角会弹出一个小的解析窗口,显示输入的解析结果。比如输入”yi”,解析窗口中的就会出现9个备选字,可以用逗号和点号往后翻页和往前翻页。由于只是一个“demo”,所以解析器的字库里只有(yi,a,ao)三个很简单的拼音字库。最重要的是,能达到效果就可以了。?
|
|