Как работает paintComponent?

это может быть очень noob вопрос. Я только начинаю изучать Java

Я не понимаю работу метода paintComponent. Я знаю, что если я хочу что-то нарисовать, я должен переопределить метод paintComponent.

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

но когда это называется? Я никогда не видел ничего похожего на "объект".paintComponent (g)", но все же он рисуется при запуске программы.

и что такое графический параметр? Откуда она? Параметр должен быть указан, когда вызывается метод. Но, как я уже говорил ранее, похоже, что этот метод никогда не вызывается явно. Итак, кто предоставляет этот параметр? И почему мы должны бросить его в Graphics2D?

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

4 ответов


(очень) короткий ответ на ваш вопрос заключается в том, что paintComponent называется "когда это нужно."Иногда легче думать о системе Java Swing GUI как о "черном ящике", где большая часть внутренних органов обрабатывается без слишком большой видимости.

существует ряд факторов, которые определяют, когда компонент должен быть перекрашен, начиная от перемещения, изменения размера, изменения фокуса, скрытия другими кадрами и т. д. Многие из этих событий обнаружены авто-магически, и paintComponent называется внутренне, когда определено, что эта операция необходима.

Я работал с Swing в течение многих лет, и я не думаю, что я когда-нибудь под названием paintComponent непосредственно, или даже видели его с чем-то еще. Ближайший я пришел с помощью repaint() методы программного запуска перекраски определенных компонентов (которые, как я предполагаю, вызывают правильные paintComponent методы вниз по течению.

в моем опыт, paintComponent редко напрямую переопределяется. Я признаю, что есть пользовательские задачи рендеринга, которые требуют такой детализации, но Java Swing предлагает (довольно) надежный набор JComponents и макетов, которые можно использовать для выполнения большей части тяжелой работы без необходимости прямого переопределения paintComponent. Я думаю, что моя точка зрения здесь заключается в том, чтобы убедиться, что вы не можете сделать что-то с родными JComponents и макетами, прежде чем пытаться свернуть свои собственные настраиваемые компоненты.


две вещи, которые вы можете сделать здесь:

  1. читать живопись в AWT и Swing
  2. используйте отладчик и поместите точку останова в метод paintComponent. Затем пройдите вверх по stacktrace и посмотрите, как предоставляет графический параметр.

просто для информации, вот stacktrace, который я получил из примера кода, который я опубликовал в конце:

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.access0(RepaintManager) line: 59  
    RepaintManager$ProcessingRunnable.run() line: 1621  
    InvocationEvent.dispatch() line: 251    
    EventQueue.dispatchEventImpl(AWTEvent, Object) line: 705    
    EventQueue.access0(EventQueue, AWTEvent, Object) line: 101   
    EventQueue.run() line: 666    
    EventQueue.run() line: 664    
    AccessController.doPrivileged(PrivilegedAction<T>, AccessControlContext) line: not available [native method]    
    ProtectionDomain.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  

Параметр графики приходит от здесь:

RepaintManager.paintDirtyRegions(Map) line: 781 

задействованный фрагмент выглядит следующим образом:

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();
                    }
                }

если вы посмотрите на него, вы увидите, что он извлекает графику из самого JComponent (косвенно с javax.swing.JComponent.safelyGetGraphics(Component, Component)), который сам берет его в конечном итоге от своего первого "тяжеловеса-родителя" (обрезанного до границ компонента), который он сам берет его из соответствующего собственного ресурса.

относительно того, что вы должны бросить Graphics до Graphics2D, это просто происходит что при работе с window Toolkit,Graphics на самом деле выходит Graphics2D, но вы могли бы использовать другие Graphics которые "не должны" расширяются Graphics2D (это происходит не очень часто, но AWT/Swing позволяет вам это делать).

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);
    }
}

внутренние части системы GUI вызывают этот метод, и они проходят в Graphics параметр как графический контекст, на который можно рисовать.


вызов object.paintComponent(g) ошибка.

вместо этого этот метод вызывается автоматически при создании панели. The paintComponent() метод также может быть вызван явно с помощью repaint() метод, определенный в Component класса.

эффект вызова repaint() Это Swing автоматически очищает графику на панели и выполняет paintComponent метод перерисовки графики на этой панели.