developer tip

paintComponent는 어떻게 작동합니까?

copycodes 2020. 12. 9. 08:24
반응형

paintComponent는 어떻게 작동합니까?


이것은 매우 멍청한 질문 일 수 있습니다. Java를 배우기 시작했습니다.

paintComponent 메소드의 작동을 이해하지 못합니다. 무언가를 그리려면 paintComponent 메서드를 재정의해야합니다.

public void paintComponent(Graphics g)
{
   ...
}

그러나 언제 호출됩니까? 나는 "object.paintComponent (g)"와 같은 것을 본 적이 없지만 여전히 프로그램이 실행될 때 그려집니다.

그리고 그래픽 매개 변수는 무엇입니까? 그것이 어디에서 온 것인가? 메소드가 호출 될 때 매개 변수를 제공해야합니다. 그러나 앞서 말했듯이이 메서드는 명시 적으로 호출되지 않는 것 같습니다. 그렇다면 누가이 매개 변수를 제공합니까? 그리고 왜 그것을 Graphics2D로 캐스트해야합니까?

public void paintComponent(Graphics g)
{
    ...
    Graphics2D g2= (Graphics2D) g;
    ...
}

귀하의 질문에 대한 (매우) 짧은 대답 paintComponent은 "필요할 때"라는 것입니다. 때때로 Java Swing GUI 시스템을 "블랙 박스"로 생각하는 것이 더 쉬울 때가 있습니다.이 시스템에서는 많은 내부가 너무 많은 가시성없이 처리됩니다.

이동, 크기 조정, 초점 변경, 다른 프레임에 의해 숨기기 등 구성 요소를 다시 칠해야하는시기를 결정하는 여러 요소가 있습니다. 이러한 이벤트의 대부분은 자동으로 감지되며 paintComponent해당 작업이 필요하다고 판단되면 내부적으로 호출됩니다.

나는 스윙과 수년 동안 일해 왔고 직접 전화를 걸거나 다른 곳에서 직접 전화 적이 없다고 생각 paintComponent합니다. 가장 가까운 repaint()방법 메서드를 사용하여 특정 구성 요소의 다시 그리기를 프로그래밍 방식으로 트리거하는 것입니다 (올바른 paintComponent메서드를 다운 스트림으로 호출한다고 가정합니다 .

내 경험상 paintComponent거의 직접 재정의되지 않습니다. 이러한 세분성을 요구하는 사용자 정의 렌더링 작업이 있다는 것을 인정하지만 Java Swing은 paintComponent. 내 요점은 사용자 정의 렌더링 구성 요소를 롤링하기 전에 기본 JComponents 및 Layouts로 무언가를 할 수 없는지 확인하는 것입니다.


여기서 수행 할 수있는 두 가지 작업 :

  1. AWT 및 스윙에서 페인팅 읽기
  2. 디버거를 사용하고 paintComponent 메소드에 중단 점을 넣으십시오. 그런 다음 스택 추적으로 이동하여 Graphics 매개 변수를 제공하는 방법을 확인합니다.

정보를 위해 마지막에 게시 한 코드 예제에서 얻은 스택 트레이스가 있습니다.

Thread [AWT-EventQueue-0] (Suspended (breakpoint at line 15 in TestPaint))  
    TestPaint.paintComponent(Graphics) line: 15 
    TestPaint(JComponent).paint(Graphics) line: 1054    
    JPanel(JComponent).paintChildren(Graphics) line: 887    
    JPanel(JComponent).paint(Graphics) line: 1063   
    JLayeredPane(JComponent).paintChildren(Graphics) line: 887  
    JLayeredPane(JComponent).paint(Graphics) line: 1063 
    JLayeredPane.paint(Graphics) line: 585  
    JRootPane(JComponent).paintChildren(Graphics) line: 887 
    JRootPane(JComponent).paintToOffscreen(Graphics, int, int, int, int, int, int) line: 5228   
    RepaintManager$PaintManager.paintDoubleBuffered(JComponent, Image, Graphics, int, int, int, int) line: 1482 
    RepaintManager$PaintManager.paint(JComponent, JComponent, Graphics, int, int, int, int) line: 1413  
    RepaintManager.paint(JComponent, JComponent, Graphics, int, int, int, int) line: 1206   
    JRootPane(JComponent).paint(Graphics) line: 1040    
    GraphicsCallback$PaintCallback.run(Component, Graphics) line: 39    
    GraphicsCallback$PaintCallback(SunGraphicsCallback).runOneComponent(Component, Rectangle, Graphics, Shape, int) line: 78    
    GraphicsCallback$PaintCallback(SunGraphicsCallback).runComponents(Component[], Graphics, int) line: 115 
    JFrame(Container).paint(Graphics) line: 1967    
    JFrame(Window).paint(Graphics) line: 3867   
    RepaintManager.paintDirtyRegions(Map<Component,Rectangle>) line: 781    
    RepaintManager.paintDirtyRegions() line: 728    
    RepaintManager.prePaintDirtyRegions() line: 677 
    RepaintManager.access$700(RepaintManager) line: 59  
    RepaintManager$ProcessingRunnable.run() line: 1621  
    InvocationEvent.dispatch() line: 251    
    EventQueue.dispatchEventImpl(AWTEvent, Object) line: 705    
    EventQueue.access$000(EventQueue, AWTEvent, Object) line: 101   
    EventQueue$3.run() line: 666    
    EventQueue$3.run() line: 664    
    AccessController.doPrivileged(PrivilegedAction<T>, AccessControlContext) line: not available [native method]    
    ProtectionDomain$1.doIntersectionPrivilege(PrivilegedAction<T>, AccessControlContext, AccessControlContext) line: 76    
    EventQueue.dispatchEvent(AWTEvent) line: 675    
    EventDispatchThread.pumpOneEventForFilters(int) line: 211   
    EventDispatchThread.pumpEventsForFilter(int, Conditional, EventFilter) line: 128    
    EventDispatchThread.pumpEventsForHierarchy(int, Conditional, Component) line: 117   
    EventDispatchThread.pumpEvents(int, Conditional) line: 113  
    EventDispatchThread.pumpEvents(Conditional) line: 105   
    EventDispatchThread.run() line: 90  

Graphics 매개 변수는 여기에서 가져옵니다.

RepaintManager.paintDirtyRegions(Map) line: 781 

The snippet involved is the following:

Graphics g = JComponent.safelyGetGraphics(
                        dirtyComponent, dirtyComponent);
                // If the Graphics goes away, it means someone disposed of
                // the window, don't do anything.
                if (g != null) {
                    g.setClip(rect.x, rect.y, rect.width, rect.height);
                    try {
                        dirtyComponent.paint(g); // This will eventually call paintComponent()
                    } finally {
                        g.dispose();
                    }
                }

If you take a look at it, you will see that it retrieve the graphics from the JComponent itself (indirectly with javax.swing.JComponent.safelyGetGraphics(Component, Component)) which itself takes it eventually from its first "Heavyweight parent" (clipped to the component bounds) which it self takes it from its corresponding native resource.

Regarding the fact that you have to cast the Graphics to a Graphics2D, it just happens that when working with the Window Toolkit, the Graphics actually extends Graphics2D, yet you could use other Graphics which do "not have to" extends Graphics2D (it does not happen very often but AWT/Swing allows you to do that).

import java.awt.Color;
import java.awt.Graphics;

import javax.swing.JFrame;
import javax.swing.JPanel;

class TestPaint extends JPanel {

    public TestPaint() {
        setBackground(Color.WHITE);
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.drawOval(0, 0, getWidth(), getHeight());
    }

    public static void main(String[] args) {
        JFrame jFrame = new JFrame();
        jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jFrame.setSize(300, 300);
        jFrame.add(new TestPaint());
        jFrame.setVisible(true);
    }
}

The internals of the GUI system call that method, and they pass in the Graphics parameter as a graphics context onto which you can draw.


Calling object.paintComponent(g) is an error.

Instead this method is called automatically when the panel is created. The paintComponent() method can also be called explicitly by the repaint() method defined in Component class.

The effect of calling repaint() is that Swing automatically clears the graphic on the panel and executes the paintComponent method to redraw the graphics on this panel.

참고URL : https://stackoverflow.com/questions/15544549/how-does-paintcomponent-work

반응형