java记事本开发
今天我想要分享的是一个用java写的一个记事本程序。我知道现在市面上有各种各样的记事本了,但是我发现有的写的功能不够完善,或者是代码层次结构不够清晰,有的甚至看了之后云里雾里的,有的还不乏了非常明显的bug,我现在分享的这个记事本程序基本上把代码层次都抽分出来,并修复了一些已知bug。先看一下界面效果图,快捷键我都已经全部加上了,只是没有在界面上标明而已,一般常用的那几个快捷键都直接使用即可!
该程序主要功能有:打开、保存、另存为、退出、新建、黏贴、复制、全选、剪切、删除、查找、替换、转到、修改字体、自动换行、查看帮助等功能。目前未完善的功能有自动显示标题。
首先我是使用了swt这个插件在eclipse中开发的,该程序在跨平台使用时会有稍许不同之处!安装swt在这里就不再重复说明,我们直接来新建工程吧!
一、新建一个swt工程,命名为Note,这个时候我们说需要依赖的swt中的jar包会自动导入了,如果你的有导入jar包的问题,你也可以手工导入jar包。
之后建立3个包来存放我们的类:dialog(主要是一些弹窗类的实现)、noteUi(存放主要的实现类)、Utils(抓哟存放一些公有的工具文件)。
二、在noteUI包中新建一个住类,我们命名为Note1.java好了,额,忘记说了,这个Note1.java是一个swt的new Appliction Windows的类,在里面就可以通过design来制作这个窗口的布局,主要就是menu bar,等,具体布局方式可以看这个图:
布局写好之后,我们就可以添加各种事件了
三、添加快捷键
//快捷键部分
open.setAccelerator(SWT.CTRL |'o');
save_file.setAccelerator(SWT.CTRL |'s');
quit.setAccelerator(SWT.CTRL |'p');
select_all.setAccelerator(SWT.CTRL + 'a');
new_file.setAccelerator(SWT.CTRL |'n');
new_file.setAccelerator(SWT.CTRL + 'N'); //新建文件快捷键
undo.setAccelerator(SWT.CTRL + 'Z'); //撤销快捷键
cut.setAccelerator(SWT.CTRL + 'T'); //剪切快捷键
copy.setAccelerator(SWT.CTRL + 'C'); //复制快捷键
paste.setAccelerator(SWT.CTRL + 'V'); //粘贴快捷键
delete.setAccelerator(SWT.DEL); //删除快捷键
find.setAccelerator(SWT.CTRL + 'F'); //查找快捷键
find_next.setAccelerator(SWT.F3); //查找下一处快捷键
replace.setAccelerator(SWT.CTRL + 'H'); //替换快捷键
go_to.setAccelerator(SWT.CTRL + 'G'); //转到快捷键
四、我们先从简单的做起吧!,先写查看帮助吧!
MenuItem look_help = new MenuItem(menu_5, SWT.NONE);
look_help.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
UiUtils.showMessageDialog(shell, "帮助","欢迎查看我的博客:http://blog.csdn.net/sdksdk0!");
}
});
look_help.setText("查看帮助");
当然,对于这个“关于我们”的话可以使用一个弹窗来写,新建一个swt窗口文件,那么我们可以这样来调用:这个界面是具体的实现跨越看我文末提供的源码。
MenuItem menuItem_15 = new MenuItem(menu_6, SWT.NONE);
menuItem_15.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
About_us as=new About_us();
as.open();
}
});
五、然后我们可以来看一个字体的设置,主要是调用系统本身的api就可以了,调用这个窗体然后来使用!更改颜色的部分我暂时只加了三种颜色,其他的颜色你可以自己加上,
//字体设置
font.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
FontDialog fd=new FontDialog(shell,SWT.None);
Font oldFont=getText().getFont();
if(oldFont!=null){
fd.setFontList(oldFont.getFontData());
}
FontData fontData=fd.open();
if(fontData==null){
return;
} Color c=new Color(shell.getDisplay(),fd.getRGB().red,fd.getRGB().green,fd.getRGB().blue);
text.setForeground(c);
final Display display=Display.getDefault();
Font newFont=new Font(display,fontData);
getText().setFont(newFont);
if(oldFont!=null){
oldFont.dispose();
}
}
});
六、在这个记事本的最下面一行有一个可以记录当前时间的,我们可以使用Data来写,然后通过SimpleDateFormat来格式化显示日期时间。
Label lblNewLabel = new Label(sashForm, SWT.NONE);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss"); lblNewLabel.setText("指令汇科技欢迎您的使用,现在是:" + sdf.format(new Date()));
sashForm.setWeights(new int[] {309, 24});
七、我们可以来看一下复制、黏贴、剪切、全选的书写,其他这个应该是最简单了了,因为这个可以直接调用以下方法。全选就直接使用text.selectAll();就可以了。
MenuItem cut = new MenuItem(menu_2, SWT.NONE);
cut.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
getText().cut();
}
});
cut.setText("剪切"); MenuItem copy = new MenuItem(menu_2, SWT.NONE);
copy.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
text.copy();
}
});
copy.setText("复制"); MenuItem paste = new MenuItem(menu_2, SWT.NONE);
paste.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
getText().paste();
}
});
paste.setText("黏贴");
八、这个时候我们来写一下查找替换等,这个时候新建一个弹出的方法更好了,
/**
* Create contents of the dialog.
*/
private void createContents() {
shell = new Shell(getParent(), getStyle());
shell.setSize(445, 137);
shell.setLocation(780, 300);
shell.setText("\u67E5\u627E"); textContent = new Text(shell, SWT.BORDER);
textContent.addKeyListener(new KeyAdapter() {
/**
* 为查找编辑框添加事件,以同步查找按钮的更新
* 有内容则显示查找,否则显示为不可点击
*/
public void keyReleased(KeyEvent e) {
if(textContent.getText() != ""){
find_next.setEnabled(true);
chazhao = true;
}else{
find_next.setEnabled(false);
chazhao = false;
}
}
});
textContent.setBounds(99, 10, 204, 22); find_next = new Button(shell, SWT.NONE);
find_next.setEnabled(false);
find_next.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
pareStr = Util.shell.getText_1(); //获取主窗口文本框内容 true
index = pareStr.indexOf(textContent.getText(),index); //获取查找串在母串中的从index处开始的位置
if(index == -1){
JOptionPane.showMessageDialog(null, "找不到\""+textContent.getText()+"\"","记事本", JOptionPane.ERROR_MESSAGE);
}
int end = index+textContent.getText().length();//获得渲染的结束位置
Util.shell.selectContent(index, end);
index = index+textContent.getText().length();
}
});
find_next.setBounds(329, 6, 99, 27);
find_next.setText("\u67E5\u627E\u4E0B\u4E00\u5904(F)"); Label lblNewLabel = new Label(shell, SWT.NONE);
lblNewLabel.setBounds(10, 10, 85, 22);
lblNewLabel.setText("\u67E5\u627E\u5185\u5BB9(&N):"); Button quxiao = new Button(shell, SWT.NONE);
quxiao.addSelectionListener(new SelectionAdapter() {
/**
* 为取消按钮设置事件
*/
public void widgetSelected(SelectionEvent e) {
shell.setVisible(false);
}
});
quxiao.setBounds(329, 65, 100, 27);
quxiao.setText("\u53D6\u6D88"); Button qufen = new Button(shell, SWT.CHECK);
qufen.addSelectionListener(new SelectionAdapter() {
/**
* 判断是否区分大小写,若是,则改变
*/
public void widgetSelected(SelectionEvent e) {
qf = qufen.getSelection();
}
});
qufen.setBounds(10, 65, 149, 27);
qufen.setText("\u533A\u5206\u5927\u5C0F\u5199(&C)"); Label label1 = new Label(shell, SWT.NONE);
label1.setText("\u66FF\u6362\u4E3A(&F):");
label1.setBounds(10, 38, 72, 22); replaceText = new Text(shell, SWT.BORDER);
replaceText.addKeyListener(new KeyAdapter() {
/**
* 为替换编辑框添加事件,以同步替换按钮的更新
* 有内容则显示替换,否则显示为不可点击
*/
public void keyReleased(KeyEvent e) {
if(replaceText.getText() != ""){
replaceBtn.setEnabled(true);
}else{
find_next.setEnabled(false);
}
}
});
replaceText.setBounds(99, 38, 204, 22); replaceBtn = new Button(shell, SWT.NONE);
replaceBtn.addSelectionListener(new SelectionAdapter() {
/**
* 替换按钮事件
*/
public void widgetSelected(SelectionEvent e) {
pareStr = Util.shell.getText_1(); //获取主窗口文本框内容 true
pareStr = pareStr.replaceFirst(textContent.getText(), replaceText.getText());
Util.shell.showText(pareStr);
}
});
replaceBtn.setText("\u66FF\u6362(&R):");
replaceBtn.setEnabled(false);
replaceBtn.setBounds(329, 32, 99, 27);
我们在之前的主类,即Note1中添加相应的调用就可以了,例如:
replace.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
FindWindow fw = new FindWindow(shell,SWT.DIALOG_TRIM);
fw.open();
}
});
查找替换等都是一样的,这里就不再重复说明。
九、至于跳转的话这样就可以了:
queding.addSelectionListener(new SelectionAdapter() {
/**
* 确定跳转到某行
*/
public void widgetSelected(SelectionEvent e) {
int n = Integer.parseInt(goto_line.getText());
goto_line.setText(""+ n + "");
Util.shell.gotoOneLine(1);
}
});
十、接下来就是最重要的文件打开 和保存等操作了,一般这个地方的bug最多
那我们就先来看看打开文件的操作吧,我使用的是gbk编码来读取文件的,我之前发现如果默认编码的话读取文件有乱码现象,所以我就直接加gbk了,简单粗暴
// 打开
open.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
FileDialog fd = new FileDialog(shell, SWT.None);
String file = fd.open();
File f = new File(file);
BufferedInputStream bis = null;
if (f.exists() && f.isFile()) {
try {
bis = new BufferedInputStream(new FileInputStream(f));
byte[] bs = new byte[1024];
int length = 0;
StringBuffer sb = new StringBuffer();
while ((length = bis.read(bs, 0, bs.length)) != -1) {
sb.append(new String(bs, 0, length,"gbk"));
}
text.setText(sb.toString());
} catch (Exception e1) {
e1.printStackTrace();
UiUtils.showMessageDialog(shell, "出错了",e1.getMessage());
} finally {
if(bis!=null){
try {
bis.close();
} catch (IOException e1) {
UiUtils.showMessageDialog(shell, "出错了",e1.getMessage());
}
}
} } else {
UiUtils.showMessageDialog(shell, "出错了",
"文件" + f.getName() + "不存在");
}
}
});
十一、之后就是写保存文件的代码了,保存的时候有两种方法,一种是直接保存,另一种是另存为。我们采用FileOutputStream来从程序写出到文件中。
public class SaveMethod {
/**
* 将保存的两种方法分装成类,方便调用
* 保存
* 另存为
*/
public void Save(){ /**
* 保存文件
*/
if(Util.shell.fileDir!=null ){ //表示该文件有目录,保存时直接保存,不需要弹窗
Util.shell.shell.setText((new File( Util.shell.fileDir.trim())).getName());//获取文件名(不含路径)用于设置title
FileOutputStream fileWriter;
try {
fileWriter = new FileOutputStream(Util.shell.fileDir);
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(fileWriter,"gbk"));
out.write(Util.shell.getText().getText());
out.close();
fileWriter.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
else{//否则为从未保存过,则调用另存为窗口
SaveAs();
}
} public void SaveAs(){
/**
* 将另存为这个方法进行封装,方便调用
*/
FileDialog dialog = new FileDialog(Util.shell.shell,SWT.SAVE);
dialog.setFilterPath(System.getProperty("C:\\Documents and Settings"));//设置打开默认的路径
dialog.setFilterExtensions(new String[]{"*.txt","*.sql","*.java","*.doc"});
String file = dialog.open();//打开窗口,返回用户所选的文件目录
if(file != null){
Util.shell.fileDir = file;//将文件目录保存下来,方面之后的使用
}
if ( file != null )
{
Util.shell.shell.setText((new File( file.trim())).getName());//获取文件名(不含路径)用于设置title
FileOutputStream fileWriter;
try {
fileWriter = new FileOutputStream(file);
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(fileWriter,"gbk"));
out.write(Util.shell.getText().getText());
out.close();
fileWriter.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
十二、最后我们写一下退出吧,如果你想偷懒的话直接用System.exit(0);也是可以实现这个功能的,但是我觉得吧!这样直接退出不太友好吧!所以我写了下面这种优化的退出方法!
若是保存则说明存在fileDir,直接调用保存的函数即可,若不存在fileDir则说明文件时新打开的,还没确定过路径,因此跳转另存为窗体。
首先定义一个全局变量String fileDir = null;将其赋值为空,默认所有的文件都未保存
接着不管是打开文件,还是另存为文件,都将文件所在目录(包括文件名以及后缀名)记录在fileDir中,最后在保存事件中确定fileDir是否为空即可。
public void quit(){
/**
* 退出函数退出时进行判断是否需要保存
*/
String tips;
if(Util.shell.fileDir != null || Util.shell.getText().getText() != ""){ //文件目录不为空,说明有打开着的文件,需要询问是否保存
if(Util.shell.fileDir == null){
tips = "文件 无标题 的文字已经改变。\n"+"想保存文件吗";
}else{
tips = "文件 " +Util.shell.fileDir + " 的文字已经改变。\n"+"想保存文件吗";
}
int n=JOptionPane.showConfirmDialog(null, tips,"记事本",JOptionPane.YES_NO_CANCEL_OPTION);
if(n==0){ //是 返回0 否返回1 取消 返回2
SaveMethod savemethod = new SaveMethod();
savemethod.Save(); //点是,则保存文件然后打开文件
}else if(n==1){ //返回否
System.exit(0);
}else if(n==2){ //返回取消
return ;
}
System.exit(0);
}else{
if(Util.shell.getText().getText() != ""){ //若目录为空,但是内容不为空,说明有内容但未保存,提示之
tips = "文件 无标题 的文字已经改变!\n"+"想保存文件吗?";
int n=JOptionPane.showConfirmDialog(null, tips,"记事本",JOptionPane.YES_NO_CANCEL_OPTION);
if(n==0){ //是 返回0 否返回1 取消 返回2
SaveMethod savemethod = new SaveMethod();
savemethod.Save(); //点是,则保存文件然后打开文件
}else if(n==1){ //返回否
System.exit(0);
}else if(n==2){ //返回取消
return ;
}
System.exit(0);
}else{ }
}
System.exit(0);
}
写在最后,我们这里还封装了一个弹窗的utils类
public class UiUtils { /**
* 显示普通对话框的工具类
* @param shell
* @param title
* @param message
*/
public static void showMessageDialog( Shell shell, String title, String message){
MessageBox mb=new MessageBox( shell, SWT.None);
mb.setText(title);
mb.setMessage(message);
mb.open();
}
}
总结:技术源于思维,我觉得首先在编程之前还是要有一个整体的想法构思,不要一上来就直接写代码了,首先应该想想你要做什么东西,怎么个做法来实现!对于可重用的代码尽量封装起来,让代码整体看起来更简洁明了。坚持学习,坚持分享!
源码下载地址:点击打开链接http://download.csdn.net/detail/sdksdk0/9501286
java记事本开发的更多相关文章
- Java WebService 开发简单实例
Web Service 是一种新的web应用程序分支,他们是自包含.自描述.模块化的应用,可以发布.定位.通过web调用.Web Service可以执行从简单的请求到复杂商务处理的任何功能.一旦部署以 ...
- 使用Eclipse+Maven+Jetty构建Java Web开发环境(几个教程综合集成2014发行)
工作需要使用Jetty由于web集装箱,得知Eclipse+Maven+Jetty该组合是非常好的,因此,要在网上找了很多教程,但不写或多或少特定的或过时的内容而导致最终的配置失败,易于配置为未来的同 ...
- Java 高级开发必修知识---反射
Class类的使用 1) 在面向对象的世界里,万事万物皆对象 A. Java语言中,普通数据类型,静态成员不是对象,其他皆对象 B. 每一个类也是对象 C. 类是java.lang.Class类的实例 ...
- JAVA之旅(一)——基本常识,JAVA概念,开发工具,关键字/标识符,变量/常量,进制/进制转换,运算符,三元运算
JAVA之旅(一)--基本常识,JAVA概念,开发工具,关键字/标识符,变量/常量,进制/进制转换,运算符,三元运算 Android老鸟重新学一遍JAVA是什么感觉?枯燥啊,乏味啊,而且归纳写博客,都 ...
- Java 集成开发环境的介绍及下载
集成开发环境(integrated development environment,JDE) 之前成功运行了Java小程序是经历了先在笔记本中编写源代码,然后通过命令行运行打开javac编译源文件, ...
- Java Web开发和Python Web开发之间的区别
今天的文章讨论了Java Web开发和Python Web开发之间的区别.我不鼓励我们在这里从Java Web迁移到Python Web开发.我只是想谈谈我的感受.它不一定适合所有情况,仅供我们参考. ...
- java web 开发入门实例
学习是个技巧活,关键是要找到重点的地方,新手在这方面的坑尤其多.看别人的教程一步一步的跟着做,隔几步就遇到一个新知识点,忍不住就百度往深处了解,一晃半天就过去了. 有的知识点要深入学习的,有的是了解下 ...
- Java后端开发常用工具
Java后端开发常用工具推荐: 俗话说,工欲善其事,必先利其器.不过初学时候不大建议过度依赖IDE等过多工具,这会让自己的编程基础功变得很差,比如各种语法的不熟悉,各种关键字比如synchronize ...
- java web 开发快速宝典 ------电子书
http://www.educity.cn/jiaocheng/j10259.html 1.2.1 JDk 简介 JDK是Sun公司在1995年推出的一套可以跨操作系统平台编译和运行Java程序的开 ...
随机推荐
- Angular1.x使用小结
之前工作以Angular1.x为主,主要做业务系统,以后工作中技术栈可能以vue为主,在此对Angular1.x的使用做一个简单总结,这里使用1.5+版本. 基本概念 1.依赖注入 依赖注入,在ang ...
- 前端性能监控系统 & 前端数据分析系统
前端监控系统 目前已经上线,欢迎使用! 背景:应工作要求,需要整理出前端项目的报错信息,尝试过很多统计工具,如: 腾讯bugly.听云.OneApm.还有一个忘记名字的工具. 因为各种原因,如: 统计 ...
- SSH执行hql报错:Caused by: org.hibernate.hql.ast.QuerySyntaxException: user is not mapped [from user where username = ?]
报错信息: ERROR Dispatcher:38 - Exception occurred during processing request: user is not mapped [from u ...
- python 网路爬虫(二) 爬取淘宝里的手机报价并以价格排序
今天要写的是之前写过的一个程序,然后把它整理下,巩固下知识点,并对之前的代码进行一些改进. 今天要爬取的是淘宝里的关于手机的报价的信息,并按照自己想要价格来筛选. 要是有什么问题希望大佬能指出我的错误 ...
- 在Linux服务器部署 .NET-Core 项目
一.文章概要 这篇文章是讲述一个Linux 新手将 .NET-Core 项目部署在 Linux 服务器上的一个记录,以及在部署期间遇到的问题以及解决办法.有不恰当的地方.欢迎大神指正. 二.前期准备 ...
- [SPOJ 10628]Count on a tree
Description 题库链接 求不带修改的树上路径第 \(K\) 小. \(N\) 个节点 \(M\) 组询问. \(1\leq N,M\leq 100000\) Solution 主席树维护树上 ...
- [JSOI2007]字符加密
题目描述 喜欢钻研问题的JS 同学,最近又迷上了对加密方法的思考.一天,他突然想出了一种他认为是终极的加密办法:把需要加密的信息排成一圈,显然,它们有很多种不同的读法. 例如‘JSOI07’,可以读作 ...
- NOIP 2013
Prob.1 转圈游戏 找到循环节,然后快速幂.代码: #include<cstdio> #include<cstring> #include<iostream> ...
- hdu 5427(水)
题意:按照年龄从小到大排序 名字中可能有空格什么的,处理下即可 #include<iostream> #include<cstdio> #include<cstring& ...
- HDU1348 Wall 凸包
题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=1348 题意:给出一个凸包,求出与凸包距离 L的外圈周长 凸包模板题,练练Andrew算法求出凸包周长再 ...