これは非常に初心者の質問かもしれません。私はJavaを学び始めたばかりです
PaintComponentメソッドの操作がわかりません。何かを描きたい場合は、paintComponentメソッドをオーバーライドする必要があります。
public void paintComponent(Graphics g)
{
...
}
しかし、いつ呼ばれますか? 「object.paintComponent(g)」のようなものは表示されませんが、プログラムの実行中に描画されます。
そして、Graphicsパラメーターとは何ですか?これ、どこから来たの?メソッドの呼び出し時にパラメーターを指定する必要があります。しかし、前述したように、このメソッドは明示的に呼び出されることはないようです。では、誰がこのパラメーターを提供しますか?そして、なぜそれをGraphics2Dにキャストしなければならないのですか?
public void paintComponent(Graphics g)
{
...
Graphics2D g2= (Graphics2D) g;
...
}
あなたの質問に対する(非常に)短い答えは、paintComponent
が「必要なとき」と呼ばれるということです。 Java Swing GUIシステムを「ブラックボックス」と考える方が簡単な場合があります。この場合、内部の多くはあまり見えずに処理されます。
コンポーネントの再描画が必要な時期は、移動、サイズ変更、フォーカスの変更、他のフレームでの非表示など、さまざまな要因によって決まります。これらのイベントの多くは自動的に検出され、その操作が必要であると判断されたときにpaintComponent
が内部的に呼び出されます。
私は長年Swingで働いてきましたが、私はeverpaintComponent
を直接呼び出したとは思いませんし、他の何かから直接呼び出されたとさえ見ていません。最も近いのは、repaint()
メソッドを使用して、特定のコンポーネントの再描画をプログラムでトリガーすることです(これは、下流の正しいpaintComponent
メソッドを呼び出すと想定しています)。
私の経験では、paintComponent
が直接オーバーライドされることはほとんどありません。このような粒度を必要とするカスタムレンダリングタスクがあることは認めますが、Java Swingは、直接オーバーライドすることなく多くの重い作業を行うために使用できる(かなり)堅牢なJComponentsおよびLayoutsのセットを提供しますpaintComponent
。ここでの私のポイントは、独自のカスタムレンダリングコンポーネントをロールアウトしようとする前に、ネイティブのJComponentsとLayoutsで何もできないことを確認することだと思います。
ここでできる2つのこと:
参考までに、最後に投稿したコードの例から得たスタックトレースを以下に示します。
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
関連するスニペットは次のとおりです。
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)
で間接的に)、最終的にそれが最初の「Heavyweight parent」(コンポーネントの境界にクリップ)から取得しますselfは、対応するネイティブリソースから取得します。
Graphics
をGraphics2D
にキャストする必要があるという事実に関しては、Window Toolkitで作業しているときに、Graphics
が実際にGraphics2D
を拡張することが起こります。 「する必要がない」Graphics2D
を拡張する他のGraphics
を使用します(あまり頻繁に発生しませんが、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)
の呼び出しはエラーです。
代わりに、このメソッドはパネルの作成時に自動的に呼び出されます。 paintComponent()
メソッドは、Component
クラスで定義されているrepaint()
メソッドによって明示的に呼び出すこともできます。
repaint()
を呼び出すと、Swingはパネル上のグラフィックを自動的にクリアし、paintComponent
メソッドを実行してこのパネル上のグラフィックを再描画します。