Java中的自定义绘图 - 将UI元素绘制到JPanel上

3
我正在创建一个绘画板程序,基本上是MS Paint的简化版。它大部分时间都能工作,但当我在画板上绘制时,当前选择的UI元素会显示在绘图区域上。
我尝试了paintComponent方法,在调用super.paintComponent(g)时可以正常工作(如我们所做的那样),但它在我绘制下一个对象之前清除了绘图区域。我重写了update方法并在其中放置了一个println语句,但从未被调用。
顶部按钮的背景颜色为红色,因为我将底部JPanel的背景设置为红色,以查看这些按钮的背景。显然,它们是底部JPanel的一部分。我使用BorderLayout布局。
以下是我的代码(删除了一些不相关的部分):
public class JSPaint extends JFrame implements Serializable
{    
    private static final long serialVersionUID = -8787645153679803322L;
    private JFrame mainFrame;
    private JPanel bp;
    private JButton ...
    private DrawingArea da;

    public JSPaint()
    {
        setTitle("JS Paint");
        setSize(1024, 768);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        // Drawing area
        da = new DrawingArea();

        setLayout(new BorderLayout());

        // add the buttons to the panel
        buttonPanel();

        // Add the drawing area 
        add(bp, BorderLayout.SOUTH);
        bp.setBackground(Color.RED);
        add(da, BorderLayout.CENTER);
        da.setBackground(Color.BLUE);

        setVisible(true);        
    }

    // I put it here too just in case
    @Override
    public void update(Graphics g)
    {
        System.out.println("update in JSPaint called.");
        paint(g);
    }

   /*
    * Creates the panel for the buttons, creates the buttons and places them on
    * the panel
    */
    public void buttonPanel()
    {
        // Create the panel for the buttons to be placed in
        bp = new JPanel();

        saveButton = new JButton("Save");
        loadButton = new JButton("Load");
        //more buttons

        bp.add(saveButton);
        bp.add(loadButton);
        //more buttons

        // ActionListeners

        colorButton.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent ae)
            {
                System.out.println("color");
                da.color();
            }
        });            
    }

    public class DrawingArea extends JPanel
    {        
        private static final long serialVersionUID = -8299084743195098560L;
        boolean dragged = false;

        @Override
        public void update(Graphics g)
        {
            System.out.println("Update in DrawingArea called");
            paint(g);
        }

       /*
        * Draws the selected shape onto the screen and saves it into a Stack.
        *
        */
        public void draw()
        {
            this.addMouseMotionListener(new MouseMotionListener()
            {                
                public void mouseDragged(MouseEvent me)
                {
                    dragged = true;
                }

                public void mouseMoved(MouseEvent me) {}
            });

            //more listeners...
            });
        }

       /*
        * Draws the selected String onto the screen when the mouse is held down.
        *
        */
        public void brush()
        {
            this.addMouseMotionListener(new MouseMotionListener()
            {                
                public void mouseDragged(MouseEvent me)
                {
                    // If we are in drawing mode, draw the String. Create a new 
                    // Figure Object and push it onto the Stack
                    if(activeButton == "brush")
                    {
                        startPoint = me.getPoint();

                        Figure fig = new Figure("String", startPoint, null, currentColor);
//                        figures.push(calculate(fig));
                        toPaint.push(calculate(fig));
                        repaint();
                    }
                }

                public void mouseMoved(MouseEvent me) {}
            });           
        }

        // more of the same...

        public void paint(Graphics g)
        {                        
            toSave.addAll(toPaint);

            while(!toPaint.isEmpty())
            {
                Figure f = toPaint.pop();
                String t = f.type;

                if(f.color != null)
                {
                    g.setColor(f.color);
                }

                switch(t)
                {
                    case "Rectangle": g.drawRect(f.x1, f.y1, f.width, f.height);
                        break;
                    case "Oval": g.drawOval(f.x1, f.y1, f.width, f.height);
                        break;         
                    case "Line": g.drawLine(f.x1, f.y1, f.x2, f.y2);
                        break;
                    case "Clear": 
                        g.fillRect(0, 0, da.getWidth(), da.getHeight());
                        clearStack(toSave);
                        break;
                    case "String": g.drawString(f.toPrint, f.x1, f.y1);
                        break;
                }
            }
        }
    }

    private class Figure implements Serializable
    {
        private static final long serialVersionUID = 4690475365105752994L;
        String type, toPrint;
        Color color;
        Point start;
        Point end;
        int x1, y1, x2, y2, width, height;

        public Figure(String figureType, 
            Point startPoint, Point endPoint, Color figureColor)
        {
            type = figureType;
            color = figureColor;
            start = startPoint;
            end = endPoint;
        }

        // Rect, Oval
        public Figure(String figureType, int figureX, int figureY, 
            int figureWidth, int figureHeight, Color figureColor)
        {
            type = figureType;
            x1 = figureX;
            y1 = figureY;
            width = figureWidth;
            height = figureHeight;
            color = figureColor;
        }

        // more shapes
    }

    public static void main(String args[])
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                new JSPaint();
            }
        });
    }
}

1
你应该使用 BufferedImage 来保存绘图区域,然后在调用 paintComponent 方法时使用 drawImage 将其复制到屏幕上。你不需要重写 paint 方法来避免清除屏幕,因为缓冲区可能会在两次 paint 调用之间变得无效并填充其他数据。 - yiding
2
请编辑您的问题,包括sscce,展示您在哪里调用了pack()函数。 - trashgod
1
@yiding "你应该使用BufferedImage来保存绘图区域" 一旦你有了这个图片,你也可以在标签中显示它。 - Andrew Thompson
1个回答

0
如果当前选定的UI元素显示在绘图区域上,那么只有一个可能原因:您在处理Graphics对象时出现了问题,可能调用了它们的translate方法,但没有在完成后重置翻译。 (请参见this链接,以获取正确使用translate的示例)。

谢谢!我从这个项目中休息了很长时间,但最终计划回去。如果我弄清楚了,我会告诉你的。我会调查一下...谢谢! - jacky

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接