简体   繁体   English

为 Java 中的新图形清除屏幕 (awt)

[英]Clearing the screen for new graphics in Java (awt)

I have this code which is basically a home menu with two clickable rectangles.我有这段代码,它基本上是一个带有两个可点击矩形的主菜单。

  • Start Game开始游戏
  • Info信息

Start Game works fine.开始游戏工作正常。 Info is what is not really working.信息是没有真正起作用的。 When pressed, the info screen will appear, but the home menu buttons will still be there though not visible (can be clicked).. it seems that when the info menu is appearing, the home menu buttons are not getting cleared.按下时,会出现信息屏幕,但主菜单按钮仍然存在,虽然不可见(可以单击).. 似乎当信息菜单出现时,主菜单按钮没有被清除。 Also, any point on the info menu is clickable and will show the home menu again.此外,信息菜单上的任何点都是可点击的,并将再次显示主菜单。 (not what intended, only the back buttons should do that). (不是预期的,只有后退按钮应该这样做)。

How can I fix those problems?我该如何解决这些问题?

package test;

import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import java.awt.geom.Rectangle2D;
import java.awt.image.ImageObserver;
import java.awt.image.ImageProducer;



public class HomeMenu extends JComponent implements MouseListener, MouseMotionListener {

    private static final String GAME_TITLE = "BRICK DESTROY";
    private static final String START_TEXT = "START";
    private static final String INFO_TEXT = "INFO";
    private static final String howtoPlay = """
            1- Click Start\n
            2- Choose the mode\n
            3- Each mode has 3 levels\n
            4- To play/pause press space, use 'A' and 'D' to move\n
            5- To open pause menu press 'ESC'\n
            6- To open DebugPanel press 'ALT-SHIFT-F1'""";
    private static final String backText = "BACK";

    private static final Color BORDER_COLOR = new Color(200,8,21); //Venetian Red
    private static final Color DASH_BORDER_COLOR = new  Color(255, 216, 0);//school bus yellow
    private static final Color TEXT_COLOR = new Color(255, 255, 255);//white
    private static final Color CLICKED_BUTTON_COLOR = Color.ORANGE.darker();;
    private static final Color CLICKED_TEXT = Color.ORANGE.darker();
    private static final int BORDER_SIZE = 5;
    private static final float[] DASHES = {12,6};


    private Rectangle menuFace;
    private Rectangle infoFace;
    private Rectangle startButton;
    private Rectangle infoButton;
    private Rectangle backButton;


    private BasicStroke borderStoke;
    private BasicStroke borderStoke_noDashes;
    private Image img =  Toolkit.getDefaultToolkit().createImage("1.jpeg");
    private Font gameTitleFont;
    private Font infoFont;
    private Font buttonFont;
    private Font howtoPlayFont;

    private GameFrame owner;

    private boolean startClicked;
    private boolean infoClicked = false;
    private boolean backClicked = false;


    public HomeMenu(GameFrame owner,Dimension area){

        this.setFocusable(true);
        this.requestFocusInWindow();

        this.addMouseListener(this);
        this.addMouseMotionListener(this);

        this.owner = owner;


        menuFace = new Rectangle(new Point(0,0),area);
        infoFace = new Rectangle(new Point(0,0),area);
        this.setPreferredSize(area);

        Dimension btnDim = new Dimension(area.width / 3, area.height / 12);
        startButton = new Rectangle(btnDim);
        infoButton = new Rectangle(btnDim);
        backButton = new Rectangle(btnDim);

        borderStoke = new BasicStroke(BORDER_SIZE,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND,0,DASHES,0);
        borderStoke_noDashes = new BasicStroke(BORDER_SIZE,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND);


        gameTitleFont = new Font("Calibri",Font.BOLD,28);
        infoFont = new Font("Calibri",Font.BOLD,24);
        buttonFont = new Font("Calibri",Font.BOLD,startButton.height-2);
        howtoPlayFont = new Font("Calibri",Font.PLAIN,14);




    }


    public void paint(Graphics g){
        drawMenu((Graphics2D)g);

    }



    public void drawMenu(Graphics2D g2d){

        if(infoClicked) {
            drawInfoMenu(g2d);
            return;
        }else{
            drawContainer(g2d);

            Color prevColor = g2d.getColor();
            Font prevFont = g2d.getFont();

            double x = menuFace.getX();
            double y = menuFace.getY();


            g2d.translate(x,y);

            //methods calls
            drawText(g2d);
            drawButton(g2d);

            //end of methods calls

            g2d.translate(-x,-y);
            g2d.setFont(prevFont);
            g2d.setColor(prevColor);
        }


        Toolkit.getDefaultToolkit().sync();

    }



    private void drawContainer(Graphics2D g2d){
        Color prev = g2d.getColor();

        //g2d.setColor(BG_COLOR);
        g2d.drawImage(img,0,0,menuFace.width,menuFace.height,this);
        //g2d.fill(menuFace);

        Stroke tmp = g2d.getStroke();

        g2d.setStroke(borderStoke_noDashes);
        g2d.setColor(DASH_BORDER_COLOR);
        g2d.draw(menuFace);

        g2d.setStroke(borderStoke);
        g2d.setColor(BORDER_COLOR);
        g2d.draw(menuFace);

        g2d.setStroke(tmp);

        g2d.setColor(prev);
    }

    private void drawText(Graphics2D g2d){

        g2d.setColor(TEXT_COLOR);

        FontRenderContext frc = g2d.getFontRenderContext();

        Rectangle2D gameTitleRect = gameTitleFont.getStringBounds(GAME_TITLE,frc);

        int sX,sY;

        sY = (int)(menuFace.getHeight() / 4);

        sX = (int)(menuFace.getWidth() - gameTitleRect.getWidth()) / 2;
        sY += (int) gameTitleRect.getHeight() * 1.1;//add 10% of String height between the two strings

        g2d.setFont(gameTitleFont);
        g2d.drawString(GAME_TITLE,sX,sY);


    }

    private void drawButton(Graphics2D g2d){

        FontRenderContext frc = g2d.getFontRenderContext();

        Rectangle2D txtRect = buttonFont.getStringBounds(START_TEXT,frc);
        Rectangle2D mTxtRect = buttonFont.getStringBounds(INFO_TEXT,frc);

        g2d.setFont(buttonFont);

        int x = (menuFace.width - startButton.width) / 2;
        int y =(int) ((menuFace.height - startButton.height) * 0.5);

        startButton.setLocation(x,y);

        x = (int)(startButton.getWidth() - txtRect.getWidth()) / 2;
        y = (int)(startButton.getHeight() - txtRect.getHeight()) / 2;

        x += startButton.x;
        y += startButton.y + (startButton.height * 0.9);


        if(startClicked){
            Color tmp = g2d.getColor();
            g2d.setColor(CLICKED_BUTTON_COLOR);
            g2d.draw(startButton);
            g2d.setColor(CLICKED_TEXT);
            g2d.drawString(START_TEXT,x,y);
            g2d.setColor(tmp);
        }
        else{
            g2d.draw(startButton);
            g2d.drawString(START_TEXT,x,y);
        }

        x = startButton.x;
        y = startButton.y;

        y *= 1.3;

        infoButton.setLocation(x,y);


        x = (int)(infoButton.getWidth() - mTxtRect.getWidth()) / 2;
        y = (int)(infoButton.getHeight() - mTxtRect.getHeight()) / 2;

        x += infoButton.getX();
        y += infoButton.getY() + (startButton.height * 0.9);

        if(infoClicked){
            Color tmp = g2d.getColor();
            g2d.setColor(CLICKED_BUTTON_COLOR);
            g2d.draw(infoButton);
            g2d.setColor(CLICKED_TEXT);
            g2d.drawString(INFO_TEXT,x,y);
            g2d.setColor(tmp);
        }
        else{
            g2d.draw(infoButton);
            g2d.drawString(INFO_TEXT,x,y);
        }

    }


    private void drawInfoMenu(Graphics2D g2d){

        FontRenderContext frc = g2d.getFontRenderContext();

        Rectangle2D infoRec = infoFont.getStringBounds(INFO_TEXT,frc);

        Color prev = g2d.getColor();


        Stroke tmp = g2d.getStroke();


        g2d.setStroke(borderStoke_noDashes);
        g2d.setColor(DASH_BORDER_COLOR);
        g2d.draw(infoFace);

        g2d.setStroke(borderStoke);
        g2d.setColor(BORDER_COLOR);
        g2d.draw(infoFace);

        g2d.fillRect(0,0,infoFace.width,infoFace.height);

        g2d.setStroke(tmp);

        g2d.setColor(prev);

        g2d.setColor(TEXT_COLOR);


        int sX,sY;

        sY = (int)(infoFace.getHeight() / 15);

        sX = (int)(infoFace.getWidth() - infoRec.getWidth()) / 2;
        sY += (int) infoRec.getHeight() * 1.1;//add 10% of String height between the two strings

        g2d.setFont(infoFont);
        g2d.drawString(INFO_TEXT,sX,sY);

        TextLayout layout = new TextLayout(howtoPlay, howtoPlayFont, frc);
        String[] outputs = howtoPlay.split("\n");
        for(int i=0; i<outputs.length; i++) {
            g2d.setFont(howtoPlayFont);
            g2d.drawString(outputs[i], 40, (int) (80 + i * layout.getBounds().getHeight() + 0.5));
        }

        backButton.setLocation(getWidth()/3,getHeight()-50);


        int x = (int)(backButton.getWidth() - infoRec.getWidth()) / 2;
        int y = (int)(backButton.getHeight() - infoRec.getHeight()) / 2;

        x += backButton.x+11;
        y += backButton.y + (layout.getBounds().getHeight() * 1.35);

        backButton.setLocation(getWidth()/3,getHeight()-50);

        if(backClicked){
            Color tmp1 = g2d.getColor();
            g2d.setColor(CLICKED_BUTTON_COLOR);
            g2d.draw(backButton);
            g2d.setColor(CLICKED_TEXT);
            g2d.drawString(backText,x,y);
            g2d.setColor(tmp1);
            infoClicked = false;
            repaint();
        }
        else{
            g2d.draw(backButton);
            g2d.drawString(backText,x,y);
        }


    }

    @Override
    public void mouseClicked(MouseEvent mouseEvent) {
        Point p = mouseEvent.getPoint();
        if(startButton.contains(p)){
           owner.enableGameBoard();

        }
        else if(infoButton.contains(p)){
            infoClicked = true;
        }
        else if(backButton.contains(p)){
            infoClicked = false;

        }
        repaint();

    }

    @Override
    public void mousePressed(MouseEvent mouseEvent) {
        Point p = mouseEvent.getPoint();
        if(startButton.contains(p)){
            startClicked = true;
            repaint(startButton.x,startButton.y,startButton.width+1,startButton.height+1);

        }
        else if(infoButton.contains(p)){
            infoClicked = true;

        }
        else if(backButton.contains(p)){
            infoClicked = false;
        }
        repaint();

    }

    @Override
    public void mouseReleased(MouseEvent mouseEvent) {
        if(startClicked){
            startClicked = false;
            repaint(startButton.x,startButton.y,startButton.width+1,startButton.height+1);
        }
        else if(infoClicked){
            infoClicked = false;
        }
        else if(backClicked){
            infoClicked = true;
        }
        repaint();
    }

    @Override
    public void mouseEntered(MouseEvent mouseEvent) {

    }

    @Override
    public void mouseExited(MouseEvent mouseEvent) {

    }


    @Override
    public void mouseDragged(MouseEvent mouseEvent) {

    }

    @Override
    public void mouseMoved(MouseEvent mouseEvent) {
        Point p = mouseEvent.getPoint();
        if(startButton.contains(p) || infoButton.contains(p) || backButton.contains(p)) {
            this.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
        }
        else {
            this.setCursor(Cursor.getDefaultCursor());
        }
    }

}

Here are the images of both windows main menu这是 windows主菜单的图像

info menu, pressing anywhere = back to home menu, pressing roughly in the middle = start game or back to main menu too信息菜单,按任意位置 = 返回主菜单,大致在中间按 = 开始游戏或返回主菜单

First read, Performing Custom Painting and Painting in AWT and Swing to get a better understanding how painting in Swing works and how you're suppose to work with it.首先阅读,在 AWT 和 Swing执行自定义绘画和绘画,以更好地了解 Swing 中的绘画如何工作以及您应该如何使用它。

But I already have...但是我已经...

public void paint(Graphics g){
    drawMenu((Graphics2D)g);

}

would suggest otherwise.否则会建议。 Seriously, go read those links so you understand all the issues that the above decision is going to create for you.说真的,go 阅读了这些链接,以便您了解上述决定将为您带来的所有问题。

You're operating in a OO language, you need to take advantage of that and decouple your code and focus on the "single responsibility" principle.您正在使用 OO 语言进行操作,您需要利用它并解耦代码并专注于“单一职责”原则。

I'm kind of tired of talking about it, so you can do some reading:我有点厌倦了谈论它,所以你可以做一些阅读:

These are basic concepts you really need to understand as they will make your live SOOO much easier and can be applied to just about language.这些是您真正需要了解的基本概念,因为它们将使您的生活变得更加轻松,并且几乎可以应用于语言。

As an example, from your code...例如,从您的代码中...

public HomeMenu(GameFrame owner,Dimension area){
    //...
    this.setPreferredSize(area);

There is no good reason (other than laziness (IMHO)) that any caller should be telling a component what size it should be, that's not their responsibility.没有充分的理由(除了懒惰(恕我直言))任何调用者都应该告诉组件它应该是什么大小,这不是他们的责任。 It's the responsibility of the component to tell the parent container how big it would like to be and for the parent component to figure out how it's going to achieve that (or ignore it as the case may be).组件有责任告诉父容器它希望有多大,而父组件则负责弄清楚它将如何实现这一目标(或视情况而定忽略它)。

The "basic" problem you're having is a simple one.您遇到的“基本”问题很简单。 You "God" class is simply trying to do too much (ie it's taken on too much responsibility).您的“上帝” class 只是试图做太多事情(即承担了太多责任)。 Now we "could" add a dozen or more flags into the code to compensate for this, which is just going to increase the coupling and complexity, making it harder to understand and maintain, or we can take a step back, break it down into individual areas of responsibility and build the solution around those, for example...现在我们“可以”在代码中添加十几个或更多标志来弥补这一点,这只会增加耦合和复杂性,使其更难理解和维护,或者我们可以退后一步,将其分解为各个责任领域并围绕这些领域构建解决方案,例如...

import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Stroke;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class Test {

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

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new HomePane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class HomePane extends JPanel {

        public HomePane() {
            setLayout(new BorderLayout());
            navigateToMenu();
        }

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

        protected void navigateToMenu() {
            removeAll();
            HomeMenuPane pane = new HomeMenuPane(new HomeMenuPane.NavigationListener() {
                @Override
                public void navigateToInfo(HomeMenuPane source) {
                    HomePane.this.navigateToInfo();
                }

                @Override
                public void navigateToStartGame(HomeMenuPane source) {
                    startGame();
                }
            });
            add(pane);
            revalidate();
            repaint();
        }

        protected void navigateToInfo() {
            removeAll();
            HowToPlayPane pane = new HowToPlayPane(new HowToPlayPane.NavigationListener() {
                @Override
                public void navigateBack(HowToPlayPane source) {
                    navigateToMenu();
                }
            });
            add(pane);
            revalidate();
            repaint();
        }

        protected void startGame() {
            removeAll();
            add(new JLabel("This is pretty awesome, isn't it!", JLabel.CENTER));
            revalidate();
            repaint();
        }

    }

    public abstract class AbstractBaseMenuPane extends JPanel {

        protected static final Color BORDER_COLOR = new Color(200, 8, 21); //Venetian Red
        protected static final Color DASH_BORDER_COLOR = new Color(255, 216, 0);//school bus yellow
        protected static final Color TEXT_COLOR = new Color(255, 255, 255);//white
        protected static final Color CLICKED_BUTTON_COLOR = Color.ORANGE.darker();
        protected static final Color CLICKED_TEXT = Color.ORANGE.darker();
        protected static final int BORDER_SIZE = 5;
        protected static final float[] DASHES = {12, 6};

        private Rectangle border;

        private BasicStroke borderStoke;
        private BasicStroke borderStoke_noDashes;

        private BufferedImage backgroundImage;

        public AbstractBaseMenuPane() {
            borderStoke = new BasicStroke(BORDER_SIZE, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 0, DASHES, 0);
            borderStoke_noDashes = new BasicStroke(BORDER_SIZE, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
            border = new Rectangle(new Point(0, 0), getPreferredSize());
            // You are now responsible for filling the background
            setOpaque(false);
        }

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

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            BufferedImage backgroundImage = getBackgroundImage();
            if (backgroundImage != null) {
                g2d.drawImage(backgroundImage, 0, 0, getWidth(), getHeight(), this);
            }

            Color prev = g2d.getColor();
            Stroke tmp = g2d.getStroke();

            g2d.setStroke(borderStoke_noDashes);
            g2d.setColor(DASH_BORDER_COLOR);
            g2d.draw(border);

            g2d.setStroke(borderStoke);
            g2d.setColor(BORDER_COLOR);
            g2d.draw(border);

            g2d.dispose();
        }

        public void setBackgroundImage(BufferedImage backgroundImage) {
            this.backgroundImage = backgroundImage;
            repaint();
        }

        public BufferedImage getBackgroundImage() {
            return backgroundImage;
        }

    }

    public class HomeMenuPane extends AbstractBaseMenuPane {

        public static interface NavigationListener {

            public void navigateToInfo(HomeMenuPane source);

            public void navigateToStartGame(HomeMenuPane source);
        }

        private static final String GAME_TITLE = "BRICK DESTROY";
        private static final String START_TEXT = "START";
        private static final String INFO_TEXT = "INFO";

        private Rectangle startButton;
        private Rectangle infoButton;

        private Font gameTitleFont;
        private Font buttonFont;

        // Don't do this, this just sucks (for so many reasons)
        // Use ImageIO.read instead and save yourself a load of frustration
        //private Image img =  Toolkit.getDefaultToolkit().createImage("1.jpeg");

        private Point lastClickPoint;

        private NavigationListener navigationListener;

        public HomeMenuPane(NavigationListener navigationListener) {
            this.navigationListener = navigationListener;

            try {
                setBackgroundImage(ImageIO.read(getClass().getResource("/images/BrickWall.jpg")));
            } catch (IOException ex) {
                Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
            }

            this.addMouseListener(new MouseAdapter() {

                @Override
                public void mousePressed(MouseEvent mouseEvent) {
                    Point p = mouseEvent.getPoint();
                    lastClickPoint = p;
                    if (startButton.contains(p)) {
                        peformStartGameAction();
                    } else if (infoButton.contains(p)) {
                        performInfoAction();
                    }
                    repaint();
                }

                @Override
                public void mouseReleased(MouseEvent mouseEvent) {
                    lastClickPoint = null;
                    repaint();
                }
            });
            this.addMouseMotionListener(new MouseAdapter() {
                @Override
                public void mouseMoved(MouseEvent mouseEvent) {
                    Point p = mouseEvent.getPoint();
                    if (startButton.contains(p) || infoButton.contains(p)) {
                        setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
                    } else {
                        setCursor(Cursor.getDefaultCursor());
                    }
                }
            });

            Dimension area = getPreferredSize();

            Dimension btnDim = new Dimension(area.width / 3, area.height / 12);
            startButton = new Rectangle(btnDim);
            infoButton = new Rectangle(btnDim);

            gameTitleFont = new Font("Calibri", Font.BOLD, 28);
            buttonFont = new Font("Calibri", Font.BOLD, startButton.height - 2);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();

            Color prevColor = g2d.getColor();
            Font prevFont = g2d.getFont();

            //methods calls
            drawText(g2d);
            drawButton(g2d);

            //end of methods calls
            g2d.setFont(prevFont);
            g2d.setColor(prevColor);
            g2d.dispose();
        }

        private void drawText(Graphics2D g2d) {
            g2d.setColor(TEXT_COLOR);

            FontRenderContext frc = g2d.getFontRenderContext();

            Rectangle2D gameTitleRect = gameTitleFont.getStringBounds(GAME_TITLE, frc);

            int sX, sY;

            sY = (int) (getHeight() / 4);

            sX = (int) (getWidth() - gameTitleRect.getWidth()) / 2;
            sY += (int) gameTitleRect.getHeight() * 1.1;//add 10% of String height between the two strings

            g2d.setFont(gameTitleFont);
            g2d.drawString(GAME_TITLE, sX, sY);

        }

        private void drawButton(Graphics2D g2d) {

            FontRenderContext frc = g2d.getFontRenderContext();

            Rectangle2D txtRect = buttonFont.getStringBounds(START_TEXT, frc);
            Rectangle2D mTxtRect = buttonFont.getStringBounds(INFO_TEXT, frc);

            g2d.setFont(buttonFont);

            int x = (getWidth() - startButton.width) / 2;
            int y = (int) ((getHeight() - startButton.height) * 0.5);

            startButton.setLocation(x, y);

            x = (int) (startButton.getWidth() - txtRect.getWidth()) / 2;
            y = (int) (startButton.getHeight() - txtRect.getHeight()) / 2;

            x += startButton.x;
            y += startButton.y + (startButton.height * 0.9);

            if (lastClickPoint != null && startButton.contains(lastClickPoint)) {
                Color tmp = g2d.getColor();
                g2d.setColor(CLICKED_BUTTON_COLOR);
                g2d.draw(startButton);
                g2d.setColor(CLICKED_TEXT);
                g2d.drawString(START_TEXT, x, y);
                g2d.setColor(tmp);
            } else {
                g2d.draw(startButton);
                g2d.drawString(START_TEXT, x, y);
            }

            x = startButton.x;
            y = startButton.y;

            y *= 1.3;

            infoButton.setLocation(x, y);

            x = (int) (infoButton.getWidth() - mTxtRect.getWidth()) / 2;
            y = (int) (infoButton.getHeight() - mTxtRect.getHeight()) / 2;

            x += infoButton.getX();
            y += infoButton.getY() + (startButton.height * 0.9);

            if (lastClickPoint != null && infoButton.contains(lastClickPoint)) {
                Color tmp = g2d.getColor();
                g2d.setColor(CLICKED_BUTTON_COLOR);
                g2d.draw(infoButton);
                g2d.setColor(CLICKED_TEXT);
                g2d.drawString(INFO_TEXT, x, y);
                g2d.setColor(tmp);
            } else {
                g2d.draw(infoButton);
                g2d.drawString(INFO_TEXT, x, y);
            }

        }

        protected void peformStartGameAction() {
            navigationListener.navigateToStartGame(this);
        }

        protected void performInfoAction() {
            navigationListener.navigateToInfo(this);
        }
    }

    public class HowToPlayPane extends AbstractBaseMenuPane {

        public static interface NavigationListener {

            public void navigateBack(HowToPlayPane source);
        }

        private static final String HOW_TO_PLAY_TEXT = """
            1- Click Start\n
            2- Choose the mode\n
            3- Each mode has 3 levels\n
            4- To play/pause press space, use 'A' and 'D' to move\n
            5- To open pause menu press 'ESC'\n
            6- To open DebugPanel press 'ALT-SHIFT-F1'""";
        private static final String BACK_TEXT = "BACK";
        private static final String INFO_TEXT = "INFO";

        private Rectangle backButton;
        private boolean backClicked = false;

        private Font infoFont;
        private Font howtoPlayFont;

        private NavigationListener navigationListener;

        public HowToPlayPane(NavigationListener navigationListener) {
            this.navigationListener = navigationListener;
            this.addMouseListener(new MouseAdapter() {
                @Override
                public void mousePressed(MouseEvent mouseEvent) {
                    Point p = mouseEvent.getPoint();
                    if (backButton.contains(p)) {
                        backClicked = true;
                        repaint();
                        performBackAction();
                    }
                }

                @Override
                public void mouseReleased(MouseEvent e) {
                    backClicked = false;
                }
            });

            this.addMouseMotionListener(new MouseAdapter() {
                @Override
                public void mouseMoved(MouseEvent mouseEvent) {
                    Point p = mouseEvent.getPoint();
                    if (backButton.contains(p)) {
                        setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
                    } else {
                        setCursor(Cursor.getDefaultCursor());
                    }
                }
            });

            Dimension btnDim = new Dimension(getPreferredSize().width / 3, getPreferredSize().height / 12);
            backButton = new Rectangle(btnDim);

            infoFont = new Font("Calibri", Font.BOLD, 24);
            howtoPlayFont = new Font("Calibri", Font.PLAIN, 14);
        }

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

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();

            g2d.setColor(BORDER_COLOR);
            g2d.fillRect(0, 0, getWidth(), getHeight());

            FontRenderContext frc = g2d.getFontRenderContext();
            Rectangle2D infoRec = infoFont.getStringBounds(INFO_TEXT, frc);
//
//            Color prev = g2d.getColor();
//
//            Stroke tmp = g2d.getStroke();
//
//            g2d.setStroke(borderStoke_noDashes);
//            g2d.setColor(DASH_BORDER_COLOR);
//            g2d.draw(infoFace);
//
//            g2d.setStroke(borderStoke);
//            g2d.setColor(BORDER_COLOR);
//            g2d.draw(infoFace);
//
//            g2d.fillRect(0, 0, infoFace.width, infoFace.height);
//
//            g2d.setStroke(tmp);
//
//            g2d.setColor(prev);
//
            g2d.setColor(TEXT_COLOR);

            int sX, sY;

            sY = (int) (getHeight() / 15);

            sX = (int) (getWidth() - infoRec.getWidth()) / 2;
            sY += (int) infoRec.getHeight() * 1.1;//add 10% of String height between the two strings

            g2d.setFont(infoFont);
            g2d.drawString(INFO_TEXT, sX, sY);

            TextLayout layout = new TextLayout(HOW_TO_PLAY_TEXT, howtoPlayFont, frc);
            String[] outputs = HOW_TO_PLAY_TEXT.split("\n");
            for (int i = 0; i < outputs.length; i++) {
                g2d.setFont(howtoPlayFont);
                g2d.drawString(outputs[i], 40, (int) (80 + i * layout.getBounds().getHeight() + 0.5));
            }

            backButton.setLocation(getWidth() / 3, getHeight() - 50);

            int x = (int) (backButton.getWidth() - infoRec.getWidth()) / 2;
            int y = (int) (backButton.getHeight() - infoRec.getHeight()) / 2;

            x += backButton.x + 11;
            y += backButton.y + (layout.getBounds().getHeight() * 1.35);

            backButton.setLocation(getWidth() / 3, getHeight() - 50);

            if (backClicked) {
                Color tmp1 = g2d.getColor();
                g2d.setColor(CLICKED_BUTTON_COLOR);
                g2d.draw(backButton);
                g2d.setColor(CLICKED_TEXT);
                g2d.drawString(BACK_TEXT, x, y);
                g2d.setColor(tmp1);
                repaint();
            } else {
                g2d.draw(backButton);
                g2d.drawString(BACK_TEXT, x, y);
            }
            g2d.dispose();
        }

        protected void performBackAction() {
            navigationListener.navigateBack(this);
        }
    }

}

Now, this example makes use of components to present different views (it even has a nice abstract implementation to allow for code re-use ), but it occurs to me, that, if you "really" wanted to, you could have a series of "painter" classes, which could be used to delegate the painting of the current state to, and mouse clicks/movements could be delegated to, meaning you could have a single component, which would simple delegate the painting (via the paintComponent method) to which ever painter is active.现在,这个例子利用组件来呈现不同的视图(它甚至有一个很好的抽象实现来允许代码重用),但我突然想到,如果你“真的”想要,你可以有一个系列的“画家”类,可用于将当前 state 的绘画委托给,鼠标点击/移动可以委托给,这意味着您可以有一个组件,它可以简单地委托绘画(通过paintComponent方法)哪个painter活跃。

And, wouldn't you know it, they have a design principle for that to, the Delegation Pattern而且,你不知道吗,他们有一个设计原则, 委托模式

The above example also makes use of the observer pattern , so you might want to have a look into that as well上面的例子也使用了观察者模式,所以你可能也想看看

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM