分享
 
 
 

About My Editor (2)

王朝java/jsp·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

About My Editor 2 Afritxia 01.13.2003

引言2

这篇文章并不太适合Java高手和刚要开始学Java的人看.如果你刚弄清楚Java编程是怎么回事,并且想用Java提供swing组件做一些简单的程序,以此来巩固对Java编程学习的话,那你算是找对了.我会披露swing组件中的一些鲜为人知的方法.希望这几篇文章能够成为你在学习Java程序设计道路中的一块铺路石,助你顺利攀到Java程序设计颠峰.

afritxia.student@sina.com

本篇话题: 文本编辑区设计.

我的JMDEditor的编辑区使用的是非常简单的JTextArea组件.说它简单是因为它已经们实现了很多常用的功能:Cut,Copy,Paste,Select,SelectAll...甚至还可以设置被选取文本的背景色.所以我们并不用费心去写这些功能.

但是,要做一个象样的记事本程序,光有这点功能显然是不够的.看看JDK自带的记事本程序,就连那个还有多次"撤消"与"重做"的功能呢.可它是怎样实现的呢?做了一大堆的AbstractAction类的派生类,其中的UndoAction与RedoAction就是这样来的:

class UndoAction extends AbstractAction

{

public UndoAction(){

}

public void actionPerformed(ActionEvent e){

// Action Code

// 执行撤消操作

}

public void update(){

// Update Code

// 如果当前文本无法再进行撤消,则菜单中的"Undo"就不能被选择了

}

}

当然,还要有这些东西才能成事:

JTextArea editor=new JTextArea();

UndoableEditListener undoHandler=new UndoHandler(); // ??

UndoManager undo=new UndoManager(); // 撤消管理器?

UndoAction undoAction=new UndoAction();

editor.getDocument().addUndoableEditListener(undoHandler);

class UndoHandler implements UndoableEditListener // ?

{

public void undoableEditHappened(UndoableEditEvent e){

undo.addEdit(e.getEdit());

// ...

}

}

JMenuItem undoMenuItem=new JMenuItem("Undo");

undoMenuItem.addActionListener(undoAction);

try{ // UndoAction中的撤消操作代码

undo.undo();

}catch(CannotUndoException ex){

// Throws Exception

}

我已经乱了!虽然功能比较完善,但是很容易就会让象我一样的初学者晕头转向.所以我千方百计的简化了此操作.

JTextArea editor=new JTextArea();

UndoManager undo=new UndoManager(); // 撤消管理器?

undo.setLimit(5); // 5步撤消

editor.getDocument().addUndoableEditListener(new UndoableEditListener(){

public void undoableEditHappened(UndoableEditEvent e) {

undo.addEdit(e.getEdit());

}

});

JMenuItem undoMenuItem=new JMenuItem("Undo");

undoMenuItem.addActionListener(...);

public void actionPerformed(ActionEvent e){

String cmd=e.getActionCommand();

// ...

if(cmd.equals("Undo"))

try{

undo.undo(); // Call undo.redo() if you need redo

}catch(CannotUndoException ex){

}

// ...

}

其实看起来也没简化多少.不过我省掉了UndoableEditListener,这样看起来就没有那么多的弯弯绕了.(更简单的方式?目前我是找不到了)

作为一个程序员,在进行编码时经常会遇到编译器给出的错误提示:

Error! ... ...

... ... (17)

最后给出的是错误的所在行.那么我要做的就是将光标移到文件第一行,然后一下下的数出17行来,再然后解决问题.可是如果错误是在第1234行怎么办?还用土办法?那无异于徒步登月!最好来个行列显示功能.起初,我写了一个行列显示的算法.那不值一提,因为随着文本中的字数渐多时,这个算法几乎是以死机的方式运行的.我想JTextArea中应该有这样的方法,可是我寻觅了大半天也是一无所获.最后,所有的嫌疑都被归到

getLineOfOffset(int) 和 getLineStartOffset(int)

两个函数身上.这两个是什么意思?...看来,只有象搭积木一样把他们搭来看看了:

// import javax.swing.event.*;

JTextArea editor=new JTextArea();

editor.addCaretListener(new CaretListener(){

public void caretUpdate(CaretEvent e){

int dot=e.getDot();

int ln, col;

ln=col=0;

try{

ln=editor.getLineOfOffset(dot);

col=dot-editor.getLineStartOffset(ln);

System.out.println("["+(ln+1)+","+(col+1)+"]");

}catch (BadLocationException Ex){

}

}

});

至于getLineOfOffset(int)与getLineStartOffset(int),是个什么地噶活:

// 摘录自: SUN Microsystem jdk1.3.1 / src.jar / JTextArea.java

public int getLineOfOffset(int offset) throws BadLocationException {

Document doc = getDocument();

if (offset < 0) {

throw new BadLocationException("Can't translate offset to line", -1);

} else if (offset > doc.getLength()) {

throw new BadLocationException("Can't translate offset to line", doc.getLength()+1);

} else {

Element map = getDocument().getDefaultRootElement();

return map.getElementIndex(offset);

}

}

public int getLineStartOffset(int line) throws BadLocationException {

Element map = getDocument().getDefaultRootElement();

if (line < 0) {

throw new BadLocationException("Negative line", -1);

} else if (line >= map.getElementCount()) {

throw new BadLocationException("No such line", getDocument().getLength()+1);

} else {

Element lineElem = map.getElement(line);

return lineElem.getStartOffset();

}

}

恩!大大地好!可以把他们塞到JEditorPane,JTextPane里去,继续效忠我们Java爱好者.没看懂?各位只管拿去改改随便用就成了.

本篇最后登场的是一个重量级话题:查找与替换

首先,要做一个查找与替换对话框.它继承自JDialog类,并且是可以和主窗体并行的.

public class FindDlg extends JDialog

{

public FindDlg(JFrame f){

super(f, "Find and Replace.", false); // 用false就能并行

// ... ...

}

// Find and Replace Code ...

}

然后就是最重要的查找与替换功能的实现了:

// KEY: Find function //////////////////////////////////////////////////////////

// Algorithm is ideological: From 'pos' location, cut out 'findStrLen' character

// and 'findStr' to compare. If be identical to return, it is different and con-

// -tinued to cut out 'findStrLen' character from next location compare with

// 'findStr'. editTxtAra: The text area that has been sought. findStr: Find Str-

// -ing. direction: Find direction.

public boolean find(JTextArea editTxtAra, String findStr,

int direction, boolean checkCase){

if(findStr.equals("")) return(false);

pos=editTxtAra.getSelectionEnd();

int findStrLen=findStr.length();

int editTxtAraLen=editTxtAra.getText().length();

String temp="";

if(direction==-1) pos=editTxtAra.getSelectionStart()-1;

while(pos>=0&&pos<editTxtAraLen){

try{

temp=editTxtAra.getText(pos, findStrLen);

if(checkCase&&(temp.compareToIgnoreCase(findStr)==0)

||temp.equals(findStr)){

editTxtAra.select(pos, pos+findStrLen);

return(true);

}

}catch(Exception e){

}

pos+=direction;

}

return(false);

}

// Why return a boolean value ?

// KEY: Replace function ///////////////////////////////////////////////////////

// Algorithm is ideological: If exist selected text, replace it.

// editTxtAra: The text area that has been sought.

// replaceStr: Use 'replaceStr' replace selection.

private void replace(JTextArea editTxtAra, String replaceStr){

if(editTxtAra.getSelectionStart()!=editTxtAra.getSelectionEnd())

editTxtAra.replaceSelection(replaceStr);

}

// KEY: Replace function ///////////////////////////////////////////////////////

// Algorithm is ideological: Circulate to seek replacement.

// editTxtAra: The text area that has been sought.

// findStr: Find String.

// replaceStr: Use 'replaceStr' replace selection.

// Why function find return a boolean value ? Are you see ?

private void replaceAll(JTextArea editTxtAra, String findStr,

String replaceStr, boolean checkCase){

if(findStr.equals("")) return;

int i;

editTxtAra.select(0, 0);

for(i=0; find(editTxtAra, findStr, +1, checkCase); ++i) // Are you see ?!

replace(editTxtAra, replaceStr);

JOptionPane.showMessageDialog(FindDlg.this,

"Replaced "+i+" occurence(s) in this file.",

"INFORMATION",

JOptionPane.INFORMATION_MESSAGE);

}

// 别怪我的E文不正确,只怪现在的翻译软件都是直来直去的(注释没看懂?别急!翻译软件能看懂.

// 按理说翻译软件是可以再直译回原文的...不成?!...那可就好玩儿了).

我并不想解释我的算法中的每一句话到底是什么意思,因为那是属于算法与数据结构的范畴,非计算机专业的Java爱好者恐怕不会在意什么算法,而且这也离我的文章的主题远了点.不过我还是很希望能有人跟我讨论一下这个算法.(如果你是Java高手,你应该发现这里的替换方法与之前的撤消联起来有点毛病,我还不知道怎么解决)

每当查找完事以后,应该让JTextArea的对象选中一段文本表明已经找到.但是结果是不行!可以找到文本,但无法选中.我用一般的requestFocus()就是这个结果.后来我用的是比request生硬的多的grab, grabFocus(),这才解决了文本无法选中的问题.

一切查找工作都完事了(?),总觉得少了点什么东西.是什么呢?没有默认键(就是对话框刚一出现就被(也永远被)选中的那个按钮).我试了JButton类的setDefaultButton(boolean)的方法,可是这不是我期望的那种效果.不过我还是找到了解决方法:

JDialog dlg=new JDialog(...);

JButton OK=new JButton("OK");

dlg.getContentPane().setLayout(new FlowLayout());

dlg.getContentPane().add(OK);

dlg.getRootPane().setDefaultButton(OK); // 默认键

dlg.setSize(480, 320);

dlg.show();

搞定关键字高亮显示?要是搞定了我肯定会告诉各位的.那是个很难的课题.

要继续写下去吗? (下次是文件I/O)

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有