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


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

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

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

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

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

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

4 ответа:

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

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

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

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

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

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

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

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

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

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