JPanel定位不正确

我用Java做了一个游戏,你应该在1-100之间猜测一个随机生成的int。 如果你猜得太低,一个文本字段将填充一个文字,上面写着“太低”但是用瑞典语。 如果你猜得太高也一样。

当答案是正确的时候会出现问题,然后我调用一个方法来制作一个不可见的JPanel,可见。 这样做很好,但Jpanel本身不会移动到它应该是的顶部。 它需要完美贴合,因为它只是背景的照片拼图。 背景的属性是:1920 x 1080.Phothopped GG WP的属性是1920 x 297.Jpane被称为“grattis”

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

PS。 对不起英文和格式错误。

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://sofzh.miximages.com/java/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(); } 

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

这是游戏的几个屏幕截图。

猜猜比赛1

猜猜比赛2

我使用模型/视图/控制器模式来编写项目代码。 这将问题分开,并且更容易一次关注项目的一部分。

这是我使用的图像。

背景图片

胜利形象

这是Eclipse的Package Explorer,展示了Java Swing项目的组织。

Eclipse Package Explorer

这是代码。 我写了一个模型类和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线程 (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构建路径中的images文件夹中读取图像。 这确保了可以从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方法中,您会注意到我使用了null布局。 空布局只能在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应用程序的代码。