2011-08-11 1 views
4

JScrollPane 위에 빨간색 사각형을 그리려합니다. 아래 코드는 괜찮습니다.하지만 뷰포트를 너무 빠르게 스크롤하면 빨간색 사각형이 위아래로 움직입니다. JScrollPane의 자체가 고정되어 있기 때문에 JScrollPane의 뷰포트에 정적 이미지 그리기

enter image description here

날 홀수 강타, 그래서 스윙이 그 안에 그려진 구성 요소 주위에 이동하려고하지 않을 생각했습니다. 실제로 일어나는 현상은 빨간색 사각형이 이동하는 그래픽을 표시하는 뷰포트와 연결된다는 것입니다.

어쨌든 붉은 색 사각형이 점프하여 목록 위에 빨간색 사각형이 성공적으로 그려지지 않도록하려면 어떻게합니까? 어쩌면 내가 잘못된 접근 방식을 취하고있는 것일 수도 있습니다.

package components; 

import java.awt.*; 
import java.util.Vector; 

import javax.swing.*; 
import javax.swing.event.*; 

@SuppressWarnings("serial") 
public class DialogWithScrollPane extends JFrame { 

    public DialogWithScrollPane() { 
    super(); 

    setResizable(false); 
    Container pane = getContentPane(); 

    Vector<Object> listOfStuff = new Vector<Object>(); 
    for (int i = 0; i < 100; i++) { 
     listOfStuff.add(Integer.toString(i)); 
    } 

    final JScrollPane scrollPane = new JScrollPane() { 

     public void paint(Graphics g) { 
     System.out.println("JScrollPane.paint() called."); 
     super.paint(g); 

     g.setColor(Color.red); 
     g.fillRect(20, 50, 100, 200); 
     } 
    }; 
    JList list = new JList(listOfStuff) { 
     public void paint(Graphics g) { 
     System.out.println("JList.paint() called."); 
     super.paint(g); 

     // Well, I could do this... 
      // 
     // scrollPane.repaint(); 
     // 
     // ...and it would solve the problem, but it would also result in an 
     // infinite recursion since JScrollPane.paint() would call this 
     // function again. 
     } 
    }; 

    // Repaint the JScrollPane any time the viewport is moved or an item in the 
    // list is selected. 
    scrollPane.getViewport().addChangeListener(new ChangeListener() { 
     public void stateChanged(ChangeEvent e) { 
     scrollPane.repaint(); 
     } 
    }); 
    list.addListSelectionListener(new ListSelectionListener() { 
     public void valueChanged(ListSelectionEvent e) { 
     scrollPane.repaint(); 
     } 
    }); 

    scrollPane.setViewportView(list); 

    pane.add(scrollPane); 
    setMinimumSize(new Dimension(300, 300)); 
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    setLocation(500, 250); 
    setVisible(true); 
    } 

    public static void main(String[] args) { 
    javax.swing.SwingUtilities.invokeLater(new Runnable() { 
     public void run() { 
     new DialogWithScrollPane(); 
     } 
    }); 
    } 
} 
+2

이 솔루션이 너무 강력 될 수도 있지만 당신은'유리 Pane'에 그리기 시도 할 수 있습니다. 예를 들어 - http://stackoverflow.com/questions/6609888/drawing-between-2-images-in-1-jpanel/6610064#6610064하지만 잘못 될 수 있으며이 솔루션은 적용되지 않을 수 있습니다. – mre

+0

@ masson : 내 대답에 편집을 참조하십시오. –

답변

6

가 JScrollPane는 뒤에 그림해야 뒤에 목록을 칠해야하는 JViewport. 필자는 paintComponent가 아닌 paintComponent를 오버라이드하고 JScrollPane에 대해 repaint를 항상 호출하므로 컴포넌트가 페인트 된 후 다시 페인트되도록하기 때문에 이것이 작동하는 것으로 생각합니다.

아마도 JLayeredPane을 사용하고 JScrollPane을 잡고 그 위에 페인트하려고 할 것입니다.

편집 : 또는 내가 지금 볼 수있는 유리판,하지만 당신이 그렇게하고 glasspane을 볼 수있게 설정할 것을 두려워하면, 기본 scrollpane과 상호 작용하는 능력을 잃을 것입니다. 예를 들어

편집 2
,

import java.awt.*; 
import java.awt.event.ComponentAdapter; 
import java.awt.event.ComponentEvent; 
import java.util.Vector; 
import javax.swing.*; 

@SuppressWarnings("serial") 
public class DialogWithScrollPane2 extends JFrame { 

    public DialogWithScrollPane2() { 
     super(); 

     //setResizable(false); 
     final JPanel pane = (JPanel) getContentPane(); 

     Vector<Object> listOfStuff = new Vector<Object>(); 
     for (int i = 0; i < 100; i++) { 
     listOfStuff.add(Integer.toString(i)); 
     } 

     final JScrollPane scrollPane = new JScrollPane(); 
     JList list = new JList(listOfStuff); 

     scrollPane.setViewportView(list); 

     final JPanel blueRectPanel = new JPanel() { 
     @Override 
     protected void paintComponent(Graphics g) { 
      super.paintComponent(g); 
      g.setColor(Color.blue); 
      g.fillRect(20, 50, 100, 200); 
     } 
     }; 
     blueRectPanel.setOpaque(false); 

     final JLayeredPane layeredPane = new JLayeredPane(); 
     layeredPane.add(scrollPane, JLayeredPane.DEFAULT_LAYER); 
     layeredPane.add(blueRectPanel, JLayeredPane.PALETTE_LAYER); 

     layeredPane.addComponentListener(new ComponentAdapter() { 

     private void resizeLayers() { 
      final JViewport viewport = scrollPane.getViewport(); 
      scrollPane.setBounds(layeredPane.getBounds()); 
      blueRectPanel.setBounds(viewport.getBounds()); 
      SwingUtilities.invokeLater(new Runnable() { 
       public void run() { 
        blueRectPanel.setBounds(viewport.getBounds()); 
       } 
      }); 
     } 

     @Override 
     public void componentShown(ComponentEvent e) { 
      resizeLayers(); 
     } 

     @Override 
     public void componentResized(ComponentEvent e) { 
      resizeLayers(); 
     } 
     }); 

     pane.add(layeredPane); 
     setPreferredSize(new Dimension(300, 300)); 
     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     pack(); 
     setLocation(500, 250); 
     setVisible(true); 
    } 

    public static void main(String[] args) { 
     javax.swing.SwingUtilities.invokeLater(new Runnable() { 
     public void run() { 
      new DialogWithScrollPane2(); 
     } 
     }); 
    } 
} 
+1

편집 내용이 확실하지 않습니다. 이 예에서 모든 입력 이벤트를 의도적으로 차단하고 '유리창'이 차단하지만, 기본적으로 완전히 차단되는지는 확실하지 않습니다. 따라서 기본 Scollpane과 상호 작용할 수있는 기능은 여전히있을 수 있지만 아직 테스트하지 않았습니다! : D – mre

+0

테스트 가치가 있습니다. : D –

+1

@masson JViewPort에서 무엇이든 페인팅에 관한 관련 게시물을 참조하십시오. http://stackoverflow.com/questions/7006522/how-to-add-background-image-in-jtable-when-printing/7006684#7006684 및 링크를 참조하십시오. trashgod +1 – mKorbel