JavaSwing实现的文本比较软件
先看效果:截图1

截图2:

实现思路:
1、界面UI设计
2、功能点 : a 打开文件进行比较 b 粘贴内容进去比较 c 提示帮助 d 窗口可以任意拖动
3、文本比较算法
java类 :
MainUI 类实现界面设计 Read_File 类实现文件读取 DNASequence 类文本比较算法
项目结构:

源代码:
Star.java
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants; public class Star
{
public static void main(String args[]) throws BadLocationException
{
//初始化界面
Windowm windowm = new Windowm(); //属性设置
SimpleAttributeSet attrset = new SimpleAttributeSet();
//字体大小
StyleConstants.setFontSize(attrset,16);
//获取JTextPane对象
Document docs1=windowm.text1.getDocument();
//设置初次显示文本
docs1.insertString(docs1.getLength(), "手动输入或者选择文件打开", attrset);
Document docs2=windowm.text2.getDocument();
docs2.insertString(docs2.getLength(), "手动输入输入或者选择文间打开\n点击核对试试\n红色表示错误字符\n蓝色表示多余或缺失字符", attrset);
}
}
MainUI.java
import algorithm.DNASequence;
import open_file.Read_File; import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import javax.swing.*;
import javax.swing.text.Document;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants; class Windowm extends JFrame
{
String path1;//第一个文件目录
String path2;//第二个文件目录
String File1;//第一个文件
String File2;//第二个文件
int point;//保存当前活动窗口 private static final long serialVersionUID = 1L;
JPanel myPanel1 = new JPanel();//面板1.1
JPanel myPanel2 =new JPanel();//面板2.1
JPanel myPanel3 =new JPanel();//面板3
JPanel myPanel4 =new JPanel();//面板4
JTextPane text1=new JTextPane();
JTextPane text2=new JTextPane(); JButton bt1 = new JButton("打开文档1");
JButton bt2 = new JButton("打开文档2");
JButton bt3 = new JButton("核对"); JPopupMenu jm = new JPopupMenu();//右键菜单
JMenuItem copy = new JMenuItem("复制");//菜单项
JMenuItem path = new JMenuItem("粘贴");
JMenuItem cut = new JMenuItem("剪切");
JMenuItem help = new JMenuItem("帮助");
JMenuItem about = new JMenuItem("关于"); JScrollPane scro1=new JScrollPane(text1);//添加滚动条
JScrollPane scro2=new JScrollPane(text2);//添加滚动条 JSplitPane jSplitPane =new JSplitPane();//设定为拆分布局
JSplitPane jSplitPane2 =new JSplitPane();//设定为拆分布局
JSplitPane jSplitPane3 =new JSplitPane();//设定为拆分布局 public Windowm()
{
setVisible(true);
jm.add(copy);
jm.add(path);
jm.add(cut);
jm.add(help);
jm.add(about); myPanel3.add(bt1);
myPanel3.add(bt2);
myPanel4.add(bt3); this.setTitle("欢迎使用文本比较软件");
this.setBounds(100, 100, 600, 500);
jSplitPane.setContinuousLayout(true);//操作箭头,重绘图形
jSplitPane2.setContinuousLayout(true);//操作箭头,重绘图形
jSplitPane3.setContinuousLayout(true);//操作箭头,重绘图形 jSplitPane2.setOrientation(JSplitPane.VERTICAL_SPLIT);//垂直方向
jSplitPane.setOrientation(JSplitPane.HORIZONTAL_SPLIT);//水平方向
jSplitPane3.setOrientation(JSplitPane.VERTICAL_SPLIT);//垂直方向 myPanel1.setBorder(BorderFactory.createLineBorder(Color.green));
myPanel2.setBorder(BorderFactory.createLineBorder(Color.red));
myPanel3.setBorder(BorderFactory.createLineBorder(Color.yellow));
myPanel4.setBorder(BorderFactory.createLineBorder(Color.blue)); jSplitPane.setLeftComponent(scro1);//左右布局中添加组件 ,面板1
jSplitPane.setRightComponent(scro2);//左右布局中添加组件 ,面板2 jSplitPane2.setTopComponent(myPanel3);//上下布局中添加组件 ,面板1
jSplitPane2.setBottomComponent(jSplitPane);//上下布局中添加组件 ,面板1 jSplitPane3.setTopComponent(jSplitPane2);
jSplitPane3.setBottomComponent(myPanel4); jSplitPane.setDividerSize(5);//设置分割线的宽度
jSplitPane2.setDividerSize(5);//设置分割线的宽度
jSplitPane3.setDividerSize(5);//设置分割线的宽度
setContentPane(jSplitPane3);//设置为父模块 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); copy.addActionListener(new ActionListener()//窗口监听
{
public void actionPerformed(ActionEvent e4)//菜单项
{
try{
text1.copy();
text2.copy();
}catch(Exception e1){
}
}
}
);
path.addActionListener(new ActionListener()//窗口监听
{
public void actionPerformed(ActionEvent e4)//菜单项
{
try{
if(point==1)//由于有两个窗口,因此设计point来确定粘贴在某个窗口
text1.paste();
else
text2.paste();
}catch(Exception e1){
}
}
}
);
cut.addActionListener(new ActionListener()//窗口监听
{
public void actionPerformed(ActionEvent e4)//菜单项
{
try{
text1.cut();
text2.cut();
}catch(Exception e1){
}
}
}
);
help.addActionListener(new ActionListener()//窗口监听
{
public void actionPerformed(ActionEvent e4)//菜单项
{
JOptionPane.showMessageDialog(null,"使用方法:输入或者点击打开两个文本,按核对键进行比较\n红色表示匹配失败,蓝色表示多余,黑色为正常匹配文本","使用指南",JOptionPane.PLAIN_MESSAGE);
}
}
);
about.addActionListener(new ActionListener()//窗口监听
{
public void actionPerformed(ActionEvent e4)//菜单项
{
JOptionPane.showMessageDialog(null,"原创:将军\nQQ 2910001378@qq.com \n人生苦短,欢迎转载","将军原创",JOptionPane.PLAIN_MESSAGE);
}
}
); text1.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON3) {
jm.show(text1, e.getX(), e.getY()); // 弹出菜单
point=1;
}
}
}); text2.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON3) {
jm.show(text2, e.getX(), e.getY()); // 弹出菜单
point=2;
}
}
}); jSplitPane.addComponentListener(new ComponentAdapter() {//拖动窗口监听
public void componentResized(ComponentEvent e) {
jSplitPane.setDividerLocation(jSplitPane3.getWidth()/2-7);//设置第一条宽度
}
});
jSplitPane2.setDividerLocation(50);//设定分割线的距离左边的位置
jSplitPane3.addComponentListener(new ComponentAdapter() {//拖动窗口监听
public void componentResized(ComponentEvent e) {
jSplitPane3.setDividerLocation(jSplitPane3.getHeight()-50);//设置第三条高度
}
}); bt1.addActionListener(new ActionListener()//窗口监听
{
public void actionPerformed(ActionEvent e4)//菜单项
{
try{
text1.setText("");
JFileChooser jfc=new JFileChooser();
jfc.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES );
jfc.showDialog(new JLabel(), "选择");
File file=jfc.getSelectedFile();
path1=file.getAbsolutePath();//获取文件绝对地址
new Read_File(path1);
File1= Read_File.getFile();
SimpleAttributeSet attrset = new SimpleAttributeSet();
StyleConstants.setFontSize(attrset,16);//设置字号
Document docs=text1.getDocument();
docs.insertString(docs.getLength(), File1, attrset);
}catch(Exception e1){
}
}
}
);
bt2.addActionListener(new ActionListener()//窗口监听
{
public void actionPerformed(ActionEvent e4)//菜单项
{
try{
text2.setText("");
JFileChooser jfc=new JFileChooser();
jfc.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES );
jfc.showDialog(new JLabel(), "选择");
File file=jfc.getSelectedFile();
path2=file.getAbsolutePath();//获取文件绝对地址
new Read_File(path2);
File2= Read_File.getFile();
SimpleAttributeSet attrset = new SimpleAttributeSet();
StyleConstants.setFontSize(attrset,16);//设置字号
Document docs=text2.getDocument();
docs.insertString(docs.getLength(), File2, attrset);
}catch(Exception e1){
System.out.println("选择文件出错");
}
}
}
);
bt3.addActionListener(new ActionListener()//窗口监听
{
public void actionPerformed(ActionEvent e4)//菜单项
{
try{
String dnas1;//算法处理之后的字符串1
String dnas2;//算法处理之后的字符串2
String jtp1;//JTextpane的内容1
String jtp2;//JTextpane的内容2
int len=0; //处理后的字符串长度 jtp1=text1.getText();//获取窗口文本
jtp2=text2.getText();
text1.setText("");//清空之前内容
text2.setText("");
Document docs1=text1.getDocument();
Document docs2=text2.getDocument();
DNASequence dna=new DNASequence(jtp1,jtp2);//通过构造方法传递参数
dna.runAnalysis();
dna.traceback();
dnas1=dna.getString1();//获取处理后的字符串
dnas2=dna.getString2();
char[] s = dnas1.toCharArray();//字符串转Char数组
char[] p = dnas2.toCharArray();
len=dnas1.length();
SimpleAttributeSet set2 = new SimpleAttributeSet();//设置一个属性
StyleConstants.setFontSize(set2,16);//设置字号
for(int i=0;i<len;i++){
if(s[i]=='-'){
StyleConstants.setForeground(set2,Color.BLUE);//设置文字颜色
docs2.insertString(docs2.getLength(),String.valueOf(p[i]), set2);
}else if(p[i]=='-'){
StyleConstants.setForeground(set2,Color.BLUE);//设置文字颜色
docs1.insertString(docs1.getLength(),String.valueOf(s[i]), set2);
}else if(s[i]==p[i]){
StyleConstants.setForeground(set2,Color.black);//设置文字颜色
docs1.insertString(docs1.getLength(),String.valueOf(s[i]), set2);
docs2.insertString(docs2.getLength(),String.valueOf(p[i]), set2);
}else if(s[i]!=p[i]){ StyleConstants.setForeground(set2,Color.red);//设置文字颜色
docs1.insertString(docs1.getLength(),String.valueOf(s[i]), set2);
docs2.insertString(docs2.getLength(),String.valueOf(p[i]), set2);
}else{
System.out.print("考虑更多颜色");
}
} }catch(Exception e1){
System.out.println("选择文件2出错");
}
}
}
);
}
}
Read_File.java
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader; public class Read_File {
static String fileName; public Read_File(String str){
fileName=str;
}
public static String getFile(){
BufferedReader br = null;
StringBuffer sb = null;
try {
br = new BufferedReader(new InputStreamReader(new FileInputStream(fileName),"utf-8")); //这里可以控制编码
sb = new StringBuffer();
String line = null;
while((line = br.readLine()) != null) {
sb.append(line);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
br.close();
} catch (Exception e) {
e.printStackTrace();
}
}
String data = new String(sb); //StringBuffer ==> String
System.out.println("数据为==> " + data);
return data;
} // public static void main(String[] args) {
// new Read_File("1");
// }
}
DNASequence.java
//https://codereview.stackexchange.com/questions/182601/optimizing-needleman-wunsch-algorithm-in-java
public class DNASequence {
protected final String seq_1, seq_2; //要分析的两个序列
public int alignmentScore; //使用Needleman-Wunsch算法
protected Node[][] matrix; //存储分数和缩进
protected final int matchScore, mismatchScore, indel;
//用于打印DNA序列分析的字符串
String top = ""; // Sequence 1
String bottom = ""; // Sequence 2
public DNASequence(String s1, String s2) {
//我使用一个■作为缓冲,这样序列字符串正确对齐
// 在矩阵中使用缩进和分数。
ScoreScheme s = new ScoreScheme(2, -1, -2);
seq_1 = "\u25A0" + s1;
seq_2 = "\u25A0" + s2;
matchScore = s.matchScore;
mismatchScore = s.mismatchScore;
indel = s.indel;
matrix = new Node[seq_1.length()][seq_2.length()];
for (int i = 0; i < seq_1.length(); i++)
matrix[i][0] = new Node(i * indel, i, 0);
for (int i = 0; i < seq_2.length(); i++)
matrix[0][i] = new Node(i * indel, 0, i);
}
//辅助方法,帮助决定使用哪种匹配/不匹配得分。
protected int score(int i, int j) {
if (seq_1.charAt(i) == seq_2.charAt(j))
return matchScore;
else
return mismatchScore;
}
//在本地级别上实现Needleman-Wunsch algo的Helper方法。
protected Node match(int i, int j) {
Node s1,s2,s3;
s1 = new Node(matrix[i-1][j-1].score + score(i, j), i, j);
s2 = new Node(matrix[i-1][j].score + indel, i, j);
s3 = new Node(matrix[i][j-1].score + indel, i, j);
Node largest = new Node(Math.max(s1.score, Math.max(s2.score, s3.score)), i, j);
if (s1.compareTo(largest) == 0)
largest.prev = matrix[i-1][j-1];
else if(s2.compareTo(largest) == 0)
largest.prev = matrix[i-1][j];
else
largest.prev = matrix[i][j-1];
return largest;
}
public Node runAnalysis() {
for (int i = 1; i < seq_1.length(); i++) {
for (int j = 1; j < seq_2.length(); j++){
matrix[i][j] = match(i, j);
}
}
alignmentScore = matrix[seq_1.length()-1][seq_2.length()-1].score;
return matrix[seq_1.length()-1][seq_2.length()-1];
}
//辅助方法,逐步构建分析结果。它将返回
//“尾巴”,因为我们可能还需要做一些工作。
protected Node traceHelper(Node curr) {
while (curr.prev != null) {
if (curr.i - curr.prev.i == 1 && curr.j - curr.prev.j == 1){ // If the path leads diagonal
boolean x = seq_1.charAt(curr.i) == seq_2.charAt(curr.j) ? true : false;
if(x){
top = seq_1.charAt(curr.i) +top;
bottom = seq_2.charAt(curr.j) +bottom;
}else{
top = seq_1.charAt(curr.i) + top;
bottom = seq_2.charAt(curr.j) + bottom;
}
}else if (curr.i - curr.prev.i == 1){ //如果这条路通向山顶
top = seq_1.charAt(curr.i) + top;
bottom = "-" + bottom; //如果这条路通向左边
}else if (curr.j - curr.prev.j == 1){
top = "-" + top;
bottom = seq_2.charAt(curr.j) + bottom;
}
curr = curr.prev;
}
return curr;
}
//从矩阵的最后一个节点回溯到第一个索引节点。
public void traceback() {
Node curr = matrix[seq_1.length()-1][seq_2.length()-1];
curr = traceHelper(curr);
while (curr.i != 0 || curr.j != 0) {
if (curr.i != 0 && curr.j == 0){
curr.prev = matrix[curr.i-1][curr.j];
curr = traceHelper(curr);
}else if (curr.i == 0 && curr.j != 0) {
curr.prev = matrix[curr.i][curr.j-1];
curr = traceHelper(curr);
}
}
//打印DNA序列分析
// System.out.println(top);
// System.out.println(bottom);
}
public String getString1(){
return top;
}
public String getString2(){
return bottom;
}
}
class Node implements Comparable<Node>{
int i, j;
int score;
Node prev;
public Node(int score, int x, int y) {
this.i = x;
this.j = y;
this.score = score;
this.prev = null;
}
public int compareTo(Node n) {
return this.score - n.score;
}
public String toString() {
return ""+score;
}
}
class ScoreScheme {
int matchScore, mismatchScore, indel;
public ScoreScheme(int m1, int m2, int i) {
matchScore = m1;
mismatchScore = m2;
indel = i;
}
}
项目源代码已经上传到我的GitHub仓库 下载点击https://github.com/Wo-com/TextCheck

JavaSwing实现的文本比较软件的更多相关文章
- [转]Windows 下常用盗版软件的替代免费软件列表
当您看完这篇文章,我相信您完全可以把您 Windows 系统里安装的盗版软件清理干净而不影响您的任何工作.如果您仍然希望并且喜欢.享受做一个盗版软件用户的话,那也没有办法,但是请您记住,非常非常重要的 ...
- 【软件分析与挖掘】Vision of Software Clone Management: Past, Present, and Future (Keynote Paper)
abstract: 代码克隆的综述 S1 INTRODUCTION AND MOTIVATION 代码克隆的利弊: 利:可以有效地去耦合,避免其他一些可能的错误: 弊:当被复制的那段code中带 ...
- 你不得不用的MAC软件开发工具软件,个个万里挑一
作为软件行业,尤其是程序员,Mac上都不得不安装一些必备的MAC软件开发工具软件,下面给大家分享一些必装的MAC软件开发工具软件,以备日后之需,有备无患. 其中,包含各种语言的主流 IDE.开发辅助. ...
- JavaSwing程序设计(目录)
一.JavaSwing 概述 JavaSwing 图形界面概述 二.JavaSwing 基本组件 JLabel(标签) JButton(按钮) JTextField(文本框) JPasswordFie ...
- Mac常备必用的软件-mac软件推荐
目录 终端工具 iTerm2,做开发的都用它代替系统自带的“终端”,免费软件,官网直接下载即可. 文件比较工具 meld,开源免费的文件/文本比较工具. 安装方法:brew cask install ...
- Java-Swing中使用Web富文本编辑器
资料下载 (截取出了邮件发送的功能.) 2018/11/10 因为要 win7 电脑 IE 8 的原因,使用了 jxBrower 拓展,更容易使用,参考链接(推荐) 问题介绍 window客户端软件的 ...
- [日常] 免费的文本比较工具Meld使用
需要在linux桌面环境进行文件比较的时候,发现的一款文本比较工具,并且还有windows版本.之前一直在windows下使用的是beyond compare这个的破解版,这个软件本身是收费的而且还非 ...
- 异想家Win10常用的软件推荐
本文总结一下自己日常使用Win10中涉及到的好用小软件,那些装机必备的软件在这里就不一一列出了.我重点想推荐一些自己觉得好用,符合自己偏好,但又不是每个人都知道的小工具: Rolan:一款类似于Win ...
- DBImport V3.7版本发布及软件稳定性(自动退出问题)解决过程分享
DBImport V3.7介绍: 1:先上图,再介绍亮点功能: 主要的升级功能为: 1:增加(Truncate Table)清表再插入功能: 清掉再插,可以保证两个库的数据一致,自己很喜欢这个功能. ...
随机推荐
- PriorityQueue 优先队列的实现
PriorityQueue 的 implementation PriorityQueue即是优先队列.通俗的说就是体育课的时候老师要求从高到低排序,老师能直接一眼看出谁是最高的在班级里.当这个最高的离 ...
- ansible playbook 安装docker
1.新增host配置到/etc/ansible/hosts文件中 [docker] 192.168.43.95 2.配置无密码登录 # 配置ssh,默认rsa加密,保存目录(公钥)~/.ssh/id_ ...
- day4(cookie与session的原理及区别)
1.COOKIE使用和优缺点 1.1 cookie原理:用户名+密码 cookie是保存在用户浏览器端,用户名和密码等明文信息 1.2session使用原理 session是存储在服务器端的一段字符串 ...
- 从内存泄露、内存溢出和堆外内存,JVM优化参数配置参数
内存泄漏 内存泄漏是指程序在申请内存后,无法释放已申请的内存空间,无用对象(不再使用的对象)持续占有内存或无用对象的内存得不到及时释放,从而造成内存空间的浪费.内存泄漏最终会导致OOM. 造成内存泄漏 ...
- 再也不怕 JavaScript 报错了,怎么看怎么处理都在这
在开发中,有时,我们花了几个小时写的 JS 代码,在游览器调试一看,控制台一堆红,瞬间一万头草泥马奔腾而来.至此,本文主要记录 JS 常见的一些报错类型,以及常见的报错信息,分析其报错原因,并给予处理 ...
- Java获取不到请求的真实IP
问题 最近在写博客浏览量的时候,设计了这么一个逻辑:同一个IP浏览一遍文章,5分钟内不刷新次数.就需要在服务器端得到用户的真实IP,我代码是这样写的(从网上找的方法): public static S ...
- Java程序员普遍存在的面试问题以及应对之道(新书第一章节摘录)
其实大多数Java开发确实能胜任日常的开发工作,但不少候选人却无法在面试中打动面试官.因为要在短时间的面试中全面展示自己的实力,这很需要技巧,而从当前大多数Java开发的面试现状来看,会面试的候选人不 ...
- CSP-S2020 DP专项训练
前言 \(\text{CPS-S2020}\) 已然临近,而 \(\text{DP}\) 作为联赛中的常考内容,是必不可少的复习要点,现根据教练和个人刷题,整理部分好题如下(其实基本上是直接搬--). ...
- v-once
v-once 使用了这个指令,那么这个值将只会渲染一次,后续将不会再被更改 初始运行结果: 在控制台中分别修改他们的值: 可以看到使用了v-once指令的插值没有被修改.
- 刚入坑之C#《方法》解说
说好的用一周时间学方法,我都快耽误成两周了.原因就是跟着传智播客的课程做了个飞行棋项目,想要梳理其中的方法却把自己绕晕了.那接下来我先说一下我学到方法的内容,在最后献上飞行器项目的代码,当然是传智播客 ...