1

paint(Graphics)のメソッド内にコンポーネントをペイントしようとしていますJPanel。次のコードスニペットは問題なく機能しますJButton。aは私の中でうまく描かれていますJPanel

        @Override
        public void paint(Graphics g) {
            super.paint(g);
            JButton btn = new JButton("hello");
            Dimension dim = btn.getPreferredSize();
            btn.setSize(dim.width, dim.height);
            btn.paint(g);   // paint the button
        }

コードスニペットは、を除く他のコンポーネント(、、 ...)でも完全に機能JLabelJTreeますJPanel。次のコードは非常に奇妙なものになりNullPointerException at java.awt.Window.access$700(Window.java:132)ます。

        @Override
        public void paint(Graphics g) {
            super.paint(g);
            JPanel panel = new JPanel();
            panel.setSize(10, 10);
            panel.paint(g);   // paint the panel
        }

ここに完全なスタックトレースがあります:

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
    at java.awt.Window.access$700(Window.java:132)
    at java.awt.Window$1.isOpaque(Window.java:3458)
    at javax.swing.RepaintManager.getVolatileOffscreenBuffer(RepaintManager.java:983)
    at javax.swing.RepaintManager$PaintManager.paint(RepaintManager.java:1395)
    at javax.swing.BufferStrategyPaintManager.paint(BufferStrategyPaintManager.java:294)
    at javax.swing.RepaintManager.paint(RepaintManager.java:1224)
    at javax.swing.JComponent.paint(JComponent.java:1015)
    at test.paintcontainer.TestPaintContainerMain$TestContentPane.paint(TestPaintContainerMain.java:48)
    at javax.swing.JComponent.paintChildren(JComponent.java:862)
    at javax.swing.JComponent.paint(JComponent.java:1038)
    at javax.swing.JLayeredPane.paint(JLayeredPane.java:567)
    at javax.swing.JComponent.paintChildren(JComponent.java:862)
    at javax.swing.JComponent.paintToOffscreen(JComponent.java:5131)
    at javax.swing.BufferStrategyPaintManager.paint(BufferStrategyPaintManager.java:278)
    at javax.swing.RepaintManager.paint(RepaintManager.java:1224)
    at javax.swing.JComponent.paint(JComponent.java:1015)
    at java.awt.GraphicsCallback$PaintCallback.run(GraphicsCallback.java:21)
    at sun.awt.SunGraphicsCallback.runOneComponent(SunGraphicsCallback.java:60)
    at sun.awt.SunGraphicsCallback.runComponents(SunGraphicsCallback.java:97)
    at java.awt.Container.paint(Container.java:1780)
    at java.awt.Window.paint(Window.java:3375)
    at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:796)
    at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:713)
    at javax.swing.RepaintManager.seqPaintDirtyRegions(RepaintManager.java:693)
    at javax.swing.SystemEventQueueUtilities$ComponentWorkRequest.run(SystemEventQueueUtilities.java:125)
    at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209)
    at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:641)
    at java.awt.EventQueue.access$000(EventQueue.java:84)
    at java.awt.EventQueue$1.run(EventQueue.java:602)
    at java.awt.EventQueue$1.run(EventQueue.java:600)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:87)
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:611)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)

この問題を解決する方法はありますか?メソッドJPanel内でペイントする必要があります。paint(Graphics)前述の例外を再現するためにコピー&ペーストできる簡単なテストアプリケーションを作成しました。

package test.paintcontainer;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JRadioButton;

public class TestPaintContainerMain extends JFrame {

    public static void main(String[] args) {
        TestPaintContainerMain test = new TestPaintContainerMain();
        test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        test.setBounds(0, 0, 300, 200);
        test.setContentPane(new TestContentPane());
        test.setVisible(true);
    }

    static class TestContentPane extends JPanel {

        JRadioButton paintButtonCheck;

        JRadioButton paintPanelCheck;

        public TestContentPane() {
            paintButtonCheck = createRadioButton("paint button", true);
            paintPanelCheck = createRadioButton("paint panel", false);
            ButtonGroup buttonGroup = new ButtonGroup();
            buttonGroup.add(paintButtonCheck);
            buttonGroup.add(paintPanelCheck);
            add(paintButtonCheck);
            add(paintPanelCheck);
        }

        @Override
        public void paint(Graphics g) {
            super.paint(g);

            g.translate(100, 100);
            if (paintButtonCheck.isSelected()) {
                createButton().paint(g);
            } else {
                createPanel().paint(g);
            }
        }

        private JButton createButton() {
            JButton button = new JButton("button");
            button.setSize(button.getPreferredSize().width, button.getPreferredSize().height);
            return button;
        }

        private JPanel createPanel() {
            JPanel panel = new JPanel();
            panel.setBackground(Color.GREEN);
            panel.add(createButton());
            panel.setSize(panel.getPreferredSize().width, panel.getPreferredSize().height);
            return panel;
        }

        private JRadioButton createRadioButton(String title, boolean selected) {
            JRadioButton radio = new JRadioButton(title, selected);
            radio.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    TestContentPane.this.repaint();
                }
            });
            return radio;
        }
    }

}
4

2 に答える 2

2

これはSwingのバグではない可能性が高いですが、まだ実現されていないコンポーネントをペイントしようとしているため、より多くの問題が発生します。つまり、アクティブなグラフィックコンテキストがありません。JFrameのようなすでに実現されているコンポーネントにコンポーネントを追加することでコンポーネントを実現できます。これ自体はによって実現されsetVisible(true)ます。

また、これはSwing(より正確にはイベントディスパッチャスレッド)の仕事であるため、手動で呼び出すことはおそらく絶対にしないでください。メソッドJComponent.paint(Graphics)のドキュメントでもそう述べています。paint

アプリケーションはpaintを直接呼び出すべきではなく、代わりにrepaintメソッドを使用してコンポーネントの再描画をスケジュールする必要があります。

呼び出すことができるのはprintAll(Graphics g)、コンポーネントとそのすべてのサブコンポーネントをペイントするメソッドです。また、Swingでは、オーバーライドする必要はありませんpaintが、paintComponent

だからここにテストコードがあります:

    JButton button = createButton();
    JPanel panel = createPanel();

    public TestContentPane() {
        paintButtonCheck = createRadioButton("paint button", true);
        paintPanelCheck = createRadioButton("paint panel", false);
        ButtonGroup buttonGroup = new ButtonGroup();
        buttonGroup.add(paintButtonCheck);
        buttonGroup.add(paintPanelCheck);
        add(paintButtonCheck);
        add(paintPanelCheck);

        //Hack, just prove something (realize both components)
        add(panel);
        add(button);
    }

    ...

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);

        g.translate(100, 100);
        if (paintButtonCheck.isSelected()) {
            button.paintAll(g);
        } else {
            panel.paintAll(g);
        }
        g.translate(-100, -100);
    }

これは機能するはずです(ただし、画面上に不要なコンポーネントが2つあることは明らかです)。グラフィックオブジェクトは後でSwingによって引き続き使用されるため、グラフィックオブジェクトを「リセット」することにも注意してください。


これは理論ですが、まだ実際の解決策ではありません。

あなたの問題に対する私の解決策は、「このようにしないでください」です!

コンポーネントは、どこでも同じように見えないという意味で、画像のようなものではありません呼び出しの出力はpaintAll、コンポーネントがどのように(またはどこで)実現されたかによって異なります。

したがって、1つの提案は、実際のコンポーネントを表示することです。ツールチップボックスを作成し、パネルとボタンを追加して、それらに描画させます。これらのコンポーネントをサブクラス化し、それらのpaintComponent()メソッドをオーバーライドしたり、透明性を追加したりすることもできます。多少の作業が必要になりますが、Swingが簡単であるとは知られていませんでした。

于 2012-04-13T11:32:36.910 に答える
1

解決策を見つけました。私の質問からのサンプルコードの唯一の変更は、panel.setDoubleBuffered(false)JPanelがペイントしようとしていたことです。

ただし、それでも例外はSwingのバグであると考えています。設計上ダブルバッファリングをオフにする必要がある場合は、発生しないはずですNullPointerExceptionが、条件を説明する他のより意味のある例外が発生します。

固定サンプルアプリケーションは次のとおりです。

package test.paintcontainer;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JRadioButton;

public class TestPaintContainerMain extends JFrame {

    public static void main(String[] args) {
        TestPaintContainerMain test = new TestPaintContainerMain();
        test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        test.setBounds(0, 0, 300, 200);
        test.setContentPane(new TestContentPane());
        test.setVisible(true);
    }

    static class TestContentPane extends JPanel {

        JRadioButton paintButtonCheck;

        JRadioButton paintPanelCheck;

        public TestContentPane() {
            paintButtonCheck = createRadioButton("paint button", false);
            paintPanelCheck = createRadioButton("paint panel", true);
            ButtonGroup buttonGroup = new ButtonGroup();
            buttonGroup.add(paintButtonCheck);
            buttonGroup.add(paintPanelCheck);
            add(paintButtonCheck);
            add(paintPanelCheck);
        }

        @Override
        public void paint(Graphics g) {
            super.paint(g);

            g.translate(100, 100);
            if (paintButtonCheck.isSelected()) {
                createButton().paint(g);
            } else {
                createPanel().paint(g);
            }
        }

        private JButton createButton() {
            JButton button = new JButton("button");
            button.setSize(button.getPreferredSize().width, button.getPreferredSize().height);
            return button;
        }

        private JPanel createPanel() {
            JPanel panel = new JPanel();
            panel.setBackground(Color.GREEN);
            panel.add(createButton());
            // --------------------------------
            panel.setDoubleBuffered(false);  // <-- TURN OFF DOUBLE BUFFERING
            // --------------------------------
            panel.setSize(panel.getPreferredSize().width, panel.getPreferredSize().height);
            return panel;
        }

        private JRadioButton createRadioButton(String title, boolean selected) {
            JRadioButton radio = new JRadioButton(title, selected);
            radio.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    TestContentPane.this.repaint();
                }
            });
            return radio;
        }
    }

}
于 2012-04-13T10:33:57.370 に答える