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校園導航系統內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- java中addMouseListener()方法的使用
- JAVA GUI基礎與MouseListener用法
- 基於Java GUI 事件處理方式
- Java監聽器ActionListener與MouseListener的執行順序說明
- Java基礎之CardLayout的使用