【问题标题】:JPanel positioned incorrectlyJPanel 定位不正确
【发布时间】:2014-05-05 02:09:49
【问题描述】:

我用 Java 制作了一个游戏,您应该在其中猜测一个随机生成的 int,介于 1-100 之间。如果你猜的太低,一个文本框会填满一个“太低”的文本,但是是瑞典语。如果你猜得太高,也一样。

当答案正确时就会出现问题,然后我调用一个方法使 Invisible JPanel 可见。这工作得很好,但 Jpanel 本身不会移动到它应该在的顶部。它需要完美契合,因为它只是一张经过照片处理的背景图片。 背景的属性是:1920 x 1080。photoshopped GG WP的属性是1920 x 297。Jpane被称为“免费”

我希望我没有错过任何重要的事情,我很感激我能得到的所有帮助,因为我现在卡住了。

附言。抱歉英文和格式不好。

package slumpatal;

import java.util.Random;

//This class runs the program, the main method is here.
public class SlumpaTal extends callback1 {
    private int randomTal;
    Random random = new Random();

    @Override
    public int SetValue(int value) {
        if (value < randomTal)
            return -1;
        else if (value == randomTal)
            return 0;
        else
            return 1;

    }

    //private JFrame1 frame;
    SlumpaTal() {
        GenerateRandomNumber();
        JFrame1.createWindow(this);
    }

    public void GenerateRandomNumber() {
        randomTal = random.nextInt(100) + 1;
    }

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

.

package slumpatal;


import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;


public class JFrame1 {
    //public  static int dittSvar;
    public static void createWindow(callback1 callbackArg) {

        //Font font = new Font("Verdana", Font.BOLD,28);

        JFrame frame = new JFrame("Gissa ett Tal mellan 1-100");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JPanel contentPane = new JPanel();
        contentPane.setOpaque(true);
        contentPane.setBorder(BorderFactory.createMatteBorder(5, 5, 5, 5, Color.WHITE));
        contentPane.setBackground(Color.WHITE);
        contentPane.setLayout(new BorderLayout(10, 10));

        ImagePanel imagePanel = new ImagePanel(callbackArg);


        //frame properties


        contentPane.add(imagePanel, BorderLayout.CENTER);
        frame.setContentPane(contentPane);
        frame.setSize(1000, 600);
        frame.setVisible(true);
    }
}


class ImagePanel extends JPanel

{
    callback1 callback;
    public int dittSvar;
    private BufferedImage image;
    JButton restartApp;
    JTextField dittSvarText1;
    JTextField dittRes1;
    BufferedImage myPicture;
    public JPanel grattis;

    public ImagePanel(callback1 callbackArg) {
        try {
            myPicture = ImageIO.read(new URL("https://imagizer.imageshack.us/v2/1375x213q90/843/r7f8.jpg"));
        } catch (Exception ex) {
            System.err.print("No reward image");
        }
        callback = callbackArg;
        setOpaque(true);
        setBorder(BorderFactory.createLineBorder(Color.BLACK, 5));
        try {
            image = ImageIO.read(new URL("http://imageshack.com/a/img835/193/v8k3.jpg"));
        }
        //If it doesn't work, write an error message, printStackTrace.
        catch (IOException e) {
            System.err.printf("%s", e.toString());
            e.printStackTrace();
        }
        createGUI();
        createGUI2();

        dittSvarText1.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                dittSvar = Integer.parseInt(dittSvarText1.getText());
                int res = callback.SetValue(dittSvar);
                if (res < 0)
                    dittRes1.setText("För lågt");
                else if (res == 0) {
                    dittRes1.setText("Rätt Svar!!!!");
                    makeItVisible();
                } else
                    dittRes1.setText("För Högt");
                dittSvarText1.setText("");
            }
        });
        restartApp.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                callback.GenerateRandomNumber();
                dittSvarText1.setText(null);
                dittRes1.setText(null);
                grattis.setVisible(false);

            }
        });
    }

    public void makeItVisible() {
        System.out.print("Showing reward image");
        grattis = new JPanel();
        grattis.setOpaque(false);
        grattis.setLayout(new FlowLayout(FlowLayout.LEFT));


        if (myPicture != null) {
            JLabel picLabel = new JLabel(new ImageIcon(myPicture));

            //picLabel.setLocation(new Point(0,0));
            picLabel.setLocation(new Point(0, 0));
            // picLabel.setSize(1000,297);
            // grattis.setLocation(0, 0);
            picLabel.setVerticalAlignment(WIDTH);
            grattis.setVisible(true);
            grattis.setSize(1000, 600);

            grattis.add(picLabel);
            add(grattis);
            updateUI();
        } else {
            System.err.print("No picture created!");
        }


    }

    public void createGUI() {
        setLayout(new GridBagLayout());
        JPanel panel1 = new JPanel();

        panel1.setOpaque(false);
        panel1.setLayout(new GridLayout(2, 2, 2, 2));
        JLabel skrivdingissning = new JLabel("Skriv din gissning här : ");
        skrivdingissning.setForeground(Color.WHITE);
        dittSvarText1 = new JTextField(10);
        JLabel VadBlevDet = new JLabel("Vad blev det : ");
        VadBlevDet.setForeground(Color.WHITE);
        dittRes1 = new JTextField(10);


        panel1.add(skrivdingissning);
        panel1.add(dittSvarText1);
        panel1.add(VadBlevDet);
        panel1.add(dittRes1);

        add(panel1);

    }

    public void createGUI2() {

        JPanel panel2 = new JPanel();

        panel2.setLocation(100, 500);
        panel2.setOpaque(false);
        restartApp = new JButton("Starta om");
        restartApp.setLocation(100, 500);
        restartApp.setBackground(Color.WHITE);

        panel2.add(restartApp);

        // add(panel2);
    }


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

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        //g.drawImage(image, 0,0,this);
    }
}

abstract class callback1 {
    abstract int SetValue(int value);

    abstract void GenerateRandomNumber();

}

【问题讨论】:

  • 对于有关面板定位的问题,所有这些代码真的必要吗?见How to create a Minimal, Complete, and Verifiable example。请做。关键字是Minimum。并且请尝试正确缩进您的代码以使其更具可读性。在目前的状态下,它也可能是俄语
  • 由于格式化而投反对票。伙计,如果有人应该帮助你,请认真地给他详细信息(只有必要的)并格式化它们,以便他可以轻松阅读。
  • 来自@HenryKitchener 的评论:能否请您提供一个示例图片,我们不知道“不会移动到它应该在的顶部” i> 表示,顶部在哪里?
  • 查看CardLayout,而不是将面板设置为可见。对于该职位,可能就像在相关面板中添加EmtpyBorder 一样简单。但要获得更多帮助,请按照@peeskillet 的建议发布 MCVE。
  • 我将您的代码提取到 Eclipse 中并让它运行。图片是在线的。伙计,你的图像对于 1 - 100 的猜谜游戏来说是巨大的。将它们降低到 640 x 480,以便它们适合大多数人的屏幕。您的代码的排列方式对我这个 Swing 开发人员来说非常陌生,以至于我不得不从头开始重写您的代码。哦,还有灰色标签上的白色?你听说过对比吗?

标签: java image swing jpanel jlabel


【解决方案1】:

我重写了你的整个项目。您可以将英语翻译成瑞典语。

这里有几张游戏截图。

我使用model / view / controller pattern 对项目进行编码。这将关注点分开,并更容易一次专注于项目的一个部分。

这是我使用的图片。

这是来自 Eclipse 的 Package Explorer,显示了 Java Swing 项目的组织结构。

这是代码。我写了一个模型类和 4 个视图类。控制器是其中一个视图类中的匿名类。

这是主要的 GuessingGame 类。

package com.ggl.guessing.game;

import javax.swing.SwingUtilities;

import com.ggl.guessing.game.model.GuessingGameModel;
import com.ggl.guessing.game.view.GuessingGameFrame;

public class GuessingGame implements Runnable {

    @Override
    public void run() {
        new GuessingGameFrame(new GuessingGameModel(1, 100));

    }

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

}

短而甜。这个类做了 3 件事。

  1. 通过调用 SwingUtilities invokeLater 方法将 Swing GUI 置于 Event Dispatch thread (EDT) 上。
  2. 实例化 GUI 模型。
  3. 实例化 GUI JFrame。

接下来,我们看看模型类

package com.ggl.guessing.game.model;

import java.util.Random;

public class GuessingGameModel {

    private int lowerLimit;
    private int upperLimit;
    private int randomNumber;
    private int numberOfGuesses;


    private Random random;

    public GuessingGameModel(int lowerLimit, int upperLimit) {
        this.random = new Random();
        init(lowerLimit, upperLimit);
    }

    public void init(int lowerLimit, int upperLimit) {
        this.lowerLimit = lowerLimit;
        this.upperLimit = upperLimit;
        this.numberOfGuesses = 0;
        this.randomNumber = random.nextInt(upperLimit - lowerLimit + 1) 
                + lowerLimit;
    }

    public int guess(int guess) {
        this.numberOfGuesses++;
        if (guess < randomNumber) {
            return -1;
        } else if (guess > randomNumber) {
            return 1;
        } else {
            return 0;
        }
    }

    public int getNumberOfGuesses() {
        return numberOfGuesses;
    }

    public String getFrameTitle() {
        return "Gissa ett Tal mellan " + lowerLimit + " - "
                + upperLimit;
    }
}

该类保存游戏信息,并为标题提供方便的方法。您可以设置随机数的下限和上限,以便将来添加不同的范围。

现在,让我们来看看 GUI 本身。这是 GuessingGameFrame 类。

package com.ggl.guessing.game.view;

import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.JFrame;
import javax.swing.JPanel;

import com.ggl.guessing.game.model.GuessingGameModel;

public class GuessingGameFrame {

    private GameImages gameImages;

    private GuessingGameModel model;

    private GuessingGamePanel ggPanel;

    private JFrame frame;

    public GuessingGameFrame(GuessingGameModel model) {
        this.model = model;
        this.gameImages = new GameImages();
        createPartControl();
    }

    private void createPartControl() {
        frame = new JFrame();
        frame.setTitle(model.getFrameTitle());
        frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
        frame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent event) {
                exitProcedure();
            }
        });

        Dimension d = sizeGuessesPanel();

        ggPanel = new GuessingGamePanel(this, model, gameImages, d);
        JPanel mainPanel = new JPanel();
        mainPanel.setLayout(new FlowLayout());
        mainPanel.add(ggPanel);

        frame.setLayout(new FlowLayout());
        frame.add(mainPanel);
//      frame.setSize(640, 480);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    private Dimension sizeGuessesPanel() {
        GuessesPanel guessesPanel = new GuessesPanel(this, model);
        frame.setLayout(new FlowLayout());
        frame.add(guessesPanel.getPanel());
        frame.pack();
        Dimension d = guessesPanel.getPanel().getSize();
        guessesPanel.setPreferredSize(d);
        frame.remove(guessesPanel.getPanel());
        return d;
    }

    public void exitProcedure() {
        frame.dispose();
        System.exit(0);
    }

    public void setGuessed(boolean guessed) {
        ggPanel.setGuessed(guessed);
    }

}

相当标准的 Swing,除了 sizeGuessesPanel 方法。为了将面板放在背景图像的中心,我需要知道它有多大。 sizeGuessesPanel 使用 JFrame 包装来告诉我尺寸。

setGuessed 方法是一种方便的方法,它允许我在 JPanel 上设置布尔标志来绘制胜利图像。控制器不需要知道 JPanel。

接下来,我们来看看 GameImages 类。

package com.ggl.guessing.game.view;

import java.awt.Dimension;
import java.awt.Image;
import java.io.IOException;
import java.net.URL;

import javax.imageio.ImageIO;

public class GameImages {

    private Image backgroundImage;
    private Image victoryImage;

    public GameImages() {
        readBackgroundImage();
        readVictoryImage();
    }

    private void readBackgroundImage() {
        Image image = null;
        try {
            URL url = getClass().getResource("/v8k3reduced.jpg");
            image = ImageIO.read(url);
        } catch (IOException e) {
            e.printStackTrace();
        }
        this.backgroundImage = image;
    }

    private void readVictoryImage() {
        Image image = null;
        try {
            URL url = getClass().getResource("/r7f8reduced.jpg");
            image = ImageIO.read(url);
        } catch (IOException e) {
            e.printStackTrace();
        }
        this.victoryImage = image;
    }

    public Image getBackgroundImage() {
        return backgroundImage;
    }

    public Dimension getPreferredSize() {
        return new Dimension(backgroundImage.getWidth(null),
                backgroundImage.getHeight(null));
    }

    public Image getVictoryImage() {
        return victoryImage;
    }

}

此类从位于 Java 构建路径中的图像文件夹中读取图像。这确保了可以从 Eclipse 中读取图像以及图像何时被读取。 打包在 Java 归档文件 (JAR) 中。

接下来,我们来看看 GuessingGamePanel。

package com.ggl.guessing.game.view;

import java.awt.Dimension;
import java.awt.Graphics;

import javax.swing.JPanel;

import com.ggl.guessing.game.model.GuessingGameModel;

public class GuessingGamePanel extends JPanel {

    private static final long   serialVersionUID    = 
            -2429103448910749064L;

    private boolean guessed;

    private Dimension guessesPanelDimension;

    private GameImages gameImages;

    private GuessesPanel guessesPanel;

    private GuessingGameFrame frame;

    private GuessingGameModel model;

    public GuessingGamePanel(GuessingGameFrame frame,
            GuessingGameModel model, GameImages gameImages, 
            Dimension guessesPanelDimension) {
        this.frame = frame;
        this.model = model;
        this.gameImages = gameImages;
        this.guessesPanelDimension = guessesPanelDimension;
        this.guessed = false;

        createPartControl();
    }

    private void createPartControl() {
        this.setLayout(null);
        this.setPreferredSize(gameImages.getPreferredSize());

        guessesPanel = new GuessesPanel(frame, model);
        Dimension gp = guessesPanelDimension;
        Dimension tp = gameImages.getPreferredSize();
        int x = (tp.width - gp.width) / 2;
        int y = (tp.height - gp.height) / 2;
        guessesPanel.getPanel().setBounds(x, y, gp.width, gp.height);
        this.add(guessesPanel.getPanel());
    }

    public void setGuessed(boolean guessed) {
        this.guessed = guessed;
        repaint();
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);

        g.drawImage(gameImages.getBackgroundImage(), 0, 0, null);
        if (guessed) {
            g.drawImage(gameImages.getVictoryImage(), 0, 0, null);
        }
    }
}

我们扩展了一个 JPanel,因为我们覆盖了 JPanel 的paintComponent 方法。

在 createPartControl 方法中,您会注意到我使用了空布局。 只有在 Swing 专家的监督和批准下才能使用空布局。在这种情况下,这是我可以控制 GuessesPanel 的大小和位置的唯一方法。

最后,我们来看看 GuessesPanel 类。

package com.ggl.guessing.game.view;

import java.awt.Color;
import java.awt.Component;
import
 java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;

import com.ggl.guessing.game.model.GuessingGameModel;

public class GuessesPanel {

    private static final Insets finalInsets = 
            new Insets(6, 6, 6, 6);

    private Dimension preferredSize;

    private GuessingGameFrame frame;

    private GuessingGameModel model;

    private JPanel panel;

    private JTextField dittSvarText1;
    private JTextField dittRes1;
    private JTextField guessesField;

    public GuessesPanel(GuessingGameFrame frame,
            GuessingGameModel model) {
        this.frame = frame;
        this.model = model;
        createPartControl();
    }

    private void createPartControl() {
        panel = new JPanel();
        panel.setBackground(Color.YELLOW);
        panel.setLayout(new FlowLayout());

        JPanel insidePanel = new JPanel();
        insidePanel.setLayout(new GridBagLayout());

        int gridy = 0;

        JLabel guessLabel = new JLabel("Skriv din gissning här:");
        addComponent(insidePanel, guessLabel, 0, gridy, 1, 1,
                finalInsets, GridBagConstraints.LINE_START,
                GridBagConstraints.NONE);

        dittSvarText1 = new JTextField(10);
        dittSvarText1.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent event) {
                int guess = Integer.valueOf(dittSvarText1.getText());
                int lowHigh = model.guess(guess);
                if (lowHigh < 0) {
                    dittRes1.setText("För lågt");
                } else if (lowHigh > 0) {
                    dittRes1.setText("För Högt");
                } else {
                    dittRes1.setText("Rätt Svar!!!!");
                    frame.setGuessed(true);
                }
                guessesField.setText(Integer.toString(
                        model.getNumberOfGuesses()));
                dittSvarText1.setSelectionStart(0);
                dittSvarText1.setSelectionEnd(
                        dittSvarText1.getText().length());
            }   
        });
        addComponent(insidePanel, dittSvarText1, 1, gridy++, 1, 1,
                finalInsets, GridBagConstraints.LINE_START,
                GridBagConstraints.NONE);

        JLabel responseLabel = new JLabel("Vad blev det:");
        addComponent(insidePanel, responseLabel, 0, gridy, 1, 1,
                finalInsets, GridBagConstraints.LINE_START,
                GridBagConstraints.NONE);

        dittRes1 = new JTextField(10);
        dittRes1.setEditable(false);
        addComponent(insidePanel, dittRes1, 1, gridy++, 1, 1,
                finalInsets, GridBagConstraints.LINE_START,
                GridBagConstraints.NONE);

        JLabel guessesLabel = new JLabel("Number of guesses:");
        addComponent(insidePanel, guessesLabel, 0, gridy, 1, 1,
                finalInsets, GridBagConstraints.LINE_START,
                GridBagConstraints.NONE);

        guessesField = new JTextField(10);
        guessesField.setEditable(false);
        addComponent(insidePanel, guessesField, 1, gridy++, 1, 1,
                finalInsets, GridBagConstraints.LINE_START,
                GridBagConstraints.NONE);

        panel.add(insidePanel);
    }

    private void addComponent(Container container, Component component,
            int gridx, int gridy, int gridwidth, int gridheight, 
            Insets insets, int anchor, int fill) {
        GridBagConstraints gbc = new GridBagConstraints(gridx, gridy,
                gridwidth, gridheight, 1.0D, 1.0D, anchor, fill, 
                insets, 0, 0);
        container.add(component, gbc);
    }

    public void setPreferredSize(Dimension preferredSize) {
        panel.setPreferredSize(preferredSize);
        panel.setMaximumSize(preferredSize);
        panel.setMinimumSize(preferredSize);
        this.preferredSize = preferredSize;
    }

    public Dimension getPreferredSize() {
        return preferredSize;
    }

    public JPanel getPanel() {
        return panel;
    }

}

这是一个使用 GridBagLayout 的非常标准的 JPanel。 addComponent 方法为每个 Swing 组件创建一个 GridBagConstraints。 GridBagLayout 是您想要排列标签和字段时使用的布局。

主要且唯一的控制器是此类内部的匿名操作侦听器类。

我创建的类比你多,代码的排列方式也与你不同。研究代码,看看它是否有助于您更好地理解 MVC,以及如何编写 Swing 应用程序。

【讨论】:

  • 哇,这太棒了!我真的很感谢你花时间做这件事。我很抱歉我的坏问题。我一定会研究这段代码以及你如何组织一切。我无法描述这对我来说意味着什么,我对你的感激不尽。再次感谢您!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-23
相关资源
最近更新 更多