JPanel이 두 번 생성

사용자 3369920

전함 게임용 GUI를 만들려고합니다. 한 클래스는 GUI 자체를 생성하기위한 것이고 두 번째 클래스는 게임에서 보드를 관리하기위한 것입니다. 내 문제는 마우스 클릭이 발생하면 JPanel이 두 번 생성한다는 것입니다 (마우스 클릭은 게임에서 발사되는 곳으로 가정하고 히트 / 실패로 표시합니다). 왜 두 번 생성되는지 잘 모르겠습니다. 패널 통과 때문인가요? 아래 코드와 코드가 생성하는 사진.

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.BorderFactory;
import javax.swing.JApplet;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;


public class BattleshipApplet extends JApplet implements MouseListener {
    private final JButton playButton = new JButton("Play");
    private final JLabel msgBar = new JLabel("Click Play to start game");
    private BoardPanel panel;



    public BattleshipApplet(){
        playButton.addActionListener(this::playButtonClicked);  
        addMouseListener(this);
    }

    public void init(){
        configureGui();
    }

    private void configureGui(){
        setLayout(new BorderLayout());
        JPanel buttons = new JPanel(new FlowLayout(FlowLayout.LEFT));
        buttons.setBorder(BorderFactory.createEmptyBorder(0,5,0,0));
        buttons.add(playButton);
        add(buttons, BorderLayout.NORTH);
        msgBar.setBorder(BorderFactory.createEmptyBorder(10,10,5,5));
        add(createBoardPanel(), BorderLayout.CENTER);
        add(msgBar, BorderLayout.SOUTH);
    }

    private BoardPanel createBoardPanel(){
        panel = new BoardPanel();
        return panel;
    }

    private void displayMessage(String msg){
        msgBar.setText(msg);
    }

    private void playButtonClicked(ActionEvent event){
        displayMessage("Play button clicked!");
    }

    public void mouseClicked(MouseEvent e) {
        panel.mouseClickedAt(e.getX(), e.getY());
        e.consume();
    }


    public void mouseEntered(MouseEvent e) {
    }


    public void mouseExited(MouseEvent e) {
    }  
    public void mousePressed(MouseEvent e) {
    }
    public void mouseReleased(MouseEvent e) {
    }   
}

JPanel을 사용하는 보드 클래스

[![import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JPanel;


public class BoardPanel extends JPanel  {
    int mx, my;
    boolean rect1Clicked;
    //gamePlay a;
    public void init(){

        rect1Clicked = false;

    }

    /***Your applet shall show the status of the board before and after
     each shot, including the number of shots made and the status of
     each place (no shot or hit/miss shot). ***/
    public void paint(Graphics g){
        boolean miss = false;


        for (int i=0; i<11; i++){ 
            g.setColor(Color.blue);
            g.drawLine(20,20+i*28, 300, 20+i*28);   
        }
        for (int i=0; i<11; i++)   
            g.drawLine(20+i*28,20,20+i*28,300);

        //if inside board 
        if(rect1Clicked == true){
            g.setColor(Color.green);
            //aligns to square to check in computer board for hit/miss
            int bx =(my-20)/28;
            int by =(mx-20)/28;



            //check hit on board
            //if shot was a miss
            if(miss == true ){
                //update to white
                g.setColor(Color.white);
            }
            //if shot was a hit
            if(miss == false){
                //update to red
                g.setColor(Color.red);
            }
            //compare to line for fill
            int fillx = mx/2;
            int filly = my/2 ;
            if(mx<=47){
                fillx = 20;
            }
            if(mx>47 && mx<=75){
                fillx = 48;
            }
            if(mx>75 && mx<=103){
                fillx = 76;
            }
            if(mx>103 && mx <=131){
                fillx = 104;
            }
            if(mx>131 && mx<=159){
                fillx = 132;
            }
            if(mx>159 && mx<=187){
                fillx = 160;
            }
            if(mx>187 && mx <=215){
                fillx = 188;
            }
            if(mx>215 && mx <=243){
                fillx = 216;
            }
            if(mx>243 && mx <=271){
                fillx = 244;
            }
            if(mx>271 && mx<=299){
                fillx = 272;
            }
            if(mx>299){
                fillx = 300;
            }
            //y comparisons
            if(my<=47){
                filly = 20;
            }
            if(my>47 && my<=75){
                filly = 48;
            }
            if(my>75 && my<=103){
                filly = 76;
            }
            if(my>103 && my <=131){
                filly = 104;
            }
            if(my>131 && my<=159){
                filly = 132;
            }
            if(my>159 && my<=187){
                filly = 160;
            }
            if(my>187 && my <=215){
                filly = 188;
            }
            if(my>215 && my <=243){
                filly = 216;
            }
            if(my>243 && my <=271){
                filly = 244;
            }
            if(my>271 && my<=299){
                filly = 272;
            }
            if(my>299){
                filly = 300;
            }


            g.drawString("("+mx+","+my+")",mx,my);
            //25 describes size of square 
            g.fillOval(fillx, filly, 25, 25);

        }


    }

    public void game(BoardPanel p){
        //while game plays
    }


    public void mouseClickedAt(int x, int y){

        mx = x;
        my = y;

        //user clicked inside of board space
        if(mx>20 && mx<300 && my>20 && my<300){       

            //send to board in MainBattleship
            rect1Clicked = true;

        }
        //updates board
        repaint();
    }


}][1]][1]

너무 길을 잃었습니다. 도와 주셔서 감사합니다!

장어가 가득한 호버크라프트

제안 :

  1. JPanel의 paint메서드를 재정의하지 말고 paintComponent메서드가 더 안전하므로 나중에 애니메이션을 원할 때 더 부드러운 애니메이션이됩니다.
  2. 가장 중요한 것은 거의 항상 자신의 내부에서 super의 페인팅 메서드를 호출해야합니다. 그렇지 않으면 JPanel이 정리해야하는 이전 이미지 아티팩트를 제거하지 않습니다. 따라서 페인트를 계속 재정의하는 경우 (이것에 대해 권장하지만) 재정의의 첫 번째 줄은이어야합니다 super.paint(g);. 또는 재정의 paintComponent하는 경우 첫 번째 줄은이어야합니다 super.paintComponent(g);. 물론 메서드가라는 Graphics 매개 변수를 사용한다고 가정합니다 g.
  3. 또한 Applet이 아닌 JPanel에 MouseListener를 추가하십시오 . 패널에서 중요한 것은 마우스 클릭 위치이기 때문입니다.
  4. 또한 구성 요소 그리드 또는 일부 수학을 사용하여 코드를 크게 단순화하십시오. if 블록의 추악한 목록은 기본 수학을 사용하는 훨씬 단순한 for 루프로 대체되어야합니다.
  5. 위의 포인트에서 설명한 논리를 페인팅 방법에서 추출하여 일종의 부울의 2D 배열과 같은 모델로 추출하는 것을 고려하십시오.
  6. 코드에서 많은 "마법의" 숫자를 사용하고 있습니다. 숫자는 상수와 수학적으로 파생 된 숫자의 조합으로 변경되어야합니다.
  7. GUI를 클릭 한 다음 크기를 조정하거나 최소화 한 다음 복원하면 어떤 일이 발생하는지 확인하십시오. 마지막으로 누른 것을 제외한 모든 빨간색 원이 사라집니다. 이것은 게임의 상태를 유지하기 위해 부울 그리드 또는 다른 모델을 사용하고 GUI를 그릴 때이 모델을 사용하는 또 다른 이유입니다.
  8. 더 생각하면, 그리드 셀 상태가 2 개 이상의 값 (true 또는 false)이 될 가능성이 높지만 테스트되지 않음 , 적중 및 실패의 3 개이되기 때문에 열거 형 또는 int 배열의 2D 배열이 필요할 수 있습니다. , 맞으면 빨간색으로 타원을 채우고 실패하면 흰색으로 채우고 싶을 것입니다.

예를 들면 :

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.*;
import javax.swing.*;

public class GridExample {
    private static void createAndShowGui() {
        final GridPanel gridPanel = new GridPanel();

        JButton resetBtn = new JButton(new AbstractAction("Reset") {

            @Override
            public void actionPerformed(ActionEvent e) {
                gridPanel.reset();
            }
        });
        JPanel btnPanel = new JPanel();
        btnPanel.add(resetBtn);

        JFrame frame = new JFrame("GridExample");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(gridPanel);
        frame.getContentPane().add(btnPanel, BorderLayout.PAGE_END);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

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

@SuppressWarnings("serial")
class GridPanel extends JPanel {
    private static final int ROWS = 10;
    private static final int CELL_WIDTH = 28;
    private static final int PAD = 20;
    private static final int PREF_W = ROWS * CELL_WIDTH + 2 * PAD;
    private static final int PREF_H = PREF_W;
    private static final Color GRID_COLOR = Color.blue;
    private static final Color CIRCLE_COLOR = Color.red;
    private static final int SML_GAP = 2;
    private boolean[][] grid = new boolean[ROWS][ROWS];

    public GridPanel() {
        addMouseListener(new MyMouse());
    }

    @Override
    public Dimension getPreferredSize() {
        if (isPreferredSizeSet()) {
            return super.getPreferredSize();
        }
        return new Dimension(PREF_W, PREF_H);
    }

    public void reset() {
        grid = new boolean[ROWS][ROWS]; // fills grid with false
        repaint();
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D)g;
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        // draw grid:
        g2.setColor(GRID_COLOR);
        for (int i = 0; i <= ROWS; i++) {
            int x1 = PAD + i * CELL_WIDTH;
            int y1 = PAD;
            int x2 = x1;
            int y2 = PAD + CELL_WIDTH * ROWS;
            g2.drawLine(x1, y1, x2, y2);
            g2.drawLine(y1, x1, y2, x2);
        }

        // iterate through the grid boolean array
        // draw red circles if the grid value is true.
        g2.setColor(CIRCLE_COLOR);
        int w = CELL_WIDTH - 2 * SML_GAP; // width of the circle to draw
        int h = w;
        // nested for loop to go through the grid array
        for (int r = 0; r < grid.length; r++) {
            for (int c = 0; c < grid[r].length; c++) {
                if (grid[r][c]) {
                    int x = PAD + c * CELL_WIDTH + SML_GAP;
                    int y = PAD + r * CELL_WIDTH + SML_GAP;
                    g2.fillOval(x, y, w, h);
                }
            }
        }        
    }

    private class MyMouse extends MouseAdapter {
        public void mousePressed(MouseEvent e) {
            int x = e.getPoint().x;
            int y = e.getPoint().y;

            if (x < PAD || y < PAD) {
                // clicked above or to right of grid
                return;
            }

            int r = (y - PAD) / CELL_WIDTH;
            int c = (x - PAD) / CELL_WIDTH;

            // if clicked to right or below grid.
            // the < 0 part is likely unnecessary, but why not be extra safe?
            if (r >= ROWS || c >= ROWS || r < 0 || c < 0) {
                return;
            }
            grid[r][c] = true;
            repaint();
        }
    }
}

이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.

침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제

에서 수정
0

몇 마디 만하겠습니다

0리뷰
로그인참여 후 검토

관련 기사

분류에서Dev

NuxtJS 페이지가 두 번 생성됩니다.

분류에서Dev

두 번 이상 생성되는 사용자

분류에서Dev

생성자가 두 번 호출되는 이유

분류에서Dev

생성자가 두 번 호출되는 이유

분류에서Dev

Java에서 생성자를 두 번 사용하는 이유

분류에서Dev

Java에서 생성자를 두 번 사용하는 이유

분류에서Dev

Android SQLite-한 번에 두 개의 테이블 생성

분류에서Dev

두 번의 클릭을 추적 한 다음 이미지 생성

분류에서Dev

JavaScript로 생성 된 버튼, 버튼이 다시 생성 될 때 on click 이벤트가 두 번 발생합니다.

분류에서Dev

첫 번째 생성자로 두 번째 생성자 실행

분류에서Dev

JPanel을 바꾸면 두 번째 JPanel이 표시되지 않습니다.

분류에서Dev

클릭 이벤트를 두 번 생성하는 함수를 실행하면 한 번의 클릭으로 두 번 클릭 이벤트가 발생합니다.

분류에서Dev

생성자에서 InitializeComponent () 두 번 호출

분류에서Dev

두 번째로 "JHipster-UML"생성

분류에서Dev

이 생성자가 두 번 호출되는 이유는 무엇입니까?

분류에서Dev

"범위 지정"서비스의 생성자가 두 번 이상 호출 됨

분류에서Dev

생성자 또는 ngOnInit를 두 번 이상 실행하는 방법

분류에서Dev

컨트롤러가 두 번 생성되는 이유는 무엇입니까?

분류에서Dev

두 번째 파티션에 스왑 파일이 생성되지 않음

분류에서Dev

JSF : 페이지의 초기로드시 두 번 호출되는 Bean 생성자

분류에서Dev

JSF : 페이지의 초기로드시 두 번 호출되는 Bean 생성자

분류에서Dev

두 번째 스레드를 사용하여 Java 게임용 데이터 생성

분류에서Dev

.done 콜백으로 인해 JQuery Ajax 성공이 두 번 발생했습니다.

분류에서Dev

.done 콜백으로 인해 JQuery Ajax 성공이 두 번 발생했습니다.

분류에서Dev

Android에서 두 개 이상의 전화 번호로 연락처 생성

분류에서Dev

두 번째 방문시 속성 값을 생략하는 JSP 페이지

분류에서Dev

다른 앱에서 열면 동일한 활동이 두 번 생성됩니다.

분류에서Dev

ngStyle이 두 번 활성화됩니다.

분류에서Dev

생성 된 출력 당 두 번이 아니라 한 번 API를 호출하는 방법이 있습니까?

Related 관련 기사

  1. 1

    NuxtJS 페이지가 두 번 생성됩니다.

  2. 2

    두 번 이상 생성되는 사용자

  3. 3

    생성자가 두 번 호출되는 이유

  4. 4

    생성자가 두 번 호출되는 이유

  5. 5

    Java에서 생성자를 두 번 사용하는 이유

  6. 6

    Java에서 생성자를 두 번 사용하는 이유

  7. 7

    Android SQLite-한 번에 두 개의 테이블 생성

  8. 8

    두 번의 클릭을 추적 한 다음 이미지 생성

  9. 9

    JavaScript로 생성 된 버튼, 버튼이 다시 생성 될 때 on click 이벤트가 두 번 발생합니다.

  10. 10

    첫 번째 생성자로 두 번째 생성자 실행

  11. 11

    JPanel을 바꾸면 두 번째 JPanel이 표시되지 않습니다.

  12. 12

    클릭 이벤트를 두 번 생성하는 함수를 실행하면 한 번의 클릭으로 두 번 클릭 이벤트가 발생합니다.

  13. 13

    생성자에서 InitializeComponent () 두 번 호출

  14. 14

    두 번째로 "JHipster-UML"생성

  15. 15

    이 생성자가 두 번 호출되는 이유는 무엇입니까?

  16. 16

    "범위 지정"서비스의 생성자가 두 번 이상 호출 됨

  17. 17

    생성자 또는 ngOnInit를 두 번 이상 실행하는 방법

  18. 18

    컨트롤러가 두 번 생성되는 이유는 무엇입니까?

  19. 19

    두 번째 파티션에 스왑 파일이 생성되지 않음

  20. 20

    JSF : 페이지의 초기로드시 두 번 호출되는 Bean 생성자

  21. 21

    JSF : 페이지의 초기로드시 두 번 호출되는 Bean 생성자

  22. 22

    두 번째 스레드를 사용하여 Java 게임용 데이터 생성

  23. 23

    .done 콜백으로 인해 JQuery Ajax 성공이 두 번 발생했습니다.

  24. 24

    .done 콜백으로 인해 JQuery Ajax 성공이 두 번 발생했습니다.

  25. 25

    Android에서 두 개 이상의 전화 번호로 연락처 생성

  26. 26

    두 번째 방문시 속성 값을 생략하는 JSP 페이지

  27. 27

    다른 앱에서 열면 동일한 활동이 두 번 생성됩니다.

  28. 28

    ngStyle이 두 번 활성화됩니다.

  29. 29

    생성 된 출력 당 두 번이 아니라 한 번 API를 호출하는 방법이 있습니까?

뜨겁다태그

보관