如何从Java中的多个方法中绘制?

时间:2015-12-15 05:10:35

标签: java swing graphics drawing graphics2d

好吧,所以我正在尝试制作一个笑脸程序,当它第一次启动时它应该显示默认的笑脸(这个部分有效,我觉得很棒)

但是它应该给你两个按钮来挑选微笑和皱眉按钮,这些按钮应该重绘面部以显示一个微笑或皱眉但是由于某种原因它不起作用。

我一直在阅读有关图形的知识,我知道你不应该从paint()方法之外调用它们,所以我相应地改变了我的代码,我可以告诉按钮是否正常工作,因为我让它们打印出来时间,但实际重绘不起作用。我也尝试过使用repaint()和revalidate()。出于某种原因,如果你使用repaint(),它每次重绘的次数越多越奇怪,但也许它应该表现得那样?

有人可以看看代码,让我知道你认为是什么问题或者我应该在哪里寻找解决方案我已经使用了java一段时间但是我从不使用图形:/我读过你应该在最后使用setVisible / setSize(或pack()),这实际上帮助了我之前遇到的一些问题,但是当你想绘制多个东西时我不知道该做什么,大多数例子只显示绘制一件事。

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

import javax.swing.JButton;
import javax.swing.JFrame;

public class JSmileFacePanel2 extends JFrame {

/**
 * 
 */
private static final long serialVersionUID = 1L;

JButton smile = new JButton("SMILE");
JButton frown = new JButton("FROWN");

public JSmileFacePanel2() {
    setLayout(new FlowLayout());
    setTitle("JSmileFace-V2: Jose M. Tobar");
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    add(frown);
    add(smile);

    setSize(800, 800);
    setVisible(true);
}

public void paint(Graphics g) {
    super.paint(g);
    //by default should show smiling
    g.setColor(Color.YELLOW);
    g.fillOval(200, 200, 500, 500);
    g.setColor(Color.BLUE);
    g.fillOval(300, 360, 50, 50);
    g.setColor(Color.BLUE);
    g.fillOval(600, 360, 50, 50);
    g.drawArc(400, 400, 100, 40, 180, 185);

    smile.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            System.out.println("SMILE BUTTON CLICKED");
            drawSmile(g);

        }
    });

    frown.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            System.out.println("FROWN BUTTON CLICKED");
            drawFrown(g);
        }
    });
}

public void drawSmile(Graphics g) {
    g.setColor(Color.YELLOW);
    g.fillOval(200, 200, 500, 500);
    g.setColor(Color.BLUE);
    g.fillOval(300, 360, 50, 50);
    g.setColor(Color.BLUE);
    g.fillOval(600, 360, 50, 50);
    g.drawArc(400, 400, 100, 40, 180, 185);
    repaint();
}

public void drawFrown(Graphics g) {
    g.setColor(Color.WHITE);
    g.fillOval(200, 200, 500, 500);
    g.setColor(Color.BLUE);
    g.fillOval(300, 360, 50, 50);
    g.setColor(Color.BLUE);
    g.fillOval(600, 360, 50, 50);
    g.drawArc(400, 400, 100, 40, 180, 185);
    repaint();
}


public static void main(String[] args) {
    JSmileFacePanel2 js = new JSmileFacePanel2();
}

}

4 个答案:

答案 0 :(得分:1)

您仍然在paint方法之外调用绘制方法,因为actionPerformed方法的方法与paint方法不同。它们在文本内部并不重要,它仍然是一种不同的方法。

此外,每次有重绘事件时,您都会反复添加动作侦听器,这会使应用程序停止运行,并且也不会正确重新绘制。

因此,检查您是否应该在paint方法中微笑或皱眉,并在构造函数中添加动作侦听器。

然后代码变为:

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

import javax.swing.JButton;
import javax.swing.JFrame;

public class JSmileFacePanel2 extends JFrame {

    private static final long serialVersionUID = 1L;

    // by default should show smiling
    private boolean doSmile = true;

    JButton smile = new JButton("SMILE");
    JButton frown = new JButton("FROWN");

    public JSmileFacePanel2() {
        setLayout(new FlowLayout());
        setTitle("JSmileFace-V2: Jose M. Tobar");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        add(frown);
        add(smile);

        smile.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                System.out.println("SMILE BUTTON CLICKED");
                doSmile = true;
                repaint();
            }
        });

        frown.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                System.out.println("FROWN BUTTON CLICKED");
                doSmile = false;
                repaint();
            }
        });

        setSize(800, 800);
        setVisible(true);
    }

    public void paint(final Graphics g) {
        super.paint(g);

        if (doSmile) {
            drawSmile(g);
        } else {
            drawFrown(g);
        }
    }

    public void drawSmile(Graphics g) {
        g.setColor(Color.YELLOW);
        g.fillOval(200, 200, 500, 500);
        g.setColor(Color.BLUE);
        g.fillOval(300, 360, 50, 50);
        g.setColor(Color.BLUE);
        g.fillOval(600, 360, 50, 50);
        g.drawArc(400, 400, 100, 40, 180, 185);
    }

    public void drawFrown(Graphics g) {
        g.setColor(Color.WHITE);
        g.fillOval(200, 200, 500, 500);
        g.setColor(Color.BLUE);
        g.fillOval(300, 360, 50, 50);
        g.setColor(Color.BLUE);
        g.fillOval(600, 360, 50, 50);
        g.drawArc(400, 400, 100, 40, 180, 185);
    }

    public static void main(String[] args) {
        JSmileFacePanel2 js = new JSmileFacePanel2();
    }

}

答案 1 :(得分:1)

总之,没有。但是,你现在正走在正确的轨道上。

请记住,您是在事件驱动的环境中运行,这意味着某些事情会发生,然后您会对其做出回应。

绘画应该什么都不做,只需绘制当前状态,在你的例子中,每次调用paint时,你都会在按钮上添加一个新的ActionListener,这样你就可以了当屏幕可见时,每个按钮上附有3 + ActionListener个,这将导致一些非常奇怪的行为。

您也不应该直接或间接地从paint方法中修改组件的状态,这可能会导致repaint被调度,这将导致您的paint方法被重复调用,最终将被调用消耗你的CPU周期,至少可以说是凌乱。

您还应该避免从顶级容器扩展并覆盖paint(通常),而是改为使用JPanel并改为使用paintComponent方法。

这有两个主要原因,首先,它将您锁定在一个用例中,这意味着您无法重新使用您的组件,其次直接绘制到顶级容器,如JFrame可能让您在下面绘画框架的装饰/边框,以及绘画的工作方式,即使框架内容在其上绘画。

有关详细信息,请参阅Painting in AWT and SwingPerforming Custom Painting

一般解决方案是使用标志来更改绘制过程的工作方式,并在需要时相应地更改此标志(例如,在按钮的ActionListener内)

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class JSmileFace {

    private static final long serialVersionUID = 1L;

    public static void main(String[] args) {
        new JSmileFace();
    }

    public JSmileFace() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new SmilyPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class SmilyPane extends JPanel {

        JButton smile = new JButton("SMILE");
        JButton frown = new JButton("FROWN");

        private boolean frowning = false;

        public SmilyPane() {
            setLayout(new FlowLayout());

            add(frown);
            add(smile);

            smile.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    frowning = false;
                    repaint();
                }
            });

            frown.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    System.out.println("FROWN BUTTON CLICKED");
                    frowning = true;
                    repaint();
                }
            });
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(800, 600);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.setColor(Color.YELLOW);
            g.fillOval(200, 200, 500, 500);
            g.setColor(Color.BLUE);
            g.fillOval(300, 360, 50, 50);
            g.setColor(Color.BLUE);
            g.fillOval(600, 360, 50, 50);
            g.drawArc(400, 400, 100, 40, 180, 185);

            if (frowning) {
                drawFrown(g);
            } else {
                drawSmile(g);
            }
        }

        public void drawSmile(Graphics g) {
            g.setColor(Color.YELLOW);
            g.fillOval(200, 200, 500, 500);
            g.setColor(Color.BLUE);
            g.fillOval(300, 360, 50, 50);
            g.setColor(Color.BLUE);
            g.fillOval(600, 360, 50, 50);
            g.drawArc(400, 400, 100, 40, 180, 185);
        }

        public void drawFrown(Graphics g) {
            g.setColor(Color.WHITE);
            g.fillOval(200, 200, 500, 500);
            g.setColor(Color.BLUE);
            g.fillOval(300, 360, 50, 50);
            g.setColor(Color.BLUE);
            g.fillOval(600, 360, 50, 50);
            g.drawArc(400, 400, 100, 40, 180, 185);
        }

    }

}

答案 2 :(得分:0)

主要问题:你在代码中添加了很多动作列表......

...每当调用repaint()时,它会在内部调用paint(Graphics g)方法,并在paint-method中添加一个actionListener(无论何时重绘,都会一次又一次)

尝试在构造函数中添加actionListener:

public JSmileFacePanel2() {
    setLayout(new FlowLayout());
    setTitle("JSmileFace-V2: Jose M. Tobar");
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    add(frown);
    add(smile);

    setSize(800, 800);
    setVisible(true);


    //here:
    smile.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            System.out.println("SMILE BUTTON CLICKED");
            drawSmile(g);

        }
    });

    frown.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            System.out.println("FROWN BUTTON CLICKED");
            drawFrown(g);
        }
    });

}

答案 3 :(得分:0)

一个小缺陷: 请勿在{{1​​}}内拨打drawFrown(g)drawSmile(g)(您已经不能再知道actionListener了)而是致电{ {1}}。

但是在你graphics之前,你告诉你的图形将绘制什么(我使用repaint()为此,更好地使用repaint()但是它现在可以使用

我只是做微笑部分,皱眉部分是相同的

int

并调整你的绘画方法:

Enums