如何从Java中的多个方法中提取?

How to draw from multiple methods in Java?

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

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

我一直在阅读图形,我知道你不应该从 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();
}

}

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

...每当调用 repaint() 时,它都会在内部调用 paint(Graphics g) 方法,并在您的绘画方法中添加一个 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);
        }
    });

}

您仍在调用 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();
    }

}

一句话,没有。但是,你走在正确的轨道上。

请记住,您 运行 处于事件驱动的环境中,这意味着某些事情发生了,然后您会做出响应。

绘制应该只绘制当前状态,在您的示例中,每次调用 paint 时,您都会向按钮添加一个新的 ActionListener,因此您可以结束最多在屏幕可见时将 3+ ActionListener 附加到每个按钮,这将导致一些非常奇怪的行为。

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

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

这有两个主要原因,首先,它将您锁定在一个用例中,这意味着您不能重复使用您的组件,其次直接绘制到像 JFrame 这样的顶级容器可能会让您在框架的下方绘画 decorations/borders 并且由于绘画的工作方式,即使框架内容在其上绘画。

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

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

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

    }

}

一个小瑕疵: 不要在 actionListener 中调用 drawFrown(g)drawSmile(g) (你不能再这样了,你不再知道 graphics 了)而是调用 repaint().

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

我只是在做微笑部分,皱眉部分也是一样

private int style = 0;

public JSmileFacePanel2() {

    //other code as above
    ...

    smile.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            System.out.println("SMILE BUTTON CLICKED");
            style = 1; //1=smile, 2=frown
            repaint(); //this calls internally the paint(g) method
        }
    });
}

并调整你的绘画方法:

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

    if(style == 1){
        drawSmile(g);
    }

    if(style == 2){
        drawFrown(g);
    }
}