Java实现的具有GUI的校园导航系统的完整代码
0.写在前面
2020-5-18更新
这个东西已经是两年前的了,现在问我具体细节我也不是很清楚了,而且现在review两年前的代码感觉写的好烂。。。请大家有问题下面留言,不要加我的企鹅了,正在准备考研,比较忙。
一点建议:
1.当时会的比较少,对象实例化对于单纯的数据查询来说效率极低而且很蠢,我现在更建议使用数据库,或者简单点用xmlorjson都可以,建议想写的好一点的同学把里面的数据读写逻辑改一改,用数据库不香吗
2.这个是分客户端服务端的,服务端相当于用底层手撸了一个相当简单的tomcat,所有的界面都是要从Client进去的。先开server再开Client,在注册时以邀请码判断是否为管理员。以管理员身份进入client之后再去添加信息。
3.如果注册时报access is denied 在Flie的路径下加一层文件夹,如下
小一个月没更新博客了,主要是临近期末,各科的大作业都下来了,今天把自己奋斗了一个礼拜的校园导航系统贴在上面,也算满足下自己的小成就感('ᴗ' )و
实验要求如下:
以我校为例,设计一个校园导航系统,主要为来访的客人提供信息查询。系统有两类登陆账号,一类是游客,使用该系统方便校内路线查询;一类是管理员,可以使用该系统查询校内路线,可对校园景点路线可编辑。
说简单点,就是给定一个地图数据,然后地图上有好几个点,每个点间有距离,这个程序提供了查询两点间最短路径的功能。当然,你可以为他增加很多细节,比如查看景点信息啊,后台的管理啊等等,这些都是加分项。
老师推荐使用C,其实题目也是这么要求的。但是使用C有几个比较麻烦的问题:
第一,要是只实现基本的功能用C的话肯定是没什么问题,但是要是想添枝加叶的话,C的代码就没法看了,写起来麻烦读起来也难受。
第二,地图是有地图数据的,要是用C的话一般人都会直接printf N多行的地图吧,这也是一个比较麻烦的事儿。
思来想去,我决定还是用Java来做这个系统,最短路径用迪杰斯特拉算法。
其实我还是第一次用Java做一个功能比较多的程序,既然是第一次我就想做好点,做的与众不同点。于是,我为这个程序增加了注册登录、邀请码注册管理员系统。
1.客户端与服务端
题目中既然区分了一般用户与管理员的权限,不如在这上面发挥一下。
import javax.swing.*; import java.awt.*; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.*; import java.net.Socket; public class Client { private JFrame jFrame; private JLabel accountLabel, passwdLabel, inviteLabel; private JTextField accountText, passwdText, inviteText; private Toolkit toolkit = Toolkit.getDefaultToolkit(); private JPanel accountJPanel, passwdJPanel, buttonjPanel, invitejPanel; private JButton loginButton, registButton; static JDialog jDialog=new JDialog(); private Font font = new Font("微软雅黑", 1, 18); private BufferedWriter bufferedWriter; private BufferedReader bufferedReader; private String account, passwd; private String tips; private boolean isAdmin = false; public Client() { init(); } public void init() { jFrame = new JFrame("用户登录"); jFrame.setLayout(new FlowLayout()); jFrame.setBounds((toolkit.getScreenSize().width - 270) / 2, (toolkit.getScreenSize().height - 200) / 2, 270, 200); componentInit(accountJPanel = new JPanel(), accountLabel = new JLabel(), accountText = new JTextField(), " 帐号"); componentInit(passwdJPanel = new JPanel(), passwdLabel = new JLabel(), passwdText = new JTextField(), " 密码"); componentInit(invitejPanel = new JPanel(), inviteLabel = new JLabel(), inviteText = new JTextField(), "邀请码"); loginButtonInit(); registButtonInit(); jFrame.setVisible(true); jFrame.setResizable(false); } public void componentInit(JPanel jPanel, JLabel jLabel, JTextField jTextField, String str) { jPanel.setLayout(new FlowLayout()); jLabel.setText(str); jLabel.setFont(font); jTextField.setText(""); jTextField.setColumns(14); jPanel.add(jLabel); jPanel.add(jTextField); jFrame.add(jPanel); } public void loginButtonInit() { loginButton = new JButton("登录"); loginButton.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { try { Socket socket = new Socket("localhost", 10001); //每点击一次必须新建一个新的Socket,否则无法一直获取服务端的数据,具体原因不明,日后考证 sendInfo(0, socket); if (tips.contains("成功")) { Home home = new Home(isAdmin); } } catch (IOException e1) { e1.printStackTrace(); } } }); jFrame.add(loginButton); } public void registButtonInit() { registButton = new JButton("注册"); registButton.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { try { Socket socket = new Socket("localhost", 10001); sendInfo(1, socket); } catch (IOException e1) { e1.printStackTrace(); } } }); jFrame.add(registButton); } public void sendInfo(int code, Socket socket)//封装了注册登录的共性方法 { account = accountText.getText(); passwd = passwdText.getText(); String string; if (code == 0) { string = "登录"; } else string = "注册"; try { bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); //这里同样要使用每次的新的Socket获取写入流 bufferedWriter.write(code + "\r\n"); bufferedWriter.flush();//输出标示,告诉服务端是登录还是注册,登录为0,注册为1 bufferedWriter.write(account + "\r\n");//必须要有结束标示,否则服务端不会停止读取 bufferedWriter.flush(); //刷新流 bufferedWriter.write(passwd + "\r\n"); bufferedWriter.flush(); if (code == 1) //注册的话有一个邀请码,需要多传输一次 { bufferedWriter.write(inviteText.getText() + "\r\n"); bufferedWriter.flush(); } bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream())); tips = bufferedReader.readLine(); if (tips.contains("管理员")) { isAdmin = true; } } catch (IOException e1) { new mDialog(string + "结果", "交换数据失败!",jFrame); } catch (NullPointerException e1) { new mDialog(string + "结果", "服务端关闭!请先打开服务端!",jFrame); } finally { try { bufferedReader.close(); bufferedWriter.close(); } catch (IOException e1) { tips = "流关闭失败!"; new mDialog(string + "结果", tips,jFrame); } new mDialog(string + "结果", tips,jFrame); } } public static void main(String[] args) { Client client = new Client(); } }
运用了Socket,并与Server交换数据。
详细解释不再说,注释里有,也没什么好说的,比较基础的代码。
这里有个bug没解决(主要是没精力也懒得改了):注册成功后立刻点击登录的话会无视注册身份,统一使用管理员身份,重启客户端之后正常。我似乎隐约知道是哪里的问题?
import com.sun.source.tree.Scope; import java.io.*; import java.net.ServerSocket; import java.net.Socket; import java.util.HashSet; import java.util.Iterator; public class Server { private Socket socket; private ServerSocket serverSocket; private String ipInfo; private BufferedReader bufferedReader; private BufferedOutputStream bufferedOutputStream; private FileOutputStream fileOutputStream; private String adminKey; private HashSet<User> hashSet; private String account, passwd, inviteCode; private File infofile = new File("D://info.key"); private boolean isAdmin = false; public Server(String adminKey) { this.adminKey = adminKey; try { serverSocket = new ServerSocket(10001); while (true)//循环接受Socket { System.out.println("服务端开启,等待客户端建立连接。"); socket = serverSocket.accept(); ipInfo = socket.getInetAddress().getHostAddress().toString(); System.out.println(ipInfo+" Connected! "); new Thread(new Task(socket)).start();//并且每次接收到Socket之后,就要新建一个线程以达到多次返回数据接受数据的目的 } } catch (IOException e) { e.printStackTrace(); } } public class Task implements Runnable { private Socket socket; public Task(Socket socket) { this.socket = socket; } @Override public void run() { try { bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream())); System.out.println(ipInfo); String code = bufferedReader.readLine();//客户端先发送一个标志,说明是登录还是返回 if (code.equals("0")) { login(); } else regist(); code = bufferedReader.readLine(); System.out.println(code); } catch (IOException e) { e.printStackTrace(); } } } public void login() { String result; String status; PrintWriter printWriter = null; if (isAdmin)//确定找到的用户的身份 { status = "管理员"; } else status = "一般用户"; try { readFile(infofile);//先读文件 account = bufferedReader.readLine();//客户端传回来的帐号密码 passwd = bufferedReader.readLine(); User user = new User(account, passwd);//封装对象 if (isExists(user, false))//找到了 { result = "登录成功,身份:" + status;//传回相关信息 } else { result = "登录失败,请查验帐号密码!"; } printWriter = new PrintWriter(socket.getOutputStream(), true); printWriter.println(result);//返回客户端 } catch (IOException e) { e.printStackTrace(); } } public void regist() { PrintWriter printWriter = null; String status = null; try { printWriter = new PrintWriter(socket.getOutputStream(), true); account = bufferedReader.readLine();//客户端传回来的帐号密码 passwd = bufferedReader.readLine(); inviteCode = bufferedReader.readLine(); User user = new User(account, passwd); readFile(infofile); if (!isExists(user, true)) { user.setAdmin(inviteCode); if (user.isAdmin()) { status = "管理员"; } else status = "一般用户"; hashSet.add(user);//没找到就添加进Set writeFile(infofile); printWriter.println("注册成功!身份:" + status); } else { printWriter.println("注册失败,用户已存在!"); } } catch (IOException e) { e.printStackTrace(); } } public void readFile(File file) { ObjectInputStream objectInputStream = null; PrintWriter printWriter = null; try { printWriter = new PrintWriter(socket.getOutputStream()); objectInputStream = new ObjectInputStream(new FileInputStream(file));//读取密码文件 hashSet = (HashSet) objectInputStream.readObject();//信息是以hashSet的形式存放在文件中 } catch (IOException e) { if (hashSet == null) { hashSet = new HashSet<>();//程序第一次运行时添加进的hashMap是null,需要新实例化一个 writeFile(infofile);//然后再写进去 } } catch (ClassNotFoundException e) { printWriter.println("数据文件异常,请检查文件!"); } } public void writeFile(File file) { PrintWriter printWriter = null; ObjectOutputStream objectOutputStream = null; try { objectOutputStream = new ObjectOutputStream(new FileOutputStream(file));//对象写入流 objectOutputStream.writeObject(hashSet);//将hashSet写入文件 printWriter = new PrintWriter(socket.getOutputStream()); } catch (IOException e) { printWriter.println("数据文件异常,请检查文件!"); } } public boolean isExists(User user, boolean isRegister) { String account = user.getAccount(); String passwd = user.getPasswd(); Iterator iterator = hashSet.iterator(); while (iterator.hasNext()) { User stu = (User) iterator.next(); isAdmin = stu.isAdmin(); if (stu.getAccount().equals(account))//如果找到了相同用户名 { if (isRegister)//注册的话 { return true;//已经找到了 } return stu.getPasswd().equals(passwd);//登陆的话还要比较密码是否相同 } } return false;//没找到就是假 } public void setAdminKey(String string) { adminKey = string; } public String getAdminKey() { return adminKey; } public static void main(String[] args) { Server server = new Server("KangYh is very handsome!"); } } class User implements Serializable { private String account; private String passwd; private boolean isAdmin = false; public User(String account, String passwd) { this.account = account; this.passwd = passwd; } public String getAccount() { return account; } public void setAccount(String account) { this.account = account; } public String getPasswd() { return passwd; } public void setPasswd(String passwd) { this.passwd = passwd; } public boolean isAdmin() { return isAdmin; } public void setAdmin(String string) { if (string.equals(new Server("KangYh is very handsome!").getAdminKey())) { isAdmin = true; } } @Override public int hashCode() { return account.hashCode() + passwd.hashCode() * 3; } @Override public boolean equals(Object obj) { if (!(obj instanceof User)) { return false; } User user = (User) obj; return account.equals(user.account); } }
服务端,里面有User.class。其实可以把这个class写出来的。把User装入HashSet<User>,保证唯一性。
这里面踩的雷就是读写的换行,刷新问题。写入完毕一次必须再写一个换行标记,否则另一头是没数据的。换行标记可以是
bufferedWriter.write(code + "\r\n"); bufferedWriter.newLine();
两者中的一种。
还有一点,序列化的对象文件,官方推荐扩展名为.ser,我用的是.obj。
放张截图:(请无视邀请码内容(゜ロ゜))
2.主界面
登录成功后就是主界面了。为了省事儿,我直接截了张图为导航的地图。这个地图是可以更换的。(动态更改我也不会啊(`Δ´)!)
import javax.swing.*; import java.awt.*; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.*; public class Home { private JFrame jFrame; private JPanel mapLabel; private JLabel title, map; private JButton admin, menu, close; private Font titleFont = new Font("微软雅黑", 1, 28); private Font charFont = new Font("微软雅黑", 1, 20); private Toolkit toolkit = Toolkit.getDefaultToolkit(); private File pointFile = new File("D://point.obj"); private File lengthFile = new File("D://length.obj"); private File mapFile = new File("D://map.png"); private boolean isAdmin = false; public Home(boolean isAdmin) { this.isAdmin = isAdmin;//确定用户身份 init(); } public void init() { jFrame = new JFrame(); jFrame.setLayout(new BorderLayout()); titleInit();//初始化标题栏 mapInit();//初始化地图 jFrame.setBounds((toolkit.getScreenSize().width - 700) / 2, (toolkit.getScreenSize().height - 450) / 2, 700, 450); JPanel buttonPanel = new JPanel(); buttonPanel.setLayout(new FlowLayout()); admin = new JButton("管理员菜单"); admin.setFont(charFont); admin.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { new AdminMenu(); } }); menu = new JButton("功能菜单"); menu.setFont(charFont); menu.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { new NormalMenu(); } }); buttonPanel.add(menu); if (isAdmin) { buttonPanel.add(admin); adminTips(); } close = new JButton("关闭"); close.setFont(charFont); close.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { System.exit(0); } }); buttonPanel.add(close); jFrame.add(buttonPanel, BorderLayout.SOUTH); jFrame.setResizable(false); jFrame.setVisible(true); } public void titleInit() { title = new JLabel("校园导航系统", SwingConstants.CENTER); title.setFont(titleFont); jFrame.add(title, BorderLayout.NORTH);//标题文字 } public void mapInit() { ImageIcon imageIcon = new ImageIcon(mapFile.getPath()); imageIcon.setImage(imageIcon.getImage().getScaledInstance(imageIcon.getIconWidth(), imageIcon.getIconHeight(), Image.SCALE_DEFAULT)); map = new JLabel(); map.setBounds(0, 0, 690, 400); map.setHorizontalAlignment(0); map.setIcon(imageIcon); mapLabel = new JPanel(); mapLabel.setSize(690, 400); mapLabel.add(map); jFrame.add(mapLabel, BorderLayout.CENTER);//地图显示 } public void adminTips() { String errorTitle = "数据错误!"; try { checkFile(mapFile, "地图"); } catch (IOException e) { e.printStackTrace(); new mDialog(errorTitle, "请管理员先录入地图数据!", jFrame); //writeMap } try { checkFile(pointFile, "景点"); } catch (IOException e) { e.printStackTrace(); new mDialog(errorTitle, "请管理员先录入景点数据!", jFrame); //writePoint } try { checkFile(lengthFile, "距离"); } catch (IOException e) { e.printStackTrace(); new mDialog(errorTitle, "请管理员先录入距离数据!", jFrame); //writeLength } } public void checkFile(File file, String string) throws IOException { if (!file.exists() || file.length() == 0) { throw new IOException(string + "文件打开失败!"); } } }
这个没啥坑,需要注意的是:
因为景点的数据,距离数据都是以文件的形式保存的,所以一定会有IO异常。这时候就得提供一个比较友好的提示界面,并同时将异常信息输出到控制台上:
这个过程我,我美名其曰为“自检”。听着就高大上~(︶ω︶)~
然后就是主界面了。主界面的地图我直接放了一个题目要求中的截图。
确实比较简陋,但是该有的都有了。
两个界面,一个是管理员的一个是一般用户的。
import javax.swing.*; import java.awt.*; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; public class AdminMenu { private JFrame jFrame; private JButton createPoint, editPoint, deletePoint, createLength, editLength; private JButton cancelButton; private Toolkit toolkit = Toolkit.getDefaultToolkit(); private Font font = new Font("微软雅黑", 1, 20); private File pointFile = new File("D://point.txt"); private File lengthFile = new File("D://length.txt"); private JFrame childFrame; private JPanel childPanel; private BufferedReader bufferedReader; private BufferedWriter bufferedWriter; public AdminMenu() { jFrame = new JFrame("管理员菜单"); jFrame.setBounds((toolkit.getScreenSize().width - 250) / 2, (toolkit.getScreenSize().height - 310) / 2, 250, 310); jFrame.setLayout(new FlowLayout()); childPanel = new JPanel(); childPanel.setLayout(new FlowLayout()); cancelButton = new JButton("关闭"); childPanel.add(cancelButton); cancelButton.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { jFrame.setVisible(false); } }); createPoint = new JButton("1.创建景点信息"); createPoint.setFont(font); createPoint.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { new CreatePoint(); } }); editPoint = new JButton("2.修改景点信息"); editPoint.setFont(font); editPoint.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { new EditPoint(); } }); deletePoint = new JButton("3.删除景点信息"); deletePoint.setFont(font); deletePoint.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { new DeletePoint(); } }); createLength = new JButton("4.创建道路信息"); createLength.setFont(font); createLength.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { new CreateLength(jFrame); } }); editLength = new JButton("5.修改道路信息"); editLength.setFont(font); editLength.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { new CreateLength(jFrame); } }); jFrame.add(createPoint); jFrame.add(editPoint); jFrame.add(deletePoint); jFrame.add(createLength); jFrame.add(editLength); jFrame.add(childPanel); jFrame.setVisible(true); } }
import javax.swing.*; import java.awt.*; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; class NormalMenu { private JFrame jFrame; private JButton visitButton, searchButton, okayButton; private Font font = new Font("微软雅黑", 1, 20); private Toolkit toolkit = Toolkit.getDefaultToolkit(); public NormalMenu() { jFrame = new JFrame("功能菜单"); jFrame.setBounds((toolkit.getScreenSize().width - 250) / 2, (toolkit.getScreenSize().height - 200) / 2, 250, 200); jFrame.setLayout(new FlowLayout()); visitButton = new JButton("1.浏览景点信息"); visitButton.setFont(font); searchButton = new JButton("2.查询最短路径"); searchButton.setFont(font); okayButton = new JButton("关闭"); okayButton.setFont(font); visitButton.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { new VisitPoint(); } }); searchButton.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { new SearchLength(); } }); okayButton.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { jFrame.setVisible(false); } }); jFrame.add(visitButton); jFrame.add(searchButton); jFrame.add(okayButton); jFrame.setResizable(false); jFrame.setVisible(true); } }
两个菜单的java文件。
3.管理员菜单
管理员有5个功能。
import javax.swing.*; import java.awt.*; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.*; import java.util.TreeMap; public class CreatePoint { private File file; private ObjectInputStream objectInputStream; private ObjectOutputStream objectOutputStream; private TreeMap treeMap; private Toolkit toolkit = Toolkit.getDefaultToolkit(); public CreatePoint() { try { file = new File("D://point.obj"); objectInputStream = new ObjectInputStream(new FileInputStream(file)); treeMap = (TreeMap) objectInputStream.readObject(); } catch (IOException e) { treeMap = new TreeMap(); } catch (ClassNotFoundException e) { }finally { frameInit(); } } public void frameInit() { JSeparator jSeparator = new JSeparator(SwingConstants.HORIZONTAL); JTextArea jTextArea = new JTextArea(15, 30); JTextField jTextField = new JTextField(20); JFrame jFrame = new JFrame(); jFrame.setBounds((toolkit.getScreenSize().width - 350) / 2, (toolkit.getScreenSize().height - 450) / 2, 350, 450); jFrame.setLayout(new FlowLayout()); jFrame.add(jTextField); jFrame.add(jSeparator); jFrame.add(jTextArea); JButton okayButton = new JButton("确定"); JButton cancelButton = new JButton("取消"); cancelButton.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { jFrame.setVisible(false); } }); okayButton.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { treeMap.put(jTextField.getText(), jTextArea.getText()); try { objectOutputStream = new ObjectOutputStream(new FileOutputStream(file)); objectOutputStream.writeObject(treeMap); new mDialog("成功", "数据正常保存", jFrame); jFrame.setVisible(false); } catch (IOException e1) { new mDialog("失败", "数据异常!", jFrame); } } }); jFrame.add(cancelButton); jFrame.add(okayButton); jFrame.setVisible(true); } public static void main(String[] args) { new CreatePoint(); } }
其实可以把两个框里的字体改一下。还有一个,每个框前面其实应该有个提示信息的。我嫌麻烦,后来有点懒得弄了。难度也不是很大,一个JLabel完事儿。
3.2 修改景点信息
import javax.swing.*; import java.awt.*; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.*; import java.util.TreeMap; import java.util.Iterator; import java.util.Set; public class EditPoint { private JComboBox jComboBox; private String key; private ObjectInputStream objectInputStream; private ObjectOutputStream objectOutputStream; private TreeMap treeMap; private Set<String> set; private File file; private Toolkit toolkit = Toolkit.getDefaultToolkit(); JFrame jFrame; public EditPoint() { try { file = new File("D://point.obj"); jFrame = new JFrame(""); objectInputStream = new ObjectInputStream(new FileInputStream(file)); treeMap = (TreeMap) objectInputStream.readObject(); set = treeMap.keySet(); frameInit(); } catch (IOException e) { new mDialog("错误", "没有文件!", jFrame); e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } public void frameInit() { jFrame.setBounds((toolkit.getScreenSize().width - 350) / 2, (toolkit.getScreenSize().height - 450) / 2, 350, 450); jFrame.setLayout(new FlowLayout()); jComboBox = new JComboBox(); jComboBox.setPreferredSize(new Dimension(270, 30)); Iterator iterator = set.iterator(); while (iterator.hasNext()) { jComboBox.addItem((String) iterator.next()); } JTextArea jTextArea = new JTextArea(15, 30); jTextArea.setText((String) treeMap.get(jComboBox.getSelectedItem())); jComboBox.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { jTextArea.setText((String) treeMap.get(jComboBox.getSelectedItem())); } }); JButton okayButton = new JButton("确定"); JButton cancelButton = new JButton("取消"); cancelButton.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { jFrame.setVisible(false); } }); okayButton.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { String string = jTextArea.getText(); treeMap.put((String) jComboBox.getSelectedItem(), string); try { objectOutputStream = new ObjectOutputStream(new FileOutputStream(file)); objectOutputStream.writeObject(treeMap); new mDialog("成功", "数据成功修改", jFrame); jFrame.setVisible(false); } catch (IOException e1) { new mDialog("失败", "数据异常!", jFrame); } } }); jFrame.add(jComboBox); jFrame.add(jTextArea); jFrame.add(cancelButton); jFrame.add(okayButton); jFrame.setResizable(false); jFrame.setVisible(true); } public static void main(String[] args) { new EditPoint(); } }
3.3删除景点信息
import javax.swing.*; import java.awt.*; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.*; import java.util.TreeMap; import java.util.Iterator; import java.util.Set; public class DeletePoint { private JComboBox jComboBox; private TreeMap treeMap; private ObjectInputStream objectInputStream; private ObjectOutputStream objectOutputStream; private Set set; private File file; private Toolkit toolkit = Toolkit.getDefaultToolkit(); private JFrame jFrame; public DeletePoint() { try { jFrame = new JFrame(); file = new File("D://point.obj"); objectInputStream = new ObjectInputStream(new FileInputStream(file)); treeMap = (TreeMap) objectInputStream.readObject(); frameInit(); } catch (IOException e) { new mDialog("错误", "没有文件!", jFrame); e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } public void frameInit() { jFrame.setLayout(new FlowLayout()); jFrame.setBounds((toolkit.getScreenSize().width - 350) / 2, (toolkit.getScreenSize().height - 250) / 2, 350, 250); jComboBox = new JComboBox(); jComboBox.setPreferredSize(new Dimension(270,30));//设置大小 jFrame.add(jComboBox); set = treeMap.keySet(); Iterator iterator = set.iterator(); while (iterator.hasNext()) { jComboBox.addItem((String) iterator.next()); } JLabel jLabel = new JLabel(); jLabel.setText((String)treeMap.get(jComboBox.getSelectedItem()));//设置景点的相关信息显示 jLabel.setPreferredSize(new Dimension(270,80)); jFrame.add(jLabel); JButton cancelButton = new JButton("取消"); JButton okayButton = new JButton("确认"); jFrame.add(cancelButton); jFrame.add(okayButton); jComboBox.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { jLabel.setText((String)treeMap.get(jComboBox.getSelectedItem())); } }); cancelButton.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { jFrame.setVisible(false); } }); okayButton.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { try { treeMap.remove((String) jComboBox.getSelectedItem()); objectOutputStream = new ObjectOutputStream(new FileOutputStream(file)); objectOutputStream.writeObject(treeMap); new mDialog("成功", "删除" + (String) jComboBox.getSelectedItem() + "成功!", jFrame); jLabel.setText(""); jFrame.setVisible(false); } catch (IOException e1) { new mDialog("失败", "数据异常!", jFrame); } catch (NullPointerException e1) { new mDialog("失败", "已经没有景点信息了!", jFrame);//删到最后就变成null了,抛异常就得处理一下 jFrame.setVisible(false); } } }); jFrame.setResizable(false); jFrame.setVisible(true); } public static void main(String[] args) { new DeletePoint(); } }
3.4创建两点间的距离信息
import javax.swing.*; import java.awt.*; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.*; import java.util.ArrayList; import java.util.Iterator; import java.util.Set; import java.util.TreeMap; public class CreateLength { private JComboBox jComboBox1, jComboBox2; private JTextField jTextField; private ObjectInputStream objectInputStream1, objectInputStream2; private ObjectOutputStream objectOutputStream; private File lengthFile; private File pointFile; private double length[][]; private Toolkit toolkit = Toolkit.getDefaultToolkit(); private TreeMap treeMap; private Set set; private LengthInfo lengthInfo; private ArrayList arrayList; public CreateLength(JFrame jFrame) { lengthFile = new File("D://length.obj"); pointFile = new File("D://point.obj"); try { objectInputStream1 = new ObjectInputStream(new FileInputStream(pointFile)); } catch (IOException e) { new mDialog("错误", "没有景点信息!", jFrame); } try { objectInputStream2 = new ObjectInputStream(new FileInputStream(lengthFile)); treeMap = (TreeMap) objectInputStream1.readObject(); arrayList = (ArrayList) objectInputStream2.readObject(); } catch (IOException e) { lengthInfo = new LengthInfo(); lengthInfo.init(); arrayList = new ArrayList(); arrayList.add(lengthInfo); try { objectOutputStream = new ObjectOutputStream(new FileOutputStream(lengthFile)); objectOutputStream.writeObject(arrayList); objectOutputStream.flush(); } catch (IOException e1) { } } catch (ClassNotFoundException e) { } frameInit(); } public void frameInit() { JFrame jFrame = new JFrame(); jFrame.setLayout(new FlowLayout()); jFrame.setBounds((toolkit.getScreenSize().width - 350) / 2, (toolkit.getScreenSize().height - 200) / 2, 350, 200); jTextField = new JTextField(27); jComboBox1 = new JComboBox(); jComboBox1.setPreferredSize(new Dimension(270, 30)); jComboBox2 = new JComboBox(); jComboBox2.setPreferredSize(new Dimension(270, 30)); set = treeMap.keySet(); Iterator iterator = set.iterator(); while (iterator.hasNext()) { String string = (String) iterator.next(); jComboBox1.addItem(string); jComboBox2.addItem(string); } int from = jComboBox1.getSelectedIndex(); int to = jComboBox2.getSelectedIndex(); lengthInfo = (LengthInfo) arrayList.get(0); jTextField.setText(lengthInfo.getLength(from, to) + ""); jComboBox1.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { jTextField.setText(lengthInfo.getLength(jComboBox1.getSelectedIndex(), jComboBox2.getSelectedIndex()) + ""); } }); jComboBox2.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { jTextField.setText(lengthInfo.getLength(jComboBox1.getSelectedIndex(), jComboBox2.getSelectedIndex()) + ""); } }); JButton cancelButton = new JButton("取消"); JButton okayButton = new JButton("确认"); cancelButton.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { jFrame.setVisible(false); } }); okayButton.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { try { double weight = Double.parseDouble(jTextField.getText().toString()); lengthInfo.editLength(jComboBox1.getSelectedIndex(), jComboBox2.getSelectedIndex(), weight); objectOutputStream = new ObjectOutputStream(new FileOutputStream(lengthFile)); objectOutputStream.writeObject(arrayList); new mDialog("成功", "数据修改成功!", jFrame); jFrame.setVisible(false); } catch (NumberFormatException e1) { e1.printStackTrace(); new mDialog("错误", "请输入正确信息!", jFrame); } catch (IOException e1) { new mDialog("错误", "信息写入失败!", jFrame); } } }); jFrame.add(jComboBox1); jFrame.add(jComboBox2); jFrame.add(jTextField); jFrame.add(cancelButton); jFrame.add(okayButton); jFrame.setVisible(true); jFrame.setResizable(false); } public static void main(String[] args) { new CreateLength(new JFrame()); } }
这个就要说明下了,因为当时在写这个模块的时候遇到了不少问题。
第一,存储结构。
既然是选用了迪杰斯特拉算法,那么使用邻接矩阵就是最方便的。我一开始所希望的是一个动态的二维数组,也就是ArrayList<<ArrayList<Integer>> arraylists。但是实际上操作起来会比较麻烦。最后为了赶时间还是用的普通的二维数组int length[][],长度也就固定了。这个动态的二维数组以后再研究下。
还有就是两个JCombobox中元素的顺序问题。景点信息是随时可以更改的,所以这个JCombobox中元素的个数与顺序也是个问题。怎么能保证item与邻接矩阵中的位置精确对应?
我采取的做法,全局将景点的信息用TreeMap存储,key为景点的名称,value为景点的详细信息。然后使用.ketSet()来将key存入set。因为TreeMap保存我存入的相对顺序。要是用HashMap顺序就乱了。
既然相对顺序是固定的,那么我就不需要去链接邻接矩阵与jcombobox了。只需要在改变景点信息的时候顺便将邻接矩阵中的数据改一下就行了。这样就可以保证对应关系。
第二,数据的赋值
两点间的距离默认应该是无限大,所以初始化的时候应该是Integer.INT_MAX。自己和自己是没有距离的,也就是0。这些工作都应该在初始化的时候做好。
有两点可以进行优化:一是目前的版本如果第一次输入数据,编辑框会将初始化的值显示在上面。其实这种情况还是留白比较好。二是既然自己跟自己没有距离,那么两个JCombobox就不应该出现一样的值。
3.5 修改两点间的距离
import javax.swing.*; import java.awt.*; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.*; import java.util.ArrayList; import java.util.Iterator; import java.util.Set; import java.util.TreeMap; public class CreateLength { private JComboBox jComboBox1, jComboBox2; private JTextField jTextField; private ObjectInputStream objectInputStream1, objectInputStream2; private ObjectOutputStream objectOutputStream; private File lengthFile; private File pointFile; private double length[][]; private Toolkit toolkit = Toolkit.getDefaultToolkit(); private TreeMap treeMap; private Set set; private LengthInfo lengthInfo; private ArrayList arrayList; public CreateLength(JFrame jFrame) { lengthFile = new File("D://length.obj"); pointFile = new File("D://point.obj"); try { objectInputStream1 = new ObjectInputStream(new FileInputStream(pointFile)); } catch (IOException e) { new mDialog("错误", "没有景点信息!", jFrame); } try { objectInputStream2 = new ObjectInputStream(new FileInputStream(lengthFile)); treeMap = (TreeMap) objectInputStream1.readObject(); arrayList = (ArrayList) objectInputStream2.readObject(); } catch (IOException e) { lengthInfo = new LengthInfo(); lengthInfo.init(); arrayList = new ArrayList(); arrayList.add(lengthInfo); try { objectOutputStream = new ObjectOutputStream(new FileOutputStream(lengthFile)); objectOutputStream.writeObject(arrayList); objectOutputStream.flush(); } catch (IOException e1) { } } catch (ClassNotFoundException e) { } frameInit(); } public void frameInit() { JFrame jFrame = new JFrame(); jFrame.setLayout(new FlowLayout()); jFrame.setBounds((toolkit.getScreenSize().width - 350) / 2, (toolkit.getScreenSize().height - 200) / 2, 350, 200); jTextField = new JTextField(27); jComboBox1 = new JComboBox(); jComboBox1.setPreferredSize(new Dimension(270, 30)); jComboBox2 = new JComboBox(); jComboBox2.setPreferredSize(new Dimension(270, 30)); set = treeMap.keySet(); Iterator iterator = set.iterator(); while (iterator.hasNext()) { String string = (String) iterator.next(); jComboBox1.addItem(string); jComboBox2.addItem(string); } int from = jComboBox1.getSelectedIndex(); int to = jComboBox2.getSelectedIndex(); lengthInfo = (LengthInfo) arrayList.get(0); jTextField.setText(lengthInfo.getLength(from, to) + ""); jComboBox1.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { jTextField.setText(lengthInfo.getLength(jComboBox1.getSelectedIndex(), jComboBox2.getSelectedIndex()) + ""); } }); jComboBox2.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { jTextField.setText(lengthInfo.getLength(jComboBox1.getSelectedIndex(), jComboBox2.getSelectedIndex()) + ""); } }); JButton cancelButton = new JButton("取消"); JButton okayButton = new JButton("确认"); cancelButton.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { jFrame.setVisible(false); } }); okayButton.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { try { double weight = Double.parseDouble(jTextField.getText().toString()); lengthInfo.editLength(jComboBox1.getSelectedIndex(), jComboBox2.getSelectedIndex(), weight); objectOutputStream = new ObjectOutputStream(new FileOutputStream(lengthFile)); objectOutputStream.writeObject(arrayList); new mDialog("成功", "数据修改成功!", jFrame); jFrame.setVisible(false); } catch (NumberFormatException e1) { e1.printStackTrace(); new mDialog("错误", "请输入正确信息!", jFrame); } catch (IOException e1) { new mDialog("错误", "信息写入失败!", jFrame); } } }); jFrame.add(jComboBox1); jFrame.add(jComboBox2); jFrame.add(jTextField); jFrame.add(cancelButton); jFrame.add(okayButton); jFrame.setVisible(true); jFrame.setResizable(false); } public static void main(String[] args) { new CreateLength(new JFrame()); } }
我承认,这个我偷懒了,这个我直接用的是上一个类。不过话说过来,这俩不是差不多嘛(´_`)
4.一般用户的操作菜单
import javax.swing.*; import java.awt.*; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; class NormalMenu { private JFrame jFrame; private JButton visitButton, searchButton, okayButton; private Font font = new Font("微软雅黑", 1, 20); private Toolkit toolkit = Toolkit.getDefaultToolkit(); public NormalMenu() { jFrame = new JFrame("功能菜单"); jFrame.setBounds((toolkit.getScreenSize().width - 250) / 2, (toolkit.getScreenSize().height - 200) / 2, 250, 200); jFrame.setLayout(new FlowLayout()); visitButton = new JButton("1.浏览景点信息"); visitButton.setFont(font); searchButton = new JButton("2.查询最短路径"); searchButton.setFont(font); okayButton = new JButton("关闭"); okayButton.setFont(font); visitButton.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { new VisitPoint(); } }); searchButton.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { new SearchLength(); } }); okayButton.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { jFrame.setVisible(false); } }); jFrame.add(visitButton); jFrame.add(searchButton); jFrame.add(okayButton); jFrame.setResizable(false); jFrame.setVisible(true); } }
4.1 浏览景点信息
import javax.swing.*; import java.awt.*; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.util.Iterator; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; public class VisitPoint { private JFrame jFrame; private JComboBox jComboBox; private JLabel jLabel; private JButton okayButton; private Toolkit toolkit = Toolkit.getDefaultToolkit(); private File file = new File("D://point.obj"); private ObjectInputStream objectInputStream; private TreeMap treeMap; private Set set; public VisitPoint() { try { objectInputStream = new ObjectInputStream(new FileInputStream(file)); jFrame = new JFrame(); } catch (IOException e) { new mDialog("错误", "无景点信息文件!", jFrame); } frameInit(); } public void frameInit() { try { jFrame.setLayout(new BorderLayout()); jFrame.setBounds((toolkit.getScreenSize().width - 350) / 2, (toolkit.getScreenSize().height - 250) / 2, 350, 250); } catch (Exception e) { e.printStackTrace(); } jComboBox = new JComboBox(); jComboBox.setPreferredSize(new Dimension(270,30)); try { treeMap = (TreeMap) objectInputStream.readObject(); set = treeMap.keySet(); } catch (IOException e) { } catch (ClassNotFoundException e) { } Iterator iterator = set.iterator(); while (iterator.hasNext()) { jComboBox.addItem((String) iterator.next()); } jLabel = new JLabel(); jLabel.setPreferredSize(new Dimension(270,20)); jLabel.setFont(new Font("宋体", 1, 20)); jLabel.setText((String) treeMap.get(jComboBox.getSelectedItem())); jComboBox.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { jLabel.setText((String) treeMap.get(jComboBox.getSelectedItem())); } }); okayButton = new JButton("确定"); okayButton.setFont(new Font("微软雅黑", 1, 20)); okayButton.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { jFrame.setVisible(false); } }); jFrame.add(jComboBox,BorderLayout.NORTH); jFrame.add(jLabel,BorderLayout.CENTER); jFrame.add(okayButton,BorderLayout.SOUTH); jFrame.setResizable(false); jFrame.setVisible(true); } public static void main(String[] args) { new VisitPoint(); } }
很简单,想不出啥需要强调的。
4.2查询任意两点间的最短路径
import javax.imageio.event.IIOReadProgressListener; import javax.swing.*; import java.awt.*; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.util.ArrayList; import java.util.Iterator; import java.util.Set; import java.util.TreeMap; public class SearchLength { private JFrame jFrame; private JComboBox jComboBox1, jComboBox2; private JLabel jLabel; private JButton jButton; private ObjectInputStream objectInputStream1, objectInputStream2; private File lengthFile, pointFile; private TreeMap treeMap; private ArrayList arrayList; private Set set; private LengthInfo lengthInfo; private Toolkit toolkit = Toolkit.getDefaultToolkit(); public SearchLength() { jFrame = new JFrame(); try { lengthFile = new File("D://length.obj"); pointFile = new File("D://point.obj"); objectInputStream1 = new ObjectInputStream(new FileInputStream(lengthFile)); objectInputStream2 = new ObjectInputStream(new FileInputStream(pointFile)); arrayList = (ArrayList) objectInputStream1.readObject(); lengthInfo = (LengthInfo) arrayList.get(0); treeMap = (TreeMap) objectInputStream2.readObject(); } catch (IOException e) { new mDialog("错误", "无景点信息!", jFrame); } catch (ClassNotFoundException e) { new mDialog("错误!", "文件信息错误!", jFrame); } try { set = treeMap.keySet(); } catch (NullPointerException e) { new mDialog("错误", "无道路长度信息!", jFrame); } frameInit(); } public void frameInit() { jFrame.setLayout(new FlowLayout()); jFrame.setBounds((toolkit.getScreenSize().width - 200) / 2, (toolkit.getScreenSize().height - 200) / 2, 400, 200); jComboBox1 = new JComboBox(); jComboBox1.setPreferredSize(new Dimension(180, 30)); jComboBox1.setFont(new Font("微软雅黑", 1, 20)); jComboBox2 = new JComboBox(); jComboBox2.setPreferredSize(new Dimension(180, 30)); jComboBox2.setFont(new Font("微软雅黑", 1, 20)); Iterator iterator = set.iterator(); while (iterator.hasNext()) { String string = (String) iterator.next(); jComboBox1.addItem(string); jComboBox2.addItem(string); } jLabel = new JLabel(); jLabel.setPreferredSize(new Dimension(350, 80)); jLabel.setFont(new Font("微软雅黑", 1, 20)); double str1 = lengthInfo.getMin(0, 1, treeMap); jComboBox1.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { double str1 = lengthInfo.getMin(jComboBox1.getSelectedIndex(), jComboBox2.getSelectedIndex(), treeMap); String str2 = lengthInfo.getStringBuilder(); jLabel.setText("<html><body>" + "最优路径: " + str2 + "<br>" + "里程: " + str1 + "m" + "<body></html>"); } }); jComboBox2.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { double str1 = lengthInfo.getMin(jComboBox1.getSelectedIndex(), jComboBox2.getSelectedIndex(), treeMap); String str2 = lengthInfo.getStringBuilder(); jLabel.setText("<html><body>" + "最优路径: " + str2 + "<br>" + "里程: " + str1 + "m" + "<body></html>"); } }); jButton = new JButton("确定"); jButton.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { jFrame.setVisible(false); } }); jFrame.add(jComboBox1); jFrame.add(jComboBox2); jFrame.add(jLabel); jFrame.add(jButton); jFrame.setResizable(false); jFrame.setVisible(true); } }
这里面的代码主要就是界面。实质的工作没在这里面。
有个可以优化的:就拿上面那个图来说,这个路径其实是反的,因为算法最后用的是回溯,stringBuilder.append()也就是从后往前拼接的。要是正的就更好了。
还有,在JLabel中居然可以使用html的格式控制,上面的“最优路程”与“里程”的换行就是使用<br>实现的。
但是这里我有一个疑惑:字符串中的“<”“>”是显示不出来的。一开始想使用“<--”来间隔,最后无奈只能用“---”了。
5.后记
程序不算完美,有很多我已经意识到的bug和可以继续优化的点。但是好歹是自己的一次实践,也是非常有价值的。
idea工程文件:
https://github.com/0-0MrLonely/SourceCode/tree/master/Java/NaviDemo
到此这篇关于Java实现的具有GUI的校园导航系统的完整代码的文章就介绍到这了,更多相关Java校园导航系统内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!