2008-09-22 12 views
10

मैं JScrollPane के अंदर स्थिति-संवेदनशील ज़ूमिंग को लागू करने की कोशिश कर रहा हूं। JScrollPane में एक अनुकूलित paint वाला एक घटक होता है जो इसे आवंटित किए गए स्थान के भीतर स्वयं खींच लेगा - इसलिए ज़ूमिंग MouseWheelListener का उपयोग करने जितना आसान है जो आवश्यकतानुसार आंतरिक घटक का आकार बदलता है।आप JScrollPane के अंदर स्थिति-संवेदनशील ज़ूमिंग कैसे कार्यान्वित करते हैं?

लेकिन मैं उस बिंदु को ज़ूम करने के लिए एक बिंदु (या बाहर) ज़ूम करना चाहता हूं ताकि परिणामस्वरूप ज़ूम-इन (या-आउट) व्यू के भीतर जितना संभव हो सके केंद्र (यह वही है जिसे मैं 'स्थिति-संवेदनशील' के रूप में संदर्भित करता हूं) ज़ूमिंग), Google नक्शे में ज़ूमिंग कैसे काम करता है। मुझे यकीन है कि यह कई बार पहले किया गया है - क्या किसी को जावा स्विंग के तहत ऐसा करने का "सही" तरीका पता है? JScrollPanes का उपयोग करने के बजाय Graphic2D के परिवर्तनों के साथ खेलना बेहतर होगा?

नमूना कोड इस प्रकार है:

package test; 

import java.awt.*; 
import java.awt.event.*; 
import java.awt.geom.*; 
import javax.swing.*; 

public class FPanel extends javax.swing.JPanel { 

private Dimension preferredSize = new Dimension(400, 400);  
private Rectangle2D[] rects = new Rectangle2D[50]; 

public static void main(String[] args) {   
    JFrame jf = new JFrame("test"); 
    jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    jf.setSize(400, 400); 
    jf.add(new JScrollPane(new FPanel())); 
    jf.setVisible(true); 
}  

public FPanel() { 
    // generate rectangles with pseudo-random coords 
    for (int i=0; i<rects.length; i++) { 
     rects[i] = new Rectangle2D.Double(
       Math.random()*.8, Math.random()*.8, 
       Math.random()*.2, Math.random()*.2); 
    } 
    // mouse listener to detect scrollwheel events 
    addMouseWheelListener(new MouseWheelListener() { 
     public void mouseWheelMoved(MouseWheelEvent e) { 
      updatePreferredSize(e.getWheelRotation(), e.getPoint()); 
     } 
    }); 
} 

private void updatePreferredSize(int n, Point p) { 
    double d = (double) n * 1.08; 
    d = (n > 0) ? 1/d : -d; 
    int w = (int) (getWidth() * d); 
    int h = (int) (getHeight() * d); 
    preferredSize.setSize(w, h); 
    getParent().doLayout(); 
    // Question: how do I keep 'p' centered in the resulting view? 
} 

public Dimension getPreferredSize() { 
    return preferredSize; 
} 

private Rectangle2D r = new Rectangle2D.Float(); 
public void paint(Graphics g) { 
    super.paint(g); 
    g.setColor(Color.red); 
    int w = getWidth(); 
    int h = getHeight(); 
    for (Rectangle2D rect : rects) { 
     r.setRect(rect.getX() * w, rect.getY() * h, 
       rect.getWidth() * w, rect.getHeight() * h); 
     ((Graphics2D)g).draw(r); 
    }  
    } 
} 
+0

जोड़ा इनाम देखने के लिए (आदर्श: कोड स्निपेट है कि, जब ऊपर कहा, सवाल का जवाब)। – tucuxi

उत्तर

8

इस परीक्षण किया गया, काम करने के लिए लगता है ...

private void updatePreferredSize(int n, Point p) { 
    double d = (double) n * 1.08; 
    d = (n > 0) ? 1/d : -d; 

    int w = (int) (getWidth() * d); 
    int h = (int) (getHeight() * d); 
    preferredSize.setSize(w, h); 

    int offX = (int)(p.x * d) - p.x; 
    int offY = (int)(p.y * d) - p.y; 
    setLocation(getLocation().x-offX,getLocation().y-offY); 

    getParent().doLayout(); 
} 

अद्यतन

यहाँ एक स्पष्टीकरण है: बिंदु pFPanel करने के लिए माउस रिश्तेदार का स्थान है। चूंकि आप पैनल के आकार को स्केल कर रहे हैं, p (पैनल के आकार के सापेक्ष) का स्थान उसी कारक से स्केल करेगा। स्केल किए गए स्थान से वर्तमान स्थान को घटाकर, आपको पैनल का आकार बदलने पर बिंदु 'शिफ्ट' कितना मिलता है। फिर यह माउस कर्सर के नीचे p डालने के लिए विपरीत दिशा में उसी राशि से स्क्रॉल फलक में पैनल स्थान को स्थानांतरित करने का विषय है।

+0

बिल्कुल वही जो मैं खोज रहा था। धन्यवाद! – tucuxi

1

आपका MouseWheelListener भी कर्सर का पता लगाने, jScrollPane के केंद्र पर ले जाते हैं और xmin/ymin समायोजित करने के लिए है और सामग्री के xmax/ymax देखा जाना चाहिए।

+0

हां, यह सच है - यह वही है जो मैं पहली जगह में करने की कोशिश कर रहा था (कर्सर 'पी' पर स्थित है, और उन सीमाओं को सही ढंग से समायोजित करना है जो मुझे नहीं पता कि मुझे कैसे करना है)। – tucuxi

1

मुझे लगता है कि इस तरह श्रीमती काम करना चाहिए ...


private void updatePreferredSize(int n, Point p) { 
    double d = (double) n * 1.08; 
    d = (n > 0) ? 1/d : -d; 
    int w = (int) (getWidth() * d); 
    int h = (int) (getHeight() * d); 
    preferredSize.setSize(w, h); 

    // Question: how do I keep 'p' centered in the resulting view? 

    int parentWdt = this.getParent().getWidth() ; 
    int parentHgt = this.getParent().getHeight() ; 

    int newLeft = p.getLocation().x - (p.x - (parentWdt/2)) ; 
    int newTop = p.getLocation().y - (p.y - (parentHgt/2)) ; 
    this.setLocation(newLeft, newTop) ; 

    getParent().doLayout(); 
} 

संपादित करें: बदली गई कुछ चीज़ें।

+0

आपका कोड परिणामस्वरूप दृश्य में केंद्रित 'पी' बिंदु नहीं रखता है (उदाहरण के लिए, नीचे-दाएं कोने के पास ज़ूमिंग करने का प्रयास करें), 'int newTop = py - w/2;' 'int newTop = पीई - एच/2; '। उत्तर के रूप में इसे प्रस्तावित करने से पहले कोड का परीक्षण करें। – tucuxi

+0

अपडेट किया गया कोड शीर्ष बाएं कोने (XP पर जावा 6) में ज़ूम करने लगता है, जहां माउस पॉइंटर इंगित नहीं कर रहा है। मैं प्रश्न में सूचीबद्ध एक ही परीक्षण कार्यक्रम का उपयोग कर रहा हूँ। – tucuxi

2

यहाँ @Kevin कश्मीर के समाधान की एक छोटी सी रिफैक्टरिंग है: अगर मैं एक पूरा जवाब प्राप्त कर सकते हैं

private void updatePreferredSize(int wheelRotation, Point stablePoint) { 
    double scaleFactor = findScaleFactor(wheelRotation); 
    scaleBy(scaleFactor); 
    Point offset = findOffset(stablePoint, scaleFactor); 
    offsetBy(offset); 
    getParent().doLayout(); 
} 

private double findScaleFactor(int wheelRotation) { 
    double d = wheelRotation * 1.08; 
    return (d > 0) ? 1/d : -d; 
} 

private void scaleBy(double scaleFactor) { 
    int w = (int) (getWidth() * scaleFactor); 
    int h = (int) (getHeight() * scaleFactor); 
    preferredSize.setSize(w, h); 
} 

private Point findOffset(Point stablePoint, double scaleFactor) { 
    int x = (int) (stablePoint.x * scaleFactor) - stablePoint.x; 
    int y = (int) (stablePoint.y * scaleFactor) - stablePoint.y; 
    return new Point(x, y); 
} 

private void offsetBy(Point offset) { 
    Point location = getLocation(); 
    setLocation(location.x - offset.x, location.y - offset.y); 
} 
संबंधित मुद्दे