Как работает 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 и макетами, прежде чем пытаться свернуть свои собственные настраиваемые компоненты.
две вещи, которые вы можете сделать здесь:
- читать живопись в AWT и Swing
- используйте отладчик и поместите точку останова в метод 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
метод перерисовки графики на этой панели.