78

これは非常に初心者の質問かもしれません。Javaを学び始めたばかりです

paintComponentメソッドの操作がわかりません。何かを描きたい場合は、paintComponentメソッドをオーバーライドする必要があります。

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

しかし、それはいつ呼ばれますか?「object.paintComponent(g)」のようなものは表示されませんが、プログラムの実行中に描画されます。

そして、グラフィックスパラメータとは何ですか?これ、どこから来たの?メソッドを呼び出すときにパラメーターを指定する必要があります。しかし、前に言ったように、このメソッドが明示的に呼び出されることはないようです。では、誰がこのパラメータを提供するのでしょうか?そして、なぜそれをGraphics2Dにキャストする必要があるのでしょうか。

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

5 に答える 5

51

あなたの質問に対する(非常に)短い答えは、paintComponent「必要なとき」と呼ばれるものです。Java Swing GUIシステムを「ブラックボックス」と考える方が簡単な場合があります。このブラックボックスでは、内部の多くがあまり目立たずに処理されます。

コンポーネントをいつ再ペイントする必要があるかを決定する要因は、移動、サイズ変更、フォーカスの変更、他のフレームによる非表示など、さまざまです。これらのイベントの多くは自動的に検出されpaintComponent、その操作が必要であると判断されたときに内部的に呼び出されます。

私はSwingと長年一緒に仕事をしてきましたが、直接電話をかけたことはなくpaintComponent、他の何かから直接電話をかけたこともありません。私が最も近いのは、repaint()メソッドを使用して、特定のコンポーネントの再描画をプログラムでトリガーすることです(これは、paintComponentダウンストリームで正しいメソッドを呼び出すと想定しています。

私の経験では、paintComponentが直接オーバーライドされることはめったにありません。このような粒度を必要とするカスタムレンダリングタスクがあることは認めますが、Java Swingは、直接オーバーライドすることなく、手間のかかる作業の多くを実行するために使用できる(かなり)堅牢なJComponentとレイアウトのセットを提供しますpaintComponent。ここでの私のポイントは、独自のカスタムレンダリングされたコンポーネントをロールする前に、ネイティブのJComponentsとLayoutsで何かを実行できないことを確認することだと思います。

于 2013-03-21T10:45:35.680 に答える
16

ここでできる2つのこと:

  1. AWTとSwingでPaintingを読む
  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 

関連するスニペットは次のとおりです。

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))グラフィックを取得し、JComponent自体が最終的に最初の「Heavyweightparent」(コンポーネントの境界にクリップされている)からグラフィックを取得し、JComponent自体からグラフィックを取得していることがわかります。対応するネイティブリソース。

Graphicsにキャストする必要があるという事実に関してはGraphics2D、Window Toolkitを使用する場合、Graphics実際には拡張されますが、拡張する必要のないGraphics2D他のものを使用することもできます(あまり頻繁には発生しませんが、AWT / Swingを使用すると、それを実行できます)。GraphicsGraphics2D

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);
    }
}
于 2013-03-21T10:41:51.690 に答える
3

GUIシステムの内部はそのメソッドを呼び出し、それらGraphicsは描画可能なグラフィックスコンテキストとしてパラメータを渡します。

于 2013-03-21T10:11:54.473 に答える
2

呼び出しobject.paintComponent(g)はエラーです。

代わりに、このメソッドはパネルの作成時に自動的に呼び出されます。このメソッドは、クラスで定義さpaintComponent()れたメソッドによって明示的に呼び出すこともできます。repaint()Component

呼び出しの効果repaint()は、Swingがパネル上のグラフィックを自動的にクリアし、paintComponentこのパネル上のグラフィックを再描画するメソッドを実行することです。

于 2014-10-23T00:17:32.900 に答える
0

void paintComponent(Graphics g){}以前の図面をコンポーネント上で永続的にしたい場合は、メソッドを再定義する必要があるかもしれません。これを行うには、のように昇順クラスのメソッドを明示的に呼び出す必要がありますsuper.painComponent();。このように、Javaが変更を保持しているpaintComponentメソッドを使用する必要があるときはいつでも。

これは、そうしないと、スーパークラスが独自のメソッドを呼び出すだけで、変更を完全に無視して、実行したすべてのことを元に戻すという事実によって説明されます。

于 2021-03-26T17:36:28.533 に答える