package dell_map; // ¶¨Òå°üÃû import javax.swing.*; // µ¼ÈëSwing×é¼þ import javax.swing.event.InternalFrameEvent; // µ¼ÈëÄÚ²¿¿ò¼Üʼþ import javax.swing.event.InternalFrameListener; // µ¼ÈëÄÚ²¿¿ò¼Ü¼àÌýÆ÷ import java.awt.*; // µ¼ÈëAWT×é¼þ import java.awt.event.*; // µ¼ÈëAWTʼþ import java.lang.ref.SoftReference; // µ¼ÈëÈíÒýÓà import java.util.List; // µ¼ÈëÁбí import java.util.ResourceBundle; // µ¼Èë¹ú¼Ê»¯×ÊÔ´°ü import targets.Mapdata; // µ¼ÈëµØÍ¼Êý¾ÝÀà public class MapViewer extends JInternalFrame implements Runnable { // µØÍ¼²é¿´Æ÷À࣬¼Ì³ÐÄÚ²¿¿ò¼Ü²¢ÊµÏÖÏß³Ì private static final long serialVersionUID = 1L; // ÐòÁл¯°æ±¾ID private MapCanvas canvas; // µØÍ¼»­²¼ private double scale = 1.0; // Ëõ·Å±ÈÀý private int scaleStep = 200; // Ëõ·Å²½³¤£¨Î´Ê¹Óã© private Point dragOrigin; // ÍÏ×§Æðʼµã private int offsetX = 0; // XÖáÆ«ÒÆÁ¿ private int offsetY = 0; // YÖáÆ«ÒÆÁ¿ private int canvasWidth; // »­²¼¿í¶È private int canvasHeight; // »­²¼¸ß¶È private int mapWidth; // µØÍ¼Ô­Ê¼¿í¶È private int mapHeight; // µØÍ¼Ô­Ê¼¸ß¶È private int scaledWidth; // Ëõ·Åºó¿í¶È private int scaledHeight; // Ëõ·Åºó¸ß¶È private double xRatio; // XÖáÏñËØÓëʵ¼Ê¾àÀë±ÈÀý private double yRatio; // YÖáÏñËØÓëʵ¼Ê¾àÀë±ÈÀý private double actualWidth; // µØÍ¼Êµ¼Ê¿í¶È£¨µ¥Î»£ºÀåÃ×£© private double actualHeight; // µØÍ¼Êµ¼Ê¸ß¶È£¨µ¥Î»£ºÀåÃ×£© private Mapdata mapData; // µØÍ¼Êý¾Ý¶ÔÏó private int originX; // Ô­µãX×ø±ê£¨ÏñËØ£© private int originY; // Ô­µãY×ø±ê£¨ÏñËØ£© private SoftReference mapImageRef; // µØÍ¼Í¼ÏñµÄÈíÒýÓà private boolean isOpen = false; // ´°¿ÚÊÇ·ñ´ò¿ª±êÖ¾ private int sleepTime = 300; // ÖØ»æÏß³ÌÐÝÃßʱ¼ä£¨ºÁÃ룩 private Point mousePosition = new Point(0, 0); // ´æ´¢Êó±êλÖà private ResourceBundle messages; // ¹ú¼Ê»¯×ÊÔ´°ü public MapViewer(Mapdata mapData, ResourceBundle messages) { // ¹¹Ô캯Êý super(mapData.getMapName(), // ´°¿Ú±êÌâ true, // ¿É¹Ø±Õ true, // ¿É×î´ó»¯ true, // ¿É×îС»¯ true); // ¿Éµ÷Õû´óС this.mapData = mapData; // ³õʼ»¯µØÍ¼Êý¾Ý this.messages = messages; // ³õʼ»¯×ÊÔ´°ü initialize(); // µ÷Óóõʼ»¯·½·¨ } public static void createMapViewer(JDesktopPane desktopPane, String mapName, ResourceBundle messages) { // ´´½¨µØÍ¼²é¿´Æ÷¾²Ì¬·½·¨ // ¸ù¾ÝÃû³Æ»ñÈ¡µØÍ¼Êý¾Ý Mapdata mapData = Dell_Map.getMapByName(mapName); // »ñÈ¡µØÍ¼Êý¾Ý if (mapData == null) { // Èç¹ûµØÍ¼²»´æÔÚ String errorMsg = messages.getString("MAP_NOT_FOUND"); // »ñÈ¡´íÎóÏûÏ¢ JOptionPane.showMessageDialog(desktopPane, errorMsg.replace("{0}", mapName), // ÏÔʾ´íÎó¶Ô»°¿ò messages.getString("ERROR"), JOptionPane.ERROR_MESSAGE); return; // ·µ»Ø } MapViewer viewer = new MapViewer(mapData, messages); // ´´½¨µØÍ¼²é¿´Æ÷ʵÀý viewer.setVisible(true); // ÉèÖô°¿Ú¿É¼û // Ëæ»úÉèÖô°¿ÚλÖà int x = (int)(Math.random() * (desktopPane.getWidth() - viewer.getWidth())); // Ëæ»úX×ø±ê int y = (int)(Math.random() * (desktopPane.getHeight() - viewer.getHeight())); // Ëæ»úY×ø±ê viewer.setLocation(x, y); // ÉèÖô°¿ÚλÖà desktopPane.add(viewer); // Ìí¼Ó´°¿Úµ½×À̾̾°å viewer.toFront(); // ´°¿ÚÖö¥ } private void initialize() { // ³õʼ»¯·½·¨ // ÉèÖô°¿Ú´óС setSize(800, 600); // ÉèÖóõʼ´óС setDefaultCloseOperation(HIDE_ON_CLOSE); // ÉèÖùرղÙ×÷ΪÒþ²Ø setBorder(null); // È¥µô´°Ìå±ß¿ò // ¼ÓÔØµØÍ¼Í¼Ïñ String mapPath = "systemfile/imagemap/" + mapData.getMapNameDetaile(); // µØÍ¼Â·¾¶ Image image = new ImageIcon(mapPath).getImage(); // ¼ÓÔØÍ¼Ïñ mapImageRef = new SoftReference<>(image); // ´´½¨ÈíÒýÓà // »ñÈ¡µØÍ¼³ß´ç mapWidth = image.getWidth(null); // »ñȡԭʼ¿í¶È mapHeight = image.getHeight(null); // »ñȡԭʼ¸ß¶È scaledWidth = mapWidth; // ³õʼ»¯Ëõ·Å¿í¶È scaledHeight = mapHeight; // ³õʼ»¯Ëõ·Å¸ß¶È // »ñÈ¡µØÍ¼²ÎÊý actualWidth = Double.parseDouble(mapData.getActualXLength()); // ʵ¼Ê¿í¶È£¨ÀåÃ×£© actualHeight = Double.parseDouble(mapData.getActualYLength()); // ʵ¼Ê¸ß¶È£¨ÀåÃ×£© originX = Integer.parseInt(mapData.getX0Coordinate()); // Ô­µãX×ø±ê originY = Integer.parseInt(mapData.getY0Coordinate()); // Ô­µãY×ø±ê // ¼ÆËã±ÈÀý xRatio = actualWidth / scaledWidth; // ¼ÆËãXÖá±ÈÀý£¨ÀåÃ×/ÏñËØ£© yRatio = actualHeight / scaledHeight; // ¼ÆËãYÖá±ÈÀý£¨ÀåÃ×/ÏñËØ£© // ÉèÖÃÄÚÈÝÃæ°å Container content = getContentPane(); // »ñÈ¡ÄÚÈÝÃæ°å content.setLayout(new BorderLayout()); // ÉèÖñ߽粼¾Ö content.setBackground(Color.WHITE); // ÉèÖñ³¾°É« // ´´½¨»­²¼ canvas = new MapCanvas(); // ʵÀý»¯»­²¼ content.add(canvas, BorderLayout.CENTER); // Ìí¼Óµ½ÖÐÐÄ // ÉèÖô°¿Úͼ±ê setFrameIcon(new ImageIcon("image/icon/mapicon.png")); // ÉèÖÃͼ±ê // Ìí¼Ó´°¿Úʼþ¼àÌýÆ÷ addInternalFrameListener(new InternalFrameListener() { // Ìí¼ÓÄÚ²¿¿ò¼Ü¼àÌýÆ÷ @Override public void internalFrameOpened(InternalFrameEvent e) { // ´°¿Ú´ò¿ªÊ± startThread(); // Æô¶¯ÖØ»æÏß³Ì } @Override public void internalFrameClosing(InternalFrameEvent e) { // ´°¿Ú¹Ø±Õʱ isOpen = false; // ÉèÖùرձêÖ¾ mapImageRef.clear(); // Çå³ýͼÏñÒýÓà } @Override public void internalFrameClosed(InternalFrameEvent e) {} // ´°¿Ú¹Ø±Õºó£¨¿ÕʵÏÖ£© @Override public void internalFrameIconified(InternalFrameEvent e) { // ´°¿Ú×îС»¯Ê± isOpen = false; // Í£Ö¹ÖØ»æÏß³Ì } @Override public void internalFrameDeiconified(InternalFrameEvent e) { // ´°¿Ú»Ö¸´Ê± startThread(); // Æô¶¯ÖØ»æÏß³Ì } @Override public void internalFrameActivated(InternalFrameEvent e) {} // ´°¿Ú¼¤»îʱ£¨¿ÕʵÏÖ£© @Override public void internalFrameDeactivated(InternalFrameEvent e) {} // ´°¿Úʧ»îʱ£¨¿ÕʵÏÖ£© }); } public void startThread() { // Æô¶¯Ï̷߳½·¨ if (!isOpen) { // Èç¹ûÏß³ÌδÔËÐÐ isOpen = true; // ÉèÖÃÔËÐбêÖ¾ new Thread(this).start(); // Æô¶¯ÐÂÏß³Ì } } @Override public void run() { // Ïß³ÌÔËÐз½·¨ while (isOpen) { // Ñ­»·Ö±µ½¹Ø±Õ try { canvas.repaint(); // ÖØ»æ»­²¼ Thread.sleep(sleepTime); // Ïß³ÌÐÝÃß } catch (InterruptedException e) { e.printStackTrace(); // ´òÓ¡Òì³£ } } } /** * µØÍ¼»­²¼Àà */ class MapCanvas extends Canvas implements MouseListener, MouseMotionListener, MouseWheelListener { // ×Ô¶¨Òå»­²¼Àà private static final long serialVersionUID = 1L; // ÐòÁл¯°æ±¾ID private Image buffer; // Ë«»º³åͼÏñ public MapCanvas() { // ¹¹Ô캯Êý dragOrigin = new Point(); // ³õʼ»¯ÍÏ×§Æðµã addMouseListener(this); // Ìí¼ÓÊó±ê¼àÌýÆ÷ addMouseMotionListener(this); // Ìí¼ÓÊó±êÒÆ¶¯¼àÌýÆ÷ addMouseWheelListener(this); // Ìí¼ÓÊó±ê¹öÂÖ¼àÌýÆ÷ setBackground(Color.WHITE); // ÉèÖñ³¾°É« setBorder(null); // È¥µô»­²¼±ß¿ò } // Ë«»º³å½â¾öÉÁ˸ÎÊÌâ @Override public void update(Graphics g) { // ÖØÐ´updateʵÏÖË«»º³å if (buffer == null || // Èç¹û»º³åͼÏñ²»´æÔÚ buffer.getWidth(null) != getWidth() || // »ò³ß´ç²»Æ¥Åä buffer.getHeight(null) != getHeight()) { buffer = createImage(getWidth(), getHeight()); // ´´½¨Ð»º³åͼÏñ } if (buffer != null) { // Èç¹û»º³åͼÏñÓÐЧ Graphics bg = buffer.getGraphics(); // »ñÈ¡»º³åͼÐζÔÏó bg.setColor(getBackground()); // ÉèÖñ³¾°É« bg.fillRect(0, 0, getWidth(), getHeight()); // Ìî³ä±³¾° paint(bg); // ÔÚ»º³åÉÏ»æÖÆÄÚÈÝ g.drawImage(buffer, 0, 0, this); // ½«»º³å»æÖƵ½ÆÁÄ» } else { super.update(g); // µ÷Óø¸Àà·½·¨ } } @Override public void paint(Graphics g) { // »æÖÆ·½·¨ super.paint(g); // µ÷Óø¸Àà Graphics2D g2d = (Graphics2D) g; // ת»»ÎªGraphics2D // ÉèÖÿ¹¾â³Ý g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); // ¿ªÆôͼÐο¹¾â³Ý g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); // ¿ªÆôÎı¾¿¹¾â³Ý // »ñÈ¡µ±Ç°»­²¼³ß´ç canvasWidth = getWidth(); // »ñÈ¡»­²¼¿í¶È canvasHeight = getHeight(); // »ñÈ¡»­²¼¸ß¶È // »æÖƵØÍ¼ Image mapImage = mapImageRef.get(); // »ñÈ¡µØÍ¼Í¼Ïñ if (mapImage != null) { // Èç¹ûͼÏñ´æÔÚ g2d.drawImage(mapImage, offsetX, offsetY, scaledWidth, scaledHeight, this); // »æÖƵØÍ¼ } // »æÖÆ×ø±êÔ­µã drawOrigin(g2d); // µ÷ÓÃÔ­µã»æÖÆ·½·¨ // ÔÚÓÒϽÇÏÔʾ±ÈÀýÐÅÏ¢ drawMapInfo(g2d); // µ÷ÓõØÍ¼ÐÅÏ¢»æÖÆ·½·¨ // ÔÚ×óϽÇÏÔʾÊó±êλÖõÄʵ¼Ê×ø±ê drawMouseCoordinates(g2d); // µ÷ÓÃÊó±ê×ø±ê»æÖÆ·½·¨ } private void drawOrigin(Graphics2D g2d) { // »æÖÆÔ­µã·½·¨ int originScreenX = offsetX - (int)(originX / xRatio); // ¼ÆËãÔ­µãÆÁÄ»X×ø±ê int originScreenY = offsetY - (int)(originY / yRatio); // ¼ÆËãÔ­µãÆÁÄ»Y×ø±ê g2d.setColor(Color.RED); // ÉèÖúìÉ« g2d.fillOval(originScreenX - 5, originScreenY - 5, 10, 10); // »æÖÆÔ­µã±ê¼Ç g2d.setColor(Color.BLACK); // ÉèÖúÚÉ« // ʹÓÃ×ÊÔ´°ü»ñȡԭµã±ê¼ÇÎı¾ g2d.drawString(messages.getString("ORIGIN_MARK"), originScreenX + 10, originScreenY); // »æÖÆÔ­µã±êÇ© } private void drawMapInfo(Graphics2D g2d) { // »æÖƵØÍ¼ÐÅÏ¢·½·¨ g2d.setColor(Color.BLACK); // ÉèÖúÚÉ« Font font = new Font("΢ÈíÑźÚ", Font.BOLD, 14); // ´´½¨×ÖÌå g2d.setFont(font); // ÉèÖÃ×ÖÌå // ʹÓÃ×ÊÔ´°ü»ñÈ¡±ÈÀýÎı¾ String scaleText = String.format(messages.getString("SCALE_FORMAT"), scale); // ¸ñʽ»¯±ÈÀýÎı¾ FontMetrics fm = g2d.getFontMetrics(); // »ñÈ¡×ÖÌå¶ÈÁ¿ int textWidth = fm.stringWidth(scaleText); // ¼ÆËãÎı¾¿í¶È // ÔÚÓÒϽǻæÖƱÈÀýÐÅÏ¢ int x = canvasWidth - textWidth - 20; // ¼ÆËãX×ø±ê int y = canvasHeight - 20; // ¼ÆËãY×ø±ê g2d.drawString(scaleText, x, y); // »æÖÆÎı¾ } private void drawMouseCoordinates(Graphics2D g2d) { // »æÖÆÊó±ê×ø±ê·½·¨ // ¼ÆËãÊó±êλÖõÄʵ¼Ê×ø±ê£¨ÀåÃ×£© double actualX = originX + (mousePosition.x - offsetX) * xRatio; // ¼ÆËãʵ¼ÊX×ø±ê double actualY = originY + (mousePosition.y - offsetY) * yRatio; // ¼ÆËãʵ¼ÊY×ø±ê g2d.setColor(Color.BLACK); // ÉèÖúÚÉ« Font font = new Font("΢ÈíÑźÚ", Font.BOLD, 14); // ´´½¨×ÖÌå g2d.setFont(font); // ÉèÖÃ×ÖÌå // ʹÓÃ×ÊÔ´°ü»ñÈ¡×ø±êÎı¾ String coordText = String.format( // ¸ñʽ»¯×ø±êÎı¾ messages.getString("COORDINATE_FORMAT"), actualX, actualY ); // ÔÚ×óϽǻæÖÆ×ø±êÐÅÏ¢ int x = 20; // X×ø±ê int y = canvasHeight - 20; // Y×ø±ê g2d.drawString(coordText, x, y); // »æÖÆÎı¾ } // Êó±êʼþ´¦Àí @Override public void mousePressed(MouseEvent e) { // Êó±ê°´Ï dragOrigin = e.getPoint(); // ¼Ç¼ÍÏ×§Æðµã setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR)); // ÉèÖÃÒÆ¶¯¹â±ê } @Override public void mouseDragged(MouseEvent e) { // Êó±êÍÏ×§ Point current = e.getPoint(); // »ñÈ¡µ±Ç°µã offsetX += current.x - dragOrigin.x; // ¸üÐÂXÆ«ÒÆ offsetY += current.y - dragOrigin.y; // ¸üÐÂYÆ«ÒÆ dragOrigin = current; // ¸üÐÂÍÏ×§Æðµã repaint(); // ÖØ»æ»­²¼ } @Override public void mouseReleased(MouseEvent e) { // Êó±êÊÍ·Å setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); // »Ö¸´Ä¬ÈϹâ±ê } @Override public void mouseMoved(MouseEvent e) { // Êó±êÒÆ¶¯ // ¸üÐÂÊó±êλÖà mousePosition = e.getPoint(); // ¼Ç¼Êó±êλÖà repaint(); // ÖØ»æ»­²¼ } @Override public void mouseWheelMoved(MouseWheelEvent e) { // Êó±ê¹öÂÖʼþ int rotation = e.getWheelRotation(); // »ñÈ¡¹öÂÖÐýת·½Ïò double zoomFactor = 1.1; // Ëõ·ÅÒò×Ó // ¼ÆËãÊó±êµ±Ç°Î»ÖöÔÓ¦µÄµØÍ¼×ø±ê Point mousePos = e.getPoint(); // »ñÈ¡Êó±êλÖà double prevMapX = (mousePos.x - offsetX) * xRatio; // ¼ÆËãÔ­µØÍ¼X×ø±ê double prevMapY = (mousePos.y - offsetY) * yRatio; // ¼ÆËãÔ­µØÍ¼Y×ø±ê // µ÷ÕûËõ·Å±ÈÀý£¨ÏÞÖÆÔÚ0.2-5.0±¶Ö®¼ä£© if (rotation < 0 && scale < 5.0) { // ·Å´ó scale *= zoomFactor; // ·Å´ó±ÈÀý if (scale > 5.0) { // ÉÏÏÞ¼ì²é scale = 5.0; // ÉèÖÃ×î´óÖµ } } else if (rotation > 0 && scale > 0.2) { // ËõС scale /= zoomFactor; // ËõС±ÈÀý if (scale < 0.2) { // ÏÂÏÞ¼ì²é scale = 0.2; // ÉèÖÃ×îСֵ } } // Ó¦ÓÃËõ·Å scaledWidth = (int)(mapWidth * scale); // ¼ÆËãпí¶È scaledHeight = (int)(mapHeight * scale); // ¼ÆËãÐÂ¸ß¶È // ¸üбÈÀý xRatio = actualWidth / scaledWidth; // ¸üÐÂX±ÈÀý yRatio = actualHeight / scaledHeight; // ¸üÐÂY±ÈÀý // ¼ÆËãËõ·ÅºóµÄÆ«ÒÆÁ¿£¬Ê¹Êó±êλÖöÔÓ¦µÄµØÍ¼Î»Öñ£³Ö²»±ä double newMapX = prevMapX / xRatio; // ¼ÆËãÐÂÆÁÄ»X×ø±ê double newMapY = prevMapY / yRatio; // ¼ÆËãÐÂÆÁÄ»Y×ø±ê offsetX = (int)(mousePos.x - newMapX); // ¸üÐÂXÆ«ÒÆ offsetY = (int)(mousePos.y - newMapY); // ¸üÐÂYÆ«ÒÆ repaint(); // ÖØ»æ»­²¼ } // ÆäËûÊó±êʼþ£¨¿ÕʵÏÖ£© @Override public void mouseClicked(MouseEvent e) {} // Êó±êµã»÷ @Override public void mouseEntered(MouseEvent e) {} // Êó±ê½øÈë @Override public void mouseExited(MouseEvent e) {} // Êó±êÀ뿪 } /** * ´´½¨ËùÓеØÍ¼µÄ´°¿Ú */ public static void createAllMapViewers(JDesktopPane desktopPane, ResourceBundle messages) { // ´´½¨ËùÓеØÍ¼´°¿Ú List allMaps = Dell_Map.getAllMaps(); // »ñÈ¡ËùÓеØÍ¼Êý¾Ý for (Mapdata map : allMaps) { // ±éÀúµØÍ¼ MapViewer viewer = new MapViewer(map, messages); // ´´½¨²é¿´Æ÷ viewer.setVisible(true); // ÉèÖÿɼû // Ëæ»úÉèÖô°¿ÚλÖà int x = (int)(Math.random() * (desktopPane.getWidth() - viewer.getWidth())); // Ëæ»úX int y = (int)(Math.random() * (desktopPane.getHeight() - viewer.getHeight())); // Ëæ»úY viewer.setLocation(x, y); // ÉèÖÃλÖà desktopPane.add(viewer); // Ìí¼Óµ½×ÀÃæ viewer.toFront(); // Öö¥ } } }