2013-03-17 22 views
4

我在JScrollpane中有一個JPanel。 我在BufferedImage上繪圖,我在JPanel上顯示。 在JScrollpane的左上角,我想要一張圖片,當我向下滾動查看我的JPanel的其餘部分時,圖片始終停留在該角落。 這裏到JPanel的paintComponent方法:我想要一張圖片在滾動時留在jscrollpane的左上角

@Override 
public void paintComponent(Graphics g){ 
    super.paintComponent(g); 
    if (bufferedImage != null){ 
     g.drawImage(bufferedImage, 0, 0, this); 
     Point p = parent.getViewPosition(); 
     System.out.println("paintComponent(): "+ p.x + "," + p.y); 
     g.setColor(Color.RED); 
     g.fillRect(p.x + 20, p.y + 20, 200, 200); 
    } 
} 

凡parent.getViewPosition()給我使用scrollPane.getViewport()在getViewPosition()。 當我啓動時,我可以在左上角看到帶有紅色矩形的緩衝圖像。 當我向下滾動時,我可以看到緩衝圖像的其餘部分,但紅色矩形向上移動,然後失敗並在我向上滾動時再次出現。 在控制檯中,我可以看到點P的變化,當我滾動:

paintComponent(): 0,0 
paintComponent(): 0,10 
paintComponent(): 0,20 
paintComponent(): 0,30 
paintComponent(): 0,40 
paintComponent(): 0,50 

誰能幫我解決這個問題?

+0

[例如(http://stackoverflow.com/q/8197261/714968),使用'塗料()',使用'JViewPort.setScrollMode(JViewport.Xxx)',使用自己的'RepaintManager' ,但我會使用'GlassPane'或'JLayer' – mKorbel 2013-03-18 07:37:32

回答

4

您可以爲此使用玻璃窗格,並告訴它在取決於視口位置的位置繪製圖像。例如:

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.image.BufferedImage; 

import javax.swing.*; 

@SuppressWarnings("serial") 
public class ScrollImgGlass extends JPanel { 
    private static final int BI_W = 40; 
    private static final int BI_H = BI_W; 
    private static final String[] DATA = { "One", "Two", "Three", "Four", 
     "Five", "Six", "Seven", "Eight", "Nine", "Zero", "One", "Two", 
     "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Zero", 
     "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", 
     "Nine", "Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", 
     "Eight", "Nine", "Zero" }; 
    private BufferedImage img = null; 
    private JViewport viewport; 

    public ScrollImgGlass(JViewport viewport) { 
     setOpaque(false); 
     this.viewport = viewport; 
     img = new BufferedImage(BI_W, BI_H, BufferedImage.TYPE_INT_ARGB); 
     Graphics2D g2 = img.createGraphics(); 
     g2.setColor(Color.red); 
     g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 
      RenderingHints.VALUE_ANTIALIAS_ON); 
     g2.fillOval(0, 0, BI_W, BI_H); 
     g2.dispose(); 
    } 

    @Override 
    protected void paintComponent(Graphics g) { 
     Point vpLocation = viewport.getLocationOnScreen(); 
     Point gpLocation = getLocationOnScreen(); 

     int x = vpLocation.x - gpLocation.x; 
     int y = vpLocation.y - gpLocation.y; 

     super.paintComponent(g); 
     if (img != null) { 
     g.drawImage(img, x, y, this); 
     } 
    } 

    private static void createAndShowGui() { 
     JList<String> jList = new JList<String>(DATA); 
     jList.setOpaque(false); 

     JViewport viewport = new JViewport(); 
     JScrollPane scrollpane = new JScrollPane(); 
     scrollpane.setViewport(viewport); 
     viewport.setView(jList); 

     ScrollImgGlass glass = new ScrollImgGlass(viewport); 

     JFrame frame = new JFrame("ScrollImg"); 
     frame.setGlassPane(glass); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.getContentPane().add(scrollpane, BorderLayout.CENTER); 

     // just to show that this works if the viewport is shifted over 
     frame.getContentPane().add(Box.createRigidArea(new Dimension(20, 20)), BorderLayout.NORTH); 
     frame.getContentPane().add(Box.createRigidArea(new Dimension(20, 20)), BorderLayout.WEST); 

     frame.pack(); 
     frame.setLocationByPlatform(true); 
     frame.setVisible(true); 

     glass.setVisible(true); 
    } 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 
     public void run() { 
      createAndShowGui(); 
     } 
     }); 
    } 
} 

這將顯示一個類似:

enter image description here

+1

我只想說,我喜歡'JViewport'因爲Blit處理...痛苦... +1 - 另外'JLayer'可能工作 – MadProgrammer 2013-03-18 00:10:31

+0

@MadProgrammer:出於某種原因,我認爲視口在視圖上方是z-ordered *,但顯然我錯了。感謝您更早地糾正我。 – 2013-03-18 00:11:47

+1

我一直在重寫視圖的'paint'方法,但由於scrollpane將視圖「blits」到視圖的方式,通常不會調用paint,除非視口的大小發生變化。 。或類似的東西:P你的方法更好 – MadProgrammer 2013-03-18 00:15:37

1

不要將圖片放在滾動的面板中。將它放在不同的面板中,並使用佈局管理器排列這兩個面板。

我建議看看BorderLayout;它有n,s,e和w區域,中間有一個區域,但你不必全部使用它們(很少使用它們全部)。您可以創建一個JPanel,將其佈局管理器設置爲BorderLayout,將包含圖像的面板放在NORTH的部分,然後將滾動面板放在CENTER中。作爲免費的獎勵,當窗口調整大小時,如果窗口調整大小,則中心的JPanel將在兩個維度上都拉伸,因爲這是BorderLayout的工作方式。

1

某處在你的代碼中創建一個JScrollPane。

變化

final JScrollPane scrollpane = new JScrollPane(); 

要:

final JScrollPane scrollpane = new JScrollPane() { 
     @Override 
     public void paint(final Graphics g) { 
      super.paint(g); 
      // Put you drawing here...example, draw a geen dot... 
      g.setColor(Color.GREEN); 
      g.fillOval(0, 0, 30, 30); 
     } 
    }; 

編輯:每評論,需要做的放置在JScrollPane的對象上的setOpaque(假)。

實施例:

list.setOpaque(false); 
    scrollpane.setViewportView(list); 
+0

-1,好想法,但它並不像MadProgrammer在一個小時前注意到的那樣工作。 – camickr 2013-03-18 02:29:45

+0

@camickr - 你測試了嗎?在我的測試中,它工作正常。 MadP講述了重寫JViewport繪畫,而我重寫了JScrollPane繪畫。 – Java42 2013-03-18 02:34:33

+0

是的,我使用JDK7在Windows 7上進行了測試。但是,我確實在我的第二個建議中找到了解決方法。發佈您用來測試它的代碼。 – camickr 2013-03-18 02:38:56

4

如所建議的通過MadProgrammer,一個JLayer不工作:

import java.awt.*; 
import javax.swing.*; 
import javax.swing.plaf.*; 

public class FixedImageLayerUI extends LayerUI<JComponent> 
{ 
    @Override 
    public void paint(Graphics g, JComponent c) 
    { 
     super.paint(g, c); 

     Graphics2D g2 = (Graphics2D) g.create(); 

     g2.setColor(Color.RED); 
     g2.fillOval(0, 0, 10, 10); 

     g2.dispose(); 
    } 

    private static void createAndShowUI() 
    { 
     String[] data = 
     { 
      "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", 
      "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", 
      "u", "v", "w", "x", "y", "z" 
     }; 

     JList<String> list = new JList<String>(data); 
     JScrollPane scrollPane = new JScrollPane(list); 

     LayerUI<JComponent> layerUI = new FixedImageLayerUI(); 
     JLayer<JComponent> layer = new JLayer<JComponent>(scrollPane, layerUI); 

     JFrame frame = new JFrame("FixedImage"); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.add(layer); 
     frame.pack(); 
     frame.setLocationByPlatform(true); 
     frame.setVisible(true); 
    } 

    public static void main(String[] args) 
    { 
     EventQueue.invokeLater(new Runnable() 
     { 
      public void run() 
      { 
       createAndShowUI(); 
      } 
     }); 
    } 
} 

而且,如由MadProgrammer注意到,覆蓋JScrollPane的的塗料方法不起作用。但是,如果你做的JList非不透明,它的工作:

import java.awt.*; 
import javax.swing.*; 
import javax.swing.plaf.*; 

public class FixedImageScrollPane 
{ 

    private static void createAndShowUI() 
    { 
     String[] data = 
     { 
      "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", 
      "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", 
      "u", "v", "w", "x", "y", "z" 
     }; 

     JList<String> list = new JList<String>(data); 
     list.setOpaque(false); 

     JScrollPane scrollPane = new JScrollPane(list) 
     { 
      @Override 
      public void paint(Graphics g) 
      { 
       super.paint(g); 
       g.setColor(Color.RED); 
       g.fillOval(0, 0, 10, 10); 
      } 
     }; 

     JFrame frame = new JFrame("FixedImage"); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.add(scrollPane); 
     frame.pack(); 
     frame.setLocationByPlatform(true); 
     frame.setVisible(true); 
    } 

    public static void main(String[] args) 
    { 
     EventQueue.invokeLater(new Runnable() 
     { 
      public void run() 
      { 
       createAndShowUI(); 
      } 
     }); 
    } 
} 
0

OK,下面的代碼工作與JTabbedPane的。 我必須在選項卡窗格的面板中添加一個componentListener,因爲當窗格不在屏幕上時,getLocationOnScreen()方法會得到一個異常。

public class GlassFrame { 
    private JPanel panel; 
    private JScrollPane scrollPane; 
    private BufferesImage img; 

    public GlassFrame() { 
     panel = new JPanel(){ 
      @Override 
      public void paintComponent(Graphics g){ 
       super.paintComponent(g); 
       img = new BufferedImage(500, 500, BufferedImage.TYPE_INT_ARGB); 
       Graphics2D g2 = img.createGraphics(); 
       g2.setPaint(Color.WHITE); 
        Rectangle2D rect = new Rectangle2D.Float(0, 0, 420, 420); 
        g2.fill(rect); 
        g2.setPaint(Color.BLACK); 
        for (int i = 0; i <= 10; i++) { 
         g2.draw(new Line2D.Float(10 + i * 40,10,10 + i * 40,410)); 
         g2.draw(new Line2D.Float(10,10 + i * 40,410,10 + i * 40)); 
        } 
       g2.dispose(); 
       g.drawImage(img, 0, 0, this); 
      } 
     }; 
     panel.setPreferredSize(new Dimension(420, 420)); 
     panel.setOpaque(false); 

     scrollPane = new JScrollPane(panel, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, 
       ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS); 
     scrollPane.getVerticalScrollBar().setUnitIncrement(10); 

     JFrame frame = new JFrame("ScrollPane and GlassPane"); 
     final GlassPane glass = new GlassPane(scrollPane.getViewport()); 
     frame.setGlassPane(glass); 

     JTabbedPane tab = new JTabbedPane(); 
     JPanel panelInTab = new JPanel(); 
     panelInTab.setLayout(new BorderLayout()); 
     tab.add("first tab", panelInTab); 
     tab.add("second tab", new JPanel()); 
     panelInTab.add(scrollPane, BorderLayout.CENTER); 
     panelInTab.add(new JButton("testbutton"), BorderLayout.NORTH); 
     panelInTab.addComponentListener(new ComponentAdapter() { 
      @Override 
      public void componentShown(ComponentEvent arg0) { 
       glass.setVisible(true); 
      } 
      @Override 
      public void componentHidden(ComponentEvent arg0) { 
       glass.setVisible(false); 
      } 
     }); 

     frame.getContentPane().add(tab);  
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.setPreferredSize(new Dimension(300, 400)); 
     frame.pack(); 
     frame.setLocation(200, 200); 
     frame.setVisible(true); 
     glass.setVisible(true); 
    } 

    class GlassPane extends JPanel{ 
     private JViewport viewport; 
     private BufferedImage image = null; 

     public GlassPane(JViewport viewport){ 
      setOpaque(false); 
      this.viewport = viewport; 
      image = new BufferedImage(58, 58, BufferedImage.TYPE_INT_ARGB); 
      Graphics2D g2 = image.createGraphics(); 
      g2.setColor(Color.red); 
      g2.setStroke(new BasicStroke(3.0f)); 
      g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 
        RenderingHints.VALUE_ANTIALIAS_ON); 
      g2.drawOval(5, 5, 50, 50); 
      g2.dispose(); 
     } 

     @Override 
     protected void paintComponent(Graphics g) { 
      Point vpLocation = viewport.getLocationOnScreen(); 
      Point gpLocation = getLocationOnScreen(); 

      int x = vpLocation.x - gpLocation.x; 
      int y = vpLocation.y - gpLocation.y; 

      super.paintComponent(g); 
      if (image != null) { 
       g.drawImage(image, x, y, this); 
      } 
     } 
    } 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 
      public void run() { 
       GlassFrame frame = new GlassFrame(); 
      } 
     }); 
    } 
} 
相關問題