在绘制JPanel时出现java.awt.Window.access $ 700(Window.java:132)处的NullPointerException [英] NullPointerException at java.awt.Window.access$700(Window.java:132) while painting JPanel

查看:50
本文介绍了在绘制JPanel时出现java.awt.Window.access $ 700(Window.java:132)处的NullPointerException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在JPanelpaint(Graphics)方法内绘制组件. 以下代码段可以正常工作,在我的JPanel中很好地绘制了JButton:

I'm trying to paint component inside paint(Graphics) method of JPanel. The following code snippet works just fine, a JButton is painted nicely in my 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
        }

除了JPanel之外,其他代码组件(JLabelJTree,...)也可以完美地使用该代码段. 以下代码将导致非常奇怪的NullPointerException at java.awt.Window.access$700(Window.java:132).

The code snippet works perfectly also for other components (JLabel, JTree, ...) except JPanel. The following code will cause very strange 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
        }

这里是完整的堆栈跟踪:

Here the full stacktrace:

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)

有什么办法解决这个问题吗?我需要在paint(Graphics)方法内绘制JPanel. 我编写了一个简单的测试应用程序,可以复制粘贴以重现上述异常:

Any idea how to solve this problem? I need to paint JPanel inside paint(Graphics) method. I wrote a simple test application which you can copy-paste to reproduce the aforementioned exception:

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

}

推荐答案

这很可能不是 Swing中的错误,但更多的问题是因为您试图绘制没有绘制的组件尚未实现 ,这意味着它没有活动的图形上下文.您可以通过将其添加到已实现的组件(例如JFrame)中来实现该组件,该组件本身可以通过setVisible(true)实现.

This is most likely not a bug in Swing, but more of a problem because you are trying to paint a component which has not yet been realized, meaning it has no active graphic context. You can realize a component by adding it to already realized component like your JFrame - which itself gets realized by setVisible(true).

也应该永远不要手动调用JComponent.paint(Graphics),因为这是Swing的工作(更确切地说是Event Dispatcher Thread)-甚至在paint方法的文档中也是如此:

Also one should probably never call JComponent.paint(Graphics) manually, because this is the job of Swing (more precisely the Event Dispatcher Thread) - it even says so in the documentation of the paint method:

应用程序不应直接调用绘画,而应使用repaint方法安排要重绘的组件.

Applications should not invoke paint directly, but should instead use the repaint method to schedule the component for redrawing.

您可以调用的是方法printAll(Graphics g),该方法绘制了组件及其所有子组件.同样在Swing中,还应该覆盖paint,但paintComponent.

What you can call is the method printAll(Graphics g), which paints the component and all its subcomponents. Also in Swing one should also not override paint but 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);
    }

这应该可以工作(尽管您显然会在屏幕上有两个不需要的组件).还要注意重置"图形对象,因为以后它仍将由Swing使用.

This should work (although you will obviously have two components on the screen you don't want). Also note "reset" the graphics object, because it will still be used afterwards by Swing.

这是理论,但这还不是实际的解决方案.

So this is the theory, but it's not yet an actual solution.

我对您的问题的解决方案是:别这样"!

My solution to your problem is: "Don't do it like this"!

在某种意义上说,组件在所有地方看起来都不一样,它们与图像不是 一样. paintAll调用的输出将有所不同,具体取决于实现组件的方式(或位置).

Components are not like images, in the sense that they don't look the same everywhere. The output of the paintAll call will be different, depending on how (or where) the components were realized.

因此,一个建议是显示实际组件.创建工具提示框,添加面板和按钮,然后让它们自己绘制.您甚至可以子类化这些组件,并覆盖它们的paintComponent()方法,添加透明度以及全部.这将需要一些工作,但是Swing从来都不是那么容易的.

So one suggestion is to show actual components. Create your tooltip box, add your panel and your button and let them draw themselves. You can even subclass these components and override their paintComponent() methods, add transparency and all. It will require some work, but Swing was never known to be easy.

这篇关于在绘制JPanel时出现java.awt.Window.access $ 700(Window.java:132)处的NullPointerException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆