2011-07-25 26 views
1

對不起,這是一個漫長的一段下面的示例代碼,但這裏的問題:JScrollPane的「跳樓」時滾動條開始使用

我有一個背景下,我積極繪圖(我可能是聰明,繪製一次,然後按比例縮放,但這也顯示了問題)。

您可以使用鼠標滾輪放大和縮小圖像。

這個想法是做一個「谷歌地圖」縮放,它放大鼠標指針下。我注意到,它似乎並沒有真正的行爲,直到圖像大到足以使用兩個滾動條。在此之前,你的形象變得越來越大,但鎖定在原點。

「正確的」行爲應該是移動視圖位置,即使滾動條尚未被超大圖像使用。

我不知道如何解決這個問題(或者如果這是正確的和預期的),而不在圖像後面繪製更大的背景,因此它不僅填充視口。

由於(我認爲)同一個問題,它在一個或另一個滾動條參與之後「跳轉」。

想法?

package com.hostigr.raw.io.client.gui; 

import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.Point; 
import java.awt.RenderingHints; 
import java.awt.event.MouseWheelEvent; 
import java.awt.event.MouseWheelListener; 

import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.JScrollPane; 
import javax.swing.JViewport; 

public class TestFrame extends JFrame { 

    public static void main(String[] arg) { 
      new TestFrame(); 
    } 

    public TestFrame() { 
     initComponents(); 
     setVisible(true); 
    } 

    private void initComponents() { 
     setLayout(new BorderLayout()); 

     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     setSize(600, 600); 
     setPreferredSize(new Dimension(600, 600)); 

     add(new TopPanel()); 

    } 

    private class TopPanel extends JPanel { 
     JScrollPane scrollPane; 

     public TopPanel() { 
      setPreferredSize(new Dimension(500,500)); 
      scrollPane = new JScrollPane(new InteriorPanel()); 
      scrollPane.setPreferredSize(new Dimension(500,500)); 
      scrollPane.getVerticalScrollBar().setPreferredSize(new Dimension(10,490)); 
      scrollPane.getHorizontalScrollBar().setPreferredSize(new Dimension(490,10)); 
      scrollPane.setWheelScrollingEnabled(false); 
      scrollPane.setHorizontalScrollBarPolicy(
        JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); 
      scrollPane.setVerticalScrollBarPolicy(
        JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); 
      add(scrollPane); 

     } 
    } 

    private class InteriorPanel extends JPanel { 
     private double scale = 10.0; 
     private final double scaleModifier = 0.1; 
     private final int width = 10; 
     private Point loc = new Point(0,0); 
     private final int SIZE = 10; 

     public InteriorPanel() { 
      super(true); 
      setPreferredSize(new Dimension((int)(scale * width * SIZE), 
        (int)(scale * width * SIZE))); 
      this.addMouseWheelListener(new MapMouseWheelListener()); 
     } 

     @Override 
     public void paintComponent(Graphics g) { 
      super.paintComponent(g); 
      Graphics2D g2D = (Graphics2D) g; 
      g2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 
       RenderingHints.VALUE_ANTIALIAS_ON); 
      g2D.scale(scale,scale); 

      for (int row = 0; row <= SIZE; row++) { 
       for (int col = 0; col < SIZE; col++) { 
        if ((col + row) % 2 == 0) { 
         g2D.setColor(Color.white); 
        } else { 
         g2D.setColor(Color.black); 
        } 
        g2D.fillRect(col * width, row * width, width, width); 
       } 
      } 

     } 

     private void incrementScale(int notches) { 
      double modifier = 0; 
      double prevScale = scale; 
      if (notches != 0) { 
       modifier = 1.0 + -notches/Math.abs(notches) * scaleModifier; 
      } 
      scale = scale * Math.pow(modifier, Math.abs(notches)); 
      /*if (scale * width < 1) { 
       scale = 1.0/width; 
      } else if (scale * width * 3 > parentHeight || scale * width * 3 > parentWidth) { 
       if (parentHeight > parentWidth) { 
        scale = parentWidth/3.0/width; 
       } else { 
        scale = parentHeight/3.0/width; 
       } 
      } else if (scale * width * SIZE < parentWidth) { 
       scale = parentWidth/(double)SIZE/width; 
      } else if (scale * width * SIZE < parentHeight) { 
       scale = parentHeight/(double)SIZE/width; 
      }*/ 

      this.repaint(); 
      setPreferredSize(new Dimension((int)(scale * width * SIZE), 
        (int)(scale * width * SIZE))); 

      JViewport viewport = ((JViewport)(getParent().getParent().getComponent(0))); 
      Point orig = viewport.getViewPosition(); 
      viewport.setViewPosition(new Point(
        orig.x - (int)Math.round(loc.x*(1 - scale/prevScale)), 
        orig.y - (int)Math.round(loc.y*(1 - scale/prevScale)))); 
      System.out.println(orig + "\n " + loc + "\n " + (1 - scale/prevScale)); 
      revalidate(); 
     } 

     private class MapMouseWheelListener implements MouseWheelListener { 

      @Override 
      public void mouseWheelMoved(MouseWheelEvent e) { 
       loc = e.getPoint(); 
       incrementScale(e.getWheelRotation()); 
      } 
     } 
    } 
} 
+0

結束,我想我認識的方式來闡述問題:視口正在設置一個可見的矩形/在滾動面板中的組件內。如果組件小於可視矩形,那麼這種範例顯然沒有任何意義。但是,我覺得你應該/仍然/能夠以某種方式改變內部部件相對於可視矩形的位置?或者,我唯一的答案是繪製比視口大的不透明邊框,因此它比滾動窗格保持「更大」? – AndyMac

+0

噢,即使我限制最小尺寸以使其等於視口的大小,仍然會發生不連續性......縮放步驟/滾動條之後的一個小「跳躍」和I我不確定是什麼原因造成的。 – AndyMac

+0

對不起,我看不到任何更新在你身邊,如果包含矩形或點,請勿隨JViewPort移動, – mKorbel

回答

1

看起來像作爲JViewPort#scrollRectToVisible(Rectangle r)對我的作品

 viewport.scrollRectToVisible(new Rectangle(new Point(
    orig.x - (int) Math.round(loc.x * (1 - scale/prevScale)), 
    orig.y - (int) Math.round(loc.y * (1 - scale/prevScale))))); 

進行修改並與正確的揮杆重繪的rulles,然後YOUT代碼塊必須revalidate(); + repaint();

 setPreferredSize(new Dimension((int) (scale * width * SIZE), 
     (int) (scale * width * SIZE))); 
     JViewport viewport = ((JViewport) (getParent().getParent().getComponent(0))); 
     Point orig = viewport.getViewPosition(); 
     /*viewport.setViewPosition(new Point(
       orig.x - (int) Math.round(loc.x * (1 - scale/prevScale)), 
       orig.y - (int) Math.round(loc.y * (1 - scale/prevScale))));*/ 
     viewport.scrollRectToVisible(new Rectangle(new Point(
       orig.x - (int) Math.round(loc.x * (1 - scale/prevScale)), 
       orig.y - (int) Math.round(loc.y * (1 - scale/prevScale))))); 
     System.out.println(orig + "\n " + loc + "\n " + (1 - scale/prevScale)); 

     revalidate(); 
     repaint(); 
+0

對不起,也許我錯過了一些東西,但是這不顯示正確的行爲。我的目標是像谷歌地圖這樣的縮放功能,您在鼠標上的位置不會移動。有了這個,視口試圖保持「移位的原點」的視野,這幾乎總是應該是無論如何。所以你得到一個縮放,但像面板的角落附加到滾動窗格的角落。在原文中,行爲是正確的/之後/你放大得足夠遠。 – AndyMac

+0

是的,你的Point是JViewPort上的某個地方,但是你必須用Scrollable increnent/decrement(以像素爲單位)來計算,然後你能夠滾動到這個區域,並且不確定這個代碼是否將你的點集中在Visible JViewPort中,因爲scroolToVisibleRectangle移動指向左上角 – mKorbel

+0

更新了原始帖子,附有說明意見。我認爲問題是scrollpane中的可視矩形的概念,其中包含比矩形小的容器,但我仍不確定該問題的「良好」解決方案是什麼。 – AndyMac