2012-10-04 10 views
5

मैं स्विंग के साथ ज़ूम करने योग्य मानचित्र बनाने की कोशिश कर रहा हूं। नक्शा जेएसक्रोलपैन में एक जेपीनल है। जब ज़ूम इन किया जाता है, तो नक्शा आकार बदलता है और पेंट() तत्वों को एक अलग स्थिति में चित्रित करता है। यह सब महान काम करता है।केंद्र को स्थानांतरित किए बिना जेपीनेल में ज़ूम इन करने के लिए कैसे करें: गणित या स्विंग?

हालांकि, छवि आकार को बढ़ाने के दौरान स्क्रॉलपैन ने व्यूपोर्ट नहीं बदला, ताकि ज़ूमिंग उन तत्वों को हमेशा स्थानांतरित कर दे जो मैं स्क्रीन से बाहर देख रहा था। मैंने scrollRectToVisible() के साथ इसे हल करने का प्रयास किया, लेकिन मैं आयताकार के लिए सही निर्देशांक प्राप्त करने का प्रबंधन नहीं करता, या तो क्योंकि मैं ज्यामिति करने में विफल रहता हूं या क्योंकि मुझे यह सब ठीक से स्विंग नहीं समझा जाता है।

public class MapPanel extends JPanel { 
    [...] 

public void setZoom(double zoom) { 
    // get the current viewport rectangle and its center in the scaled coordinate system 
    JViewport vp = (JViewport) this.getParent(); 
    Rectangle rect = vp.getViewRect(); 
    Point middle = getMiddle(rect); 
    Dimension dim = rect.getSize(); 

    // zoom in 
    scaler.setZoom(zoom); 
    setPreferredSize(scaler.transform(dim));  
    this.revalidate(); 

// calculate the full size of the scaled coordinate system 
    Dimension fullDim = scaler.transform(dim); 
    // calculate the non-scaled center of the viewport 
    Point nMiddle = new Point((int) ((double) (middle.x)/fullDim.width*dim.width),(int) ((double) (middle.y)/fullDim.height*dim.height)); 

    // this should do the trick, but is always a bit off towards the origin 
    scrollRectToVisible(getRectangleAroundPoint(nMiddle)); 

    // the below alternative always zooms in perfectly to the center of the map 
    // scrollRectToVisible(getRectangleAroundPoint(new Point(400,300))); 
} 

private Rectangle getRectangleAroundPoint(Point p){ 
    Point newP = scaler.transform(p); 
    Dimension d = railMap.getDimension(); 
    Point corner = new Point(newP.x-d.width/2,newP.y-d.height/2); 
    return new Rectangle(corner,d); 
} 

private Point getMiddle(Rectangle r){ 
    return new Point(r.x+r.width/2,r.y+r.height/2); 
} 
} 

और यहाँ Scaler वर्ग (जो कुछ नहीं करता है बहुत ही आश्चर्य की, मुझे लगता है) है::

public class Scaler { 
    private double zoom = 1; 

public void setZoom(double zoom) { 
    this.zoom = zoom; 
} 


public Point transform(Point2D p){ 
    return new Point((int) (p.getX()*zoom), (int) (p.getY()*zoom)); 
} 


public Dimension transform(Dimension d){ 
    return new Dimension((int) (d.width*zoom), (int) (d.height*zoom)); 
} 

} 

कौन मुझे बता सकते हैं जहां कोई बात बिगड़ जा रहे हैं

यहाँ मैं क्या किया है? यह मैं नक्शा की वर्तमान केंद्र का एक मान्य गणना किया था, और एक निश्चित जूम बिंदु यह काम करता है के साथ मुझे लगता है ...

संपादित करें: इसलिए यहाँ कठिन बात नई व्यूपोर्ट आयत बनाने के लिए है आधारित पुराने व्यूपोर्ट आयत पर।

+0

रेलमैप? आप जेएमआरआई जैसे कुछ पर काम नहीं करेंगे? ;-) – geowar

उत्तर

5

मैं सिर्फ यह वास्तव में त्वरित उदाहरण है, जो मूल रूप से आपूर्ति की छवि के मध्य के आसपास स्क्रॉल फलक केंद्र रखने के लिए

public class TestZooming { 

    public static void main(String[] args) { 
     new TestZooming(); 
    } 

    public TestZooming() { 

     EventQueue.invokeLater(new Runnable() { 
      @Override 
      public void run() { 

       try { 
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
       } catch (ClassNotFoundException classNotFoundException) { 
       } catch (InstantiationException instantiationException) { 
       } catch (IllegalAccessException illegalAccessException) { 
       } catch (UnsupportedLookAndFeelException unsupportedLookAndFeelException) { 
       } 

       JFrame frame = new JFrame(); 
       frame = new JFrame(); 
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       frame.setSize(400, 400); 
       frame.setLocationRelativeTo(null); 
       frame.setLayout(new BorderLayout()); 
       final ZoomPane pane = new ZoomPane(); 
       frame.add(new JScrollPane(pane)); 
       frame.setVisible(true); 

       SwingUtilities.invokeLater(new Runnable() { 

        @Override 
        public void run() { 
         pane.centerInViewport(); 
        } 

       }); 

      } 
     }); 

    } 

    protected class ZoomPane extends JPanel { 

     private Image background; 
     private Image scaled; 
     private float zoom = 1f; 

     private Dimension scaledSize; 
     private JViewport con; 

     public ZoomPane() { 

      try { 
       background = ImageIO.read(new File("...")); 
       scaled = background; 
       scaledSize = new Dimension(background.getWidth(this), background.getHeight(this)); 
      } catch (IOException ex) { 
       ex.printStackTrace(); 
      } 

      InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW); 
      ActionMap am = getActionMap(); 

      im.put(KeyStroke.getKeyStroke(KeyEvent.VK_PLUS, 0), "plus"); 
      im.put(KeyStroke.getKeyStroke(KeyEvent.VK_EQUALS, InputEvent.SHIFT_DOWN_MASK), "plus"); 
      im.put(KeyStroke.getKeyStroke(KeyEvent.VK_MINUS, 0), "minus"); 

      am.put("plus", new AbstractAction() { 
       @Override 
       public void actionPerformed(ActionEvent e) { 
        setZoom(getZoom() + 0.1f); 
       } 
      }); 
      am.put("minus", new AbstractAction() { 
       @Override 
       public void actionPerformed(ActionEvent e) { 
        setZoom(getZoom() - 0.1f); 
       } 
      }); 

      setFocusable(true); 
      requestFocusInWindow(); 

     } 

     @Override 
     public void addNotify() { 

      super.addNotify(); 

     } 

     public float getZoom() { 
      return zoom; 
     } 

     public void setZoom(float value) { 
      if (zoom != value) { 
       zoom = value; 

       if (zoom < 0) { 
        zoom = 0f; 
       } 

       int width = (int) Math.floor(background.getWidth(this) * zoom); 
       int height = (int) Math.floor(background.getHeight(this) * zoom); 
       scaled = background.getScaledInstance(width, height, Image.SCALE_SMOOTH); 
       scaledSize = new Dimension(width, height); 

       if (getParent() instanceof JViewport) { 

        int centerX = width/2; 
        int centerY = height/2; 

        JViewport parent = (JViewport) getParent(); 
        Rectangle viewRect = parent.getViewRect(); 
        viewRect.x = centerX - (viewRect.width/2); 
        viewRect.y = centerY - (viewRect.height/2); 
        scrollRectToVisible(viewRect); 
       } 

       invalidate(); 
       repaint(); 

      } 
     } 

     @Override 
     public Dimension getPreferredSize() { 

      return scaledSize; 

     } 

     @Override 
     protected void paintComponent(Graphics g) { 

      super.paintComponent(g); 

      if (scaled != null) { 

       g.drawImage(scaled, 0, 0, this); 

      } 

     } 

     protected void centerInViewport() { 

      Container container = getParent(); 
      if (container instanceof JViewport) { 

       JViewport port = (JViewport) container; 
       Rectangle viewRect = port.getViewRect(); 

       int width = getWidth(); 
       int height = getHeight(); 

       viewRect.x = (width - viewRect.width)/2; 
       viewRect.y = (height - viewRect.height)/2; 

       scrollRectToVisible(viewRect); 

      } 

     } 
    } 
} 

क्यों तुम्हारा काम नहीं करता है के रूप में, मैं यह नहीं कह सकते की कोशिश करता था, मैं उदाहरण नहीं चला सकता, लेकिन शायद यह आपको कम से कम कुछ विचार देगा ...

+0

धन्यवाद। हालांकि, अगर मैं सही ढंग से समझता हूं, तो आप हमेशा छवि के केंद्र में ज़ूम इन करते हैं। यह मेरे लिए काम किया। वर्तमान दृष्टिकोण के केंद्र की गणना नहीं कर रहा था और उस केंद्र में ज़ूम कर रहा था। क्या आपको लगता है कि आप उस पर अपना उदाहरण समायोजित कर पाएंगे? मुझे लगता है कि इसे 'viewRect.x' और '.y' को छोड़कर, आपके केंद्र इनव्यूपोर्ट() फ़ंक्शन की तरह बहुत कुछ दिखना चाहिए। मुझे यह भी लगता है कि मुझे पता है कि कैसे (मेरा उदाहरण देखें), सिवाय इसके कि काम करने के लिए बाहर नहीं निकलता है ... – roelandvanbeek

+0

कभी नहीं, मैंने इसे आपके उदाहरण से कुछ संकेतों के साथ हल किया। जैसे ही आठ घंटे खत्म हो जाएंगे, पूर्णता के लिए मेरा समाधान पोस्ट करेंगे। – roelandvanbeek

1

इसे हल किया गया। वाह। अभी भी यह सुनिश्चित नहीं है कि यह वास्तव में गलत कहां गया है, लेकिन एक नया बनाने और स्केलर में सही गोल करने के बजाय मूल आयताकार (धन्यवाद @ मैडप्रोग्रामर) को स्थानांतरित करने से चाल चल सकती है।

private Point getViewportCenter() { 
    JViewport vp = (JViewport) this.getParent(); 
    Point p = vp.getViewPosition(); 
    return new Point(p.x+vp.getWidth()/2,p.y+vp.getHeight()/2); 
} 

private void setViewportCenter(Point p) { 
    JViewport vp = (JViewport) this.getParent(); 
    Rectangle viewRect = vp.getViewRect(); 

    viewRect.x = p.x - viewRect.width/2; 
    viewRect.y = p.y - viewRect.height/2; 

    scrollRectToVisible(viewRect); 
} 

public void setZoom(double zoom) { 
    // determine unscaled center and dimensions 
    Point oCenter = scaler.inverseTransform(getViewportCenter()); 
    Dimension dim = railMap.getDimension(); 

    // zoom 
    scaler.setZoom(zoom); 

    // fix size and viewport 
    setPreferredSize(scaler.transform(dim)); 
    setViewportCenter(scaler.transform(oCenter)); // should be a transformed point 

    // finish 
    invalidate(); 
    repaint(); 
} 
संबंधित मुद्दे