先看效果:截图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

如果觉得不错的话 就在GitHub里面给我点亮 Star吧

JavaSwing实现的文本比较软件的更多相关文章

  1. [转]Windows 下常用盗版软件的替代免费软件列表

    当您看完这篇文章,我相信您完全可以把您 Windows 系统里安装的盗版软件清理干净而不影响您的任何工作.如果您仍然希望并且喜欢.享受做一个盗版软件用户的话,那也没有办法,但是请您记住,非常非常重要的 ...

  2. 【软件分析与挖掘】Vision of Software Clone Management: Past, Present, and Future (Keynote Paper)

    abstract: 代码克隆的综述 S1    INTRODUCTION AND MOTIVATION 代码克隆的利弊: 利:可以有效地去耦合,避免其他一些可能的错误: 弊:当被复制的那段code中带 ...

  3. 你不得不用的MAC软件开发工具软件,个个万里挑一

    作为软件行业,尤其是程序员,Mac上都不得不安装一些必备的MAC软件开发工具软件,下面给大家分享一些必装的MAC软件开发工具软件,以备日后之需,有备无患. 其中,包含各种语言的主流 IDE.开发辅助. ...

  4. JavaSwing程序设计(目录)

    一.JavaSwing 概述 JavaSwing 图形界面概述 二.JavaSwing 基本组件 JLabel(标签) JButton(按钮) JTextField(文本框) JPasswordFie ...

  5. Mac常备必用的软件-mac软件推荐

    目录 终端工具 iTerm2,做开发的都用它代替系统自带的“终端”,免费软件,官网直接下载即可. 文件比较工具 meld,开源免费的文件/文本比较工具. 安装方法:brew cask install ...

  6. Java-Swing中使用Web富文本编辑器

    资料下载 (截取出了邮件发送的功能.) 2018/11/10 因为要 win7 电脑 IE 8 的原因,使用了 jxBrower 拓展,更容易使用,参考链接(推荐) 问题介绍 window客户端软件的 ...

  7. [日常] 免费的文本比较工具Meld使用

    需要在linux桌面环境进行文件比较的时候,发现的一款文本比较工具,并且还有windows版本.之前一直在windows下使用的是beyond compare这个的破解版,这个软件本身是收费的而且还非 ...

  8. 异想家Win10常用的软件推荐

    本文总结一下自己日常使用Win10中涉及到的好用小软件,那些装机必备的软件在这里就不一一列出了.我重点想推荐一些自己觉得好用,符合自己偏好,但又不是每个人都知道的小工具: Rolan:一款类似于Win ...

  9. DBImport V3.7版本发布及软件稳定性(自动退出问题)解决过程分享

    DBImport V3.7介绍: 1:先上图,再介绍亮点功能: 主要的升级功能为: 1:增加(Truncate Table)清表再插入功能: 清掉再插,可以保证两个库的数据一致,自己很喜欢这个功能. ...

随机推荐

  1. DRAM三种刷新方式(转载)

    设DRAM中电容的电荷每2ms就会丢失,所以2ms内必须对其补充.补充电荷是按行来进行的,为了[全部]内存都能保住电荷,必须对[所有]的行都得补充. 假设刷新1行的时间为0.5μs(刷新时间是等于存取 ...

  2. Django搭建示例项目实战与避坑细节

    Django 开发项目是很快的,有多快?看完本篇文章,你就知道了. 安装 Django 前提条件:已安装 Python. Django 使用 pip 命令直接就可以安装: pip install dj ...

  3. PyQt学习随笔:重写setData方法截获Model/View中视图数据项编辑的注意事项

    根据<PyQt学习随笔:Model/View中视图数据项编辑变动实时获取变动数据的方法>可以重写从PyQt的Model类继承的setData方法来实时截获View中对数据的更改,但需要注意 ...

  4. PyQt(Python+Qt)学习随笔:Qt Designer中部件mimimumSize和maximumSize的含义

    1.mimimumSize mimimumSize表示部件能被缩小到的最小尺寸,单位为像素,缩小到该尺寸后不能再进一步缩小了.如果部件在布局管理器中,且布局管理器也设置了最小尺寸,则部件本身的最小尺寸 ...

  5. sqlite 数据库与mysql 数据库使用区别记录

    遇到了就记点儿. 1.sqlite 中,设置外键关联,没啥用.只有mysql 中可用.

  6. web安全漏洞

    1.什么是Web漏洞 WEB漏洞通常是指网站程序上的漏洞,可能是由于代码编写者在编写代码时考虑不周全等原因而造成的漏洞.如果网站存在WEB漏洞并被黑客攻击者利用,攻击者可以轻易控制整个网站,并可进一步 ...

  7. 我摊牌了,大厂面试Linux就这5个问题

    说真的,这就是<我想进大厂>系列第八篇,但是Linux的问题确实很少,就这样,强行编几个没有营养的问题也没啥意义. 1.CPU负载和CPU利用率的区别是什么? 首先,我们可以通过uptim ...

  8. python冒泡算法联系代码

    root@(none):~/python# python maopao.py[6, 11, 13, 22, 99]root@(none):~/python# cat maopao.py #!/usr/ ...

  9. CSP-S2020 DP专项训练

    前言 \(\text{CPS-S2020}\) 已然临近,而 \(\text{DP}\) 作为联赛中的常考内容,是必不可少的复习要点,现根据教练和个人刷题,整理部分好题如下(其实基本上是直接搬--). ...

  10. 协程gevent学习

    import gevent def f1(): print(11) gevent.sleep(2) print(33) def f2(): print(22) gevent.sleep(1) prin ...