`
古尔丹之颅
  • 浏览: 31349 次
  • 性别: Icon_minigender_1
社区版块
存档分类
最新评论

java 云秘通信小项目

阅读更多

         学java也有五个月了吧,学通信也三个月之后,而今我们四人小组用了大概一个月的时间做了这个通信项目,并为其正式命名为“云秘”!,没错,就是云秘,我们的初衷是做一个能集信息收集、管理、查询、共享资源并辅以聊天功能的项目,但是局限于时间不充裕,说来惭愧,现如今只是堪堪实现了其中的些许功能,但是值得欣慰的是我们组每天都在进步,每天都有码代码,即使学校的课程很紧,坚持总会有收获的,既已然收获,便是喜悦的,就不要去计较太多!

        说那么多,现步入正题!我们的通信项目并未涉及数据库,所以很多对于数据,信息的处理用的都是对文件的读写操作!  作为一个通信项目,自然我们要有一个服务器!~



 

		//在指定端口上创建一个服务器
	public void setUpServer(int port){
		try{
			ss = new ServerSocket(port);
			System.out.println("服务器创建成功");
			//等待客户机连接,并设置成循环等待状态
		while(true){				
				Socket client=ss.accept();
				System.out.println("欢迎进入我的服务器");			
				//启动一个线程去处理该对象
				ServerThread st=new ServerThread(client);
				st.start();
				ChatTools.add(st);
			}
		}catch(Exception ef){
			ef.printStackTrace();
		}
	}

 
          这个便是我的服务器,因为是服务器,后台的东西,所以并未做过多的界面处理!运用ServerSocket传入端口号建立服务器,循环等待客户机的连接,每当有客户端连接服务器,便启动一个线程来对该客户端与服务器之间的所有互动进行处理,再者用一个队列将该线程保存起来,后面会用到!

           服务器的所有关键代码其实都在处理客户端的线程中体现了出来,一个好的服务器必须能有条不紊的处理大量的信息,所以服务器处理客户端的线程类一定要严谨!

//处理客户机进入的连接对象
	public void processChat(Socket client){
		try{		
			ins=client.getInputStream();
			out=client.getOutputStream();	
			dis = new DataInputStream(ins);			
			dout=new DataOutputStream(out);
			int t = dis.readInt();			
			while (true) {
				// 如果读到的是1,调用读取消息
				if (t == 1) {
					readMsg();
				}
				// 读到的是2则调用保存注册信息的方法
				if (t == 2) {
					readlogon();
				}
				// 如果读到的是3,则调用核对登陆信息的方法
				if (t == 3) {
					checklogin();
				}
				// 如果读到的是4,则调用群发消息的方法
				if (t == 4) {
					allmsg();
				}
				//如果读到的是5,则调用单聊的方法
				if (t == 5) {
					sendone();
				}
				//如果读到的是6,则调用发送通知的方法
				if (t == 6) {
					sendtxt();
				}
				//如果读到的是7,则调用转发震动的方法
				if (t == 7) {
					readzhen();
				}
				//如果读到8,则调用关闭线程,通知下线的方法
				if( t == 8){
					closeThread();
				}
				//以下两个是发送表格填写的方法
				if(t==HeadConfig.tableQuest){
						readTableQuest();
					}
				if(t==HeadConfig.tableContent){
						readTableContent();
					}
				
				t = dis.readInt();
			}
		} catch (Exception ef) {
			ef.printStackTrace();
		}
	}

             不同的协议分别调用不同的方法,一目了然!关于服务器的便说这么多,但是不得不说一个好的系统,服务器十分重要!!!

 

             下面便说一说我们的客户端!

             打开客户端,首先是一个登陆界面!

 

 

              至于为什么用这张图片做背景,因为本人比较喜欢刘诗诗!

         因为我们做这个项目刚开始设定的使用单位便是班级,所以我们验证信息时用的学号!在这个登陆界面上,我们在左上角更改了java图标,而我们的注册信息的图标也不是摆设!



 

           我们现在注册了一个名为用户1的用户,当单机注册时,用户名以及账号密码会被发送到服务器去,也就是说在登陆界面打开的时候,其实客户端与服务器已经连接了....而服务器会把客户的信息利用IO流存在txt文件里,至于为什么用文件来村,实在是因为鄙人以及我们的小组目前对数据库知识还未掌握,不过目前正在学习中!!注册完了之后,注册界面会关闭并自动跳转回登陆界面!此时我们只要输入刚才注册的账号密码即可 !

 

       当我们单击登陆界面时,客户机会把输入的账号密码发送到服务器去!!服务器会遍历自己存储客户姓名账号密码的的txt文件

// 定义一个核对登陆信息的方法
	public void checklogin() {
		try {
			BufferedReader brd = new BufferedReader(new InputStreamReader(ins));
			// input为发送过来的账号和密码
			String input = brd.readLine();
			try {
				File file = new File(path);// 指定要读取的文件
				if (!file.exists()) {// 如果文件不存在则创建
					file.createNewFile();
				} else {
					// 获取该文件的缓冲输出流
					BufferedReader bufferedreader = new BufferedReader(
							new FileReader(file));
					check(input, bufferedreader);//调用核对信息的方法
					bufferedreader.close();// 关闭输出流
				}
			} catch (Exception ef) {
				ef.printStackTrace();
			}
		} catch (Exception ef) {
			ef.printStackTrace();
		}
	}


// 定义一个核对账号密码的方
	public void check(String str, BufferedReader bufferedreader) {
		String line1="";
		try {
			String line = bufferedreader.readLine();
			if (line != null) {
				if (line.equals(str)) {	//如果文件中读到信息与客户端传入的登陆信息匹配,则返回一个right,通过登陆严重					
					line1 = bufferedreader.readLine();	
					name=line1;
					setName(line1);
					sendcheck("right/"+line1);
					thsendname.start();
//					runjudge.start();	//上线提示						
					ServerTools.add(line1);// 将登陆的用户名添加到队列里							
				} else if (!line.equals(str)) {
					check(str, bufferedreader);
				}				
			} else {
				sendcheck("no");
			}
		} catch (Exception ef) {
		}
	}

 

                通过验证正是进入属于客户自己的界面了!!!附图如下:



          可以看见界面左上角的昵称便是刚才我们注册时的“用户1”;昵称下面便是四个按钮对应四个我们基本实现的功能!

一、  第一个群聊功能---------------------------------------


 



 


        两个继承了JTextPane的显示框,因为一般的现实框并不能实现对于jif表情图片的现实功能!关于表情的发送以及接受我们也是弄了一段时间,这要感谢组员钟楚斌的贡献!因为表情发送其图片的字符串过来,然后又根据其字符串在本地找到相对于的图片再将其显示在JTextPane上,一个表情的可能是插在一段文字中发送过来的,所以难点就是你要去识别它是表情还是消息!先附上读取带有表情文本的读取方法。

//定义一个读取带有表情的消息的方法
	public void readface(String input,JTextPane1 jt_recive){
		int in=0;
		String temp1="";
		String temp2= "";
		String h1 = "expression//";
		String h2 = ".gif";
		
		//如果没有表情
		if((in=input.lastIndexOf("\\"))==-1){
			jt_recive.insert_text(input);
			}
		
		else{//如果有表情
			int mark=-4;//标记上次表情出现的位置
			for(int i=0;i<input.length();i++){
				if(input.charAt(i)=='\\'){
					temp1 = input.substring(mark+4, i);
					jt_recive.insert_text(temp1);	
					
					String loc = input.substring(i+1,i+4);
					int loc_exp = Integer.parseInt(loc);
					jt_recive.insert_icon(h1+loc_exp+h2);
					mark=i;					
					}				
				else{
				temp2 = input.substring(mark+5, input.length());
				
				}
				}
				jt_recive.insert_text(temp2);
				}				
				jt_recive.insertln("");
	}

 

      如此便能成功的读取表情了!看似简单,其中确实颇为费力!

 二、进入通知的编辑,浏览界面,默认进入的编辑界面



 

 

双击进入编辑界面



 

读到的是第一条通知,通知是先保存在文件中的,当用户需要浏览时,才从文件中提取通知内容!

 

再次双击进入的是我们四个功能的总界面,当然你也可以关掉,从刚才我们主界面的四个按钮中分别进入这些界面!



 

三、就是我们对于数据收集以及能提供客户查询相应信息的版块!!






 四、就是我们想实现链接我们学校主页的方法,无奈级数不纯熟,只得弄了个链接wap百度的暂时顶替下

 



 

 

关于网页链接的代码,附上如下:

package 云秘;

 import java.awt.Color;
import java.awt.Desktop;
import java.awt.Font;
import java.net.URL;  
  
import javax.swing.JEditorPane;  
import javax.swing.JFrame;   
import javax.swing.event.HyperlinkEvent;  
import javax.swing.event.HyperlinkListener;  
  
public class News extends JFrame implements Runnable{  
      
    private JEditorPane newsPane;  
    private String newsURL = "http://m.baidu.com";  
      
    public News() {  
          
        try {  
            newsPane = new JEditorPane(new URL(newsURL));  
            newsPane.setBackground(Color.orange);
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
          
        newsPane.addHyperlinkListener(new HyperlinkListener() {  
            @Override  
            public void hyperlinkUpdate(HyperlinkEvent e) {  
                if(e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {  
                    Desktop browser = Desktop.getDesktop();  
                    try {  
                        browser.browse(e.getURL().toURI());  
                    } catch (Exception e1) {  
                        e1.printStackTrace();  
                    }  
                }  
            }  
        });  
        newsPane.setEditable(false);  
        add(newsPane);  
        setSize(400,400);
        setLocation(300,150);
        setVisible(true);  
    }  
    public void stop(){
    	this.dispose();
    }
    public void run(){
    	new News();
    }
}

当然我们实现的聊天功能不止有群聊,还有单聊!!

 



 

 


 当我单击对应的用户时,便弹出与其的对话框,但我们把消息发过去的时候,是把该对象的名字,以及发送的字符串一起发送给服务器的!

jbsend.addMouseListener(new MouseAdapter() {
				public void mouseClicked(MouseEvent e) {
					
						String msg = jt_send.getText();
						threadTwo.sendbyte(5);
						msg=name+"!说:"+msg;
						threadTwo.sendmsg(msg);
						String[] mesg=msg.split("!");
						threadTwo.readface("我"+mesg[1],jt_recive);
						jt_send.setText("");		
				}
			});
			

 

服务器调用转发单聊的方法,首先先根据你发过来对象的名字,找到该对象相对应的线程对象,调用线程的发送方法把你要说的话用他的线程发送给他

 

//定义一个单独处理指定对象发送消息的方法
	public void sendone(){
		String input="";
		try {
			BufferedReader brd = new BufferedReader(new InputStreamReader(ins));
			String mesg = brd.readLine();
			String[] msg=mesg.split("\\!");//截取字符串,按标识符划分成数组
			String name=msg[0];//字符串第一部分便是发送过来对象的名字
			for(int i=0;i<ChatTools.getsize();i++){//遍历存储线程的队列找到相应的线程调用发送方法
				ServerThread st=ChatTools.get(i);
				if(st.getName().equals(name)){
					input=this.getName()+"!"+msg[1];
					st.sendbyte(5);
					st.sendMsg(input);
				}
			}
		}catch (Exception ef) {
			ef.printStackTrace();
		}
	}

 

 

关于读取的方法便是和群聊的方法大同小异了!!

 

如此一来通信项目也搞了一段落,虽然最终的成果并不如我们预期的一般,但是就目前对通信这一块的掌握情况来说,剩下的那些未解决的东西确实只是时间问题而已!譬如说我们的客户上线的提醒问题,譬如说我们的好友列表的问题,所以说搞项目就该有一个持之以恒的心,成功向来不易,轻易得来的成功便不算成功!!!!!!!!!!!

(再次感谢我们小组的其他三个人——杨星,钟楚斌,朱凌峰)

 

 

  • 大小: 44 KB
  • 大小: 99.1 KB
  • 大小: 46.6 KB
  • 大小: 21.4 KB
  • 大小: 130.4 KB
  • 大小: 172.7 KB
  • 大小: 5.8 KB
  • 大小: 10.9 KB
  • 大小: 367.9 KB
  • 大小: 333.7 KB
  • 大小: 12.7 KB
  • 大小: 19.4 KB
  • 大小: 106 KB
  • 大小: 22.1 KB
  • 大小: 26.5 KB
分享到:
评论

相关推荐

    2023年免费在线作业答案东大秋学期语言程序设计在线作业答案.doc

    2023年免费在线作业答案东大秋学期语言程序设计在线作业答案.doc

    电子商务网店系统策划方案书.doc

    电子商务网店系统策划方案书.doc

    基于MATLAB/Simulink的三相电压型SVPWM整流器开环控制仿真模型解析

    内容概要:本文详细介绍了基于MATLAB/Simulink构建的三相电压型SVPWM整流器开环控制仿真模型。模型采用R2015b版本,适用于初学者理解SVPWM的基本原理。主要内容涵盖模型的整体结构、扇区判断逻辑、占空比计算以及PWM生成模块的具体实现。文中还讨论了仿真过程中的一些常见问题及其解决方案,如死区时间的设置、调制比的影响等。仿真结果显示,在10kHz开关频率下,直流母线电压稳定在500V左右,交流侧电流THD约为7.2%,展示了SVPWM的有效性。 适合人群:刚接触电力电子仿真的学生和工程师,尤其是对SVPWM感兴趣的学习者。 使用场景及目标:帮助读者理解SVPWM的工作原理,掌握Simulink建模技巧,熟悉三相电压型整流器的开环控制系统设计。通过动手实践,加深对电力电子器件和控制算法的理解。 其他说明:文中提供了详细的代码片段和参数配置建议,便于读者复现实验结果。同时指出了模型的局限性和改进方向,鼓励读者进行进一步的研究和探索。

    基于遗传算法的微电网运行优化MATLAB代码实现与解析

    内容概要:本文详细介绍了如何使用遗传算法进行微电网运行优化,并提供了完整的MATLAB代码实现。主要内容包括目标函数的设计,如运行成本的计算(燃料成本、维护成本、购电成本),以及约束条件的处理方法,如功率平衡约束和设备出力限制。文中还讨论了遗传算法的具体实现步骤,包括种群初始化、适应度计算、交叉变异操作等,并展示了优化结果的可视化方法。此外,文章分享了一些实用技巧,如种群规模的选择、交叉率和变异率的设置等。 适合人群:具备一定MATLAB编程基础和电力系统基础知识的研究人员、工程师和技术爱好者。 使用场景及目标:适用于希望深入了解微电网优化调度原理并掌握遗传算法应用的技术人员。目标是通过实例代码帮助读者理解和实现微电网运行成本最小化的优化过程。 其他说明:文中提供的代码可以直接用于实验和研究,同时也指出了进一步改进的方向,如引入鲁棒优化、动态调整光伏预测等。

    永磁同步电机单电流控制策略中MTPA与弱磁控制的应用及优化

    内容概要:本文详细探讨了永磁同步电机在单电流控制策略下的MTPA(最大转矩电流比)和弱磁控制的应用。首先介绍了这两种控制方式的基本原理及其切换机制,特别是在额定转速前后的工作模式转换。文中提供了具体的Python、C和Matlab代码片段,展示了如何通过数学建模和算法实现这两种控制方法。此外,还讨论了实际调试过程中遇到的问题及解决方案,如电流跳变、参数敏感性和电流环带宽等问题。最后强调了在不同转速区间内的性能优化措施,确保系统的稳定性和高效运行。 适合人群:从事电机控制系统设计与开发的技术人员,尤其是对永磁同步电机控制有一定了解的研发人员。 使用场景及目标:适用于需要深入了解永磁同步电机控制策略的研究人员和技术开发者,帮助他们掌握MTPA和弱磁控制的具体实现方法以及应对实际调试中常见问题的能力。 其他说明:文章不仅提供了理论分析,还包括大量实践经验分享,有助于读者更好地理解和应用相关技术。

    基于粒子群算法的分布式电源选址定容优化以降低配电网网损

    内容概要:本文详细介绍了利用粒子群算法(PSO)解决分布式电源在配电网中的选址定容问题,旨在将网损降至最低。文中首先解释了粒子群算法的基本原理及其参数设定,如惯性系数、学习因子等,并展示了具体的Python代码实现。接着讨论了适应度函数的设计,特别是如何通过引入电压惩罚机制确保电压稳定。随后,通过一个18节点配电网的实际案例,展示了算法的有效性,结果显示网损显著降低,电压分布更加均衡。此外,还提到了一些实际应用中的注意事项,如地理信息约束和并行计算的应用。 适合人群:从事电力系统优化、智能电网研究的技术人员,尤其是对分布式电源选址定容感兴趣的工程师。 使用场景及目标:适用于需要优化配电网性能的研究机构和技术团队,目标是在不影响电网安全性的前提下,最大化分布式电源的经济效益和社会效益。 其他说明:尽管粒子群算法在理论上有很好的表现,但在实际应用中还需综合考虑更多因素,如投资成本、维护难度等。此外,文中提到的一些技术细节(如并行计算、地理信息约束)对于提高算法效率至关重要。

    matlab基于改进 PSO 算法的 UAV 三维路径规划研究.zip

    matlab

    2023年二级办公软件选择题判断题.docx

    2023年二级办公软件选择题判断题.docx

    威纶通MT6103IP触摸屏与台达伺服Modbus RTU通讯控制实现详解

    内容概要:本文详细介绍了如何使用威纶通MT6103IP触摸屏通过Modbus RTU协议控制台达伺服电机的基本操作。主要内容涵盖硬件连接、触摸屏设置、Modbus RTU通讯配置、控制程序编写、代码分析、在线模拟和实际调试等方面。文中提供了详细的寄存器地址映射和控制逻辑示例,帮助读者理解和实现具体的控制功能。 适合人群:具备一定自动化控制和工业通信基础的技术人员,尤其是从事PLC编程、触摸屏编程和伺服控制系统集成工作的工程师。 使用场景及目标:适用于工业自动化领域的设备控制项目,如贴标机等。主要目标是掌握威纶通触摸屏与台达伺服电机的Modbus RTU通讯方法,实现电机的正反转、停止、使能和脱机等功能。 其他说明:文章不仅提供理论指导,还包括大量实用的操作技巧和调试经验,有助于解决实际应用中的常见问题。

    物联网高并发服务器:基于C#的高效数据接收与处理系统

    内容概要:本文详细介绍了如何构建一个高效的物联网数据接收服务器,能够处理数万个设备的同时连接。该系统采用C#语言,利用Socket异步事件、线程池、状态机协议解析以及EF6+SQLite/MySQL进行数据存储。文中强调了几个关键技术点:使用SocketAsyncEventArgs实现异步通信,通过状态机处理粘包/断包问题,优化EF6批量插入性能,以及使用环形缓冲区池来降低GC压力。此外,还提供了详细的性能测试数据和优化建议。 适合人群:具备一定C#编程基础,对物联网、高并发处理感兴趣的开发者和技术爱好者。 使用场景及目标:适用于需要处理大量物联网设备数据的企业和个人项目。主要目标是提高系统的并发处理能力和数据处理效率,确保在高负载情况下依然保持稳定的性能表现。 其他说明:文中提供的代码片段可以直接用于实际项目中,同时也附带了完整的源码和测试工具,便于快速上手和进一步优化。

    2023年计算机一级等级考试选择题汇总.doc

    2023年计算机一级等级考试选择题汇总.doc

    chromedriver-mac-arm64-136.0.7103.25.zip

    chromedriver-mac-arm64-136.0.7103.25.zip

    永磁同步电机有限集模型预测控制(FCS-MPC)的MATLAB实现及其波形稳定性研究

    内容概要:本文详细介绍了永磁同步电机(PMSM)的有限集模型预测控制(FCS-MPC)算法在MATLAB中的实现过程。首先解释了FCS-MPC的工作原理,即通过遍历8个基本电压矢量并选择使代价函数最小的电压矢量来优化控制性能。接着展示了具体的MATLAB函数实现,包括坐标变换、电流预测、代价函数计算以及最优电压矢量的选择。文中强调了参数设置的重要性,如电感值、电阻值和采样时间等,并讨论了如何通过调整代价函数中的权重系数来改善系统的动态响应。此外,文章还提到了一些实用技巧,如使用persistent变量缓存电压矢量集合、简化预测模型以提高响应速度等。最终,通过仿真验证了FCS-MPC相比传统PI控制的优势,特别是在突加负载情况下的快速恢复能力和较低的电流THD。 适用人群:从事电机控制系统设计的研究人员和技术工程师,尤其是对永磁同步电机控制感兴趣的读者。 使用场景及目标:适用于需要高性能、快速响应的电机控制系统开发,旨在帮助工程师理解和掌握FCS-MPC算法的具体实现方法,从而应用于实际工程项目中。 其他说明:文章提供了详细的代码片段和理论解析,有助于读者深入理解FCS-MPC的工作机制。同时提醒读者注意参数敏感性和调参技巧,确保实际控制效果达到最佳。

    2023年哈工程计算机复试面试题目参考.doc

    2023年哈工程计算机复试面试题目参考.doc

    2023年山大专升本计算机基础试卷.doc

    2023年山大专升本计算机基础试卷.doc

    三菱Q系列PLC四模块48轴运动控制系统编程详解与架构设计

    内容概要:本文详细介绍了基于三菱Q系列PLC的四模块48轴运动控制系统的设计与实现。通过分层架构和模块化设计,确保了系统的可维护性和可移植性。文中展示了如何利用ST语言进行伺服轴参数配置,以及如何通过以太网实现视觉通信和远程I/O管理。此外,还探讨了状态机嵌套用于运动控制的具体应用,以及如何通过结构体封装提高代码的可读性和效率。通信架构方面,采用了UDP广播包和环形缓冲区来提升多设备同步精度。最后,强调了良好的架构设计对于复杂系统的重要意义,使得48轴联动控制变得如同搭建乐高积木一般简单。 适合人群:具备一定PLC编程经验的工程师和技术人员,尤其是从事运动控制和自动化领域的专业人士。 使用场景及目标:适用于大型工业自动化项目,旨在提高多轴联动控制系统的稳定性和可维护性。具体应用场景包括但不限于机器人控制、生产线自动化、智能制造等领域。 其他说明:本文不仅提供了具体的编程技巧,还分享了许多实用的经验和最佳实践,帮助读者更好地理解和掌握复杂的运动控制系统设计。

    西门子S7-1200 PLC与G120变频器Modbus RTU通讯及PID控制系统的实现与优化

    内容概要:本文详细介绍了基于西门子S7-1200 PLC和G120变频器构建的Modbus RTU通讯系统及其PID控制的应用实例。主要内容涵盖硬件配置、通讯参数设置、PID控制算法实现、触摸屏界面设计以及现场调试技巧。文中提供了具体的参数配置方法,如变频器的Modbus地址设置、波特率选择,以及PLC侧的MB_MASTER指令块使用。同时,针对PID控制,作者自定义了带有手自动切换功能的功能块,并详细解释了PID算法的具体实现,包括输出限幅和抗积分饱和的设计。此外,文章还涉及了触摸屏与PLC之间的变量绑定,确保了良好的人机交互体验。最后,作者分享了一些实用的调试经验和常见问题解决方案,如通讯线缆的选择、终端电阻的配置等。 适合人群:从事自动化控制领域的工程师和技术人员,尤其是对PLC编程和变频器通讯有一定基础的人群。 使用场景及目标:适用于需要实现PLC与变频器通讯并进行PID控制的工业应用场景,如风机控制、恒压供水等。目标是帮助读者掌握Modbus RTU通讯协议的配置和PID控制算法的实现,提高系统的稳定性和可靠性。 其他说明:文中提供的项目文件和电气图纸有助于读者快速搭建和调试类似的控制系统。建议读者在实践中结合具体需求进行适当调整和优化。

    LabVIEW UDL连接SQL数据库实现客户项目进出账管理

    内容概要:本文介绍了如何利用LabVIEW和UDL(Universal Data Link)文件连接SQL Server数据库,实现客户项目进出账管理。主要内容包括:使用UDL文件简化数据库连接配置,封装数据库操作VI(如打开连接、插入数据、查询数据等),并加入错误处理和断网重连机制。此外,还讨论了参数化查询防止SQL注入、动态SQL生成器以及批量数据处理等技巧。通过这些方法,作者实现了高效的数据库管理和操作。 适合人群:对LabVIEW有一定了解,希望深入学习LabVIEW与SQL数据库集成的技术人员。 使用场景及目标:适用于需要将LabVIEW应用于企业级应用开发,尤其是涉及财务、库存或其他需要频繁访问数据库的场景。目标是提高数据管理效率,减少人工操作误差,增强系统的稳定性和安全性。 其他说明:文中提到的所有代码均已开源,可供读者下载并进行二次开发。同时提醒读者注意数据库安全性和性能优化的问题。

    Delphi 字符串转拼音源代码PinYin.rar

    Delphi字符串转拼音源代码PinYin.rar

Global site tag (gtag.js) - Google Analytics