java - 如何使用 Swing 制作一个 GUI,从列表中选择两个元素并向用户显示两个按钮,以便他们选择获胜者?
问题描述
我正在处理我想要排名的元素列表。理想情况下,程序会随机选择 2 个元素进行比较并呈现它们,使用新排名对列表进行排序,然后再选择 2 个,这样用户就可以一遍又一遍地选择获胜者,直到用户想要停止。我遇到问题的部分是:
- 让按钮与对象交互以更改其排名和
- 让 JFrame 关闭并重新打开新元素进行比较
我创建了一个名为 action 的类,它应该处理点击:
public class action extends JFrame implements ActionListener{
private JButton b1;
private JButton b2;
private JButton b3;
private JPanel jp;
public action(Bond one, Bond two){
//JFrame mf = new JFrame("My Frame");
//JPanel jp = new JPanel();
jp = new JPanel();
setSize(500,500);
setVisible(true);
setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);
b1 = new JButton(one.name+"\nRating: "+one.rating);
b1.addActionListener(this);
b2 = new JButton(two.name);
b2.addActionListener(this);
b3 = new JButton("Tie");
b3.addActionListener(this);
jp.add(b1);
jp.add(b2);
jp.add(b3);
add(jp);
}
public void actionPerformed(ActionEvent e){
int clickCount = 0;
if (clickCount > 3) {
System.exit(0);
}
JOptionPane jo = new JOptionPane();
if(e.getSource() == b1){
// jo.showMessageDialog(null, "button 1");
clickCount++;
//System.exit(0);
}
if(e.getSource() == b2){
jo.showMessageDialog(null, "button 2");
clickCount++;
//System.exit(0);
}
if(e.getSource() == b3){
jo.showMessageDialog(null, "button 3");
clickCount++;
//System.exit(0);
}
}
}
以下是我从我的主要调用动作类的方式:
while(compCount < 3){
//these generate random numbers that correspond with the index of the elements to be compared
//comp is the name of the list of objects
int r1 = r.nextInt(comp.size());
int r2 = r.nextInt(comp.size());
int t;
if(r1 == r2){
continue;
}
else{
action a = new action(comp.get(r1), comp.get(r2));
compCount++;
}
}
目前,这只会创建 3 个弹出窗口,当我单击按钮时它们什么都不做。任何帮助或见解将不胜感激!
解决方案
OP 想要制作一个复杂的 Swing GUI。他没有提供最小的、可运行的示例,所以我创建了自己的示例。
制作复杂的 Swing GUI 的最佳方式是一次构建一小块。通过单独测试每个小块,您也可以构建一个复杂的 GUI。
这是我创建的 GUI。
这个游戏的目的是从英文字母的小写字符中选择你最喜欢的字符。如果两个角色都不是您的最爱,您可以左键单击“通过”按钮。
我已经编写了JPanel
以显示先前Stack Overflow 答案的字符。
我做的第一件事是创建主类。我命名了这个类FavoriteCharacter
。
我调用了该SwingUtilities
invokeLater
方法以确保在Event Dispatch Thread上创建和执行 Swing 组件。
接下来,我编写了JFrame
代码。对于JFrame
我创建的每个 Swing GUI,代码几乎相同。JFrame
代码位于类的方法run
中FavoriteCharacter
。
接下来,我写了模型类,LetterMap
类。每当我创建一个复杂的 Swing GUI 时,我都会使用模型/视图/控制器模式。这个模型非常简单。我有一张地图,其中包含英文字母的小写字符以及投票计数。
一旦我让模型工作,我就回去创建视图。GUI 的每一小部分都包含在FavoriteCharacter
类的一个方法中。这样,我可以单独测试视图的每一小块。没有把意大利面条代码扔在墙上,看看什么对我有用。
角色的实际绘制发生在LetterPanel
课堂上。所有 Swing 自定义绘画都必须paintComponent
以JPanel
.
完成 GUI 后,我处理了两个控制器类PassListener
和VoteListener
. PassListener
调用FavoriteCharacters
类中的方法来选择另一对字符。 VoteListener
更新LetterMap
模型类,显示 a 中所选字符的投票总数JOptionPane
,并选择另一对字母。
这是可运行的示例代码。
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.TreeMap;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class FavoriteCharacter implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new FavoriteCharacter());
}
private char[] letterPair;
private JFrame frame;
private LetterMap letterMap;
private LetterPanel letterPanel1;
private LetterPanel letterPanel2;
public FavoriteCharacter() {
this.letterMap = new LetterMap();
this.letterPair = letterMap.pickTwo();
}
@Override
public void run() {
frame = new JFrame("Favorite Character");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createTitlePanel(),
BorderLayout.BEFORE_FIRST_LINE);
frame.add(createMainPanel(letterPair),
BorderLayout.CENTER);
frame.add(createSkipPanel(),
BorderLayout.AFTER_LAST_LINE);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JPanel createTitlePanel() {
JPanel panel = new JPanel();
JLabel label = new JLabel("Vote for your favorite character");
label.setHorizontalAlignment(JLabel.CENTER);
panel.add(label);
return panel;
}
private JPanel createMainPanel(char[] letterPair) {
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.LINE_AXIS));
panel.add(Box.createHorizontalStrut(10));
letterPanel1 = new LetterPanel(Color.WHITE, letterPair[0]);
panel.add(createLetterPanel(letterPanel1, "0"));
panel.add(Box.createHorizontalStrut(10));
letterPanel2 = new LetterPanel(Color.WHITE, letterPair[1]);
panel.add(createLetterPanel(letterPanel2, "1"));
panel.add(Box.createHorizontalStrut(10));
return panel;
}
private void updateLetterPanels() {
letterPanel1.setLetter(letterPair[0]);
letterPanel2.setLetter(letterPair[1]);
letterPanel1.repaint();
letterPanel2.repaint();
}
private void updateLetterPair() {
letterPair = letterMap.pickTwo();
System.out.println(Arrays.toString(letterPair));
updateLetterPanels();
}
private JPanel createLetterPanel(LetterPanel letterPanel,
String actionCommand) {
JPanel panel = new JPanel();
panel.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.anchor = GridBagConstraints.CENTER;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.gridx = 0;
gbc.gridy = 0;
gbc.insets = new Insets(0, 10, 10, 10);
gbc.weightx = 0d;
panel.add(letterPanel, gbc);
gbc.gridy++;
gbc.weightx = 1d;
JButton button = new JButton("Vote");
button.setActionCommand(actionCommand);
button.setHorizontalAlignment(JButton.CENTER);
button.addActionListener(new VoteListener());
panel.add(button, gbc);
return panel;
}
private JPanel createSkipPanel() {
JPanel panel = new JPanel();
panel.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.anchor = GridBagConstraints.CENTER;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.gridx = 0;
gbc.gridy = 0;
gbc.insets = new Insets(0, 18, 10, 18);
gbc.weightx = 1d;
JButton button = new JButton("Pass");
button.setHorizontalAlignment(JButton.CENTER);
button.addActionListener(new PassListener());
panel.add(button, gbc);
return panel;
}
public class LetterPanel extends JPanel {
private static final long serialVersionUID = 1L;
private char letter;
private Color backgroundColor;
private Font font;
public LetterPanel(Color backgroundColor, char letter) {
this.backgroundColor = backgroundColor;
this.letter = letter;
this.font = getFont().deriveFont(96f)
.deriveFont(Font.BOLD);
this.setBorder(BorderFactory.createLineBorder(
Color.GREEN, 6));
this.setPreferredSize(new Dimension(120, 200));
}
public void setLetter(char letter) {
this.letter = letter;
}
public char getLetter() {
return letter;
}
public LetterPanel getLetterPanel() {
return this;
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(backgroundColor);
g2d.fillRect(0, 0, getWidth(), getHeight());
g2d.setColor(Color.BLACK);
drawCenteredString(g2d, Character.toString(letter),
font);
}
/**
* Draw a String centered in the middle of the panel.
*
* @param g2d The Graphics2D instance.
* @param text The String to draw.
* @param font The Font to draw with.
*/
public void drawCenteredString(Graphics2D g2d,
String text, Font font) {
FontMetrics metrics = g2d.getFontMetrics(font);
int x = (getWidth() - metrics.stringWidth(text)) / 2;
int y = ((getHeight() - metrics.getHeight()) / 2) +
metrics.getAscent();
g2d.setFont(font);
g2d.drawString(text, x, y);
}
}
public class PassListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent event) {
updateLetterPair();
}
}
public class VoteListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent event) {
int index = Integer.valueOf(event.getActionCommand());
char c = letterPair[index];
letterMap.addVote(c);
int votes = letterMap.getVotes(c);
showMessageDialog(c, votes);
}
private void showMessageDialog(char c, int votes) {
String text = "The character '" + c + "' has ";
text += Integer.toString(votes);
if (votes == 1) {
text += " vote.";
} else {
text += " votes.";
}
JOptionPane.showMessageDialog(frame, text);
updateLetterPair();
}
}
public class LetterMap {
private Map<Character, Integer> letterMap;
private Random random;
public LetterMap() {
this.letterMap = createLetterMap();
this.random = new Random();
}
private Map<Character, Integer> createLetterMap() {
Map<Character, Integer> letterMap = new TreeMap<>();
for (int i = 0; i < 26; i++) {
Character c = (char) (i + 'a');
letterMap.put(c, 0);
}
return letterMap;
}
public char[] pickTwo() {
int index1 = random.nextInt(letterMap.size());
int index2 = random.nextInt(letterMap.size());
while (index2 == index1) {
index2 = random.nextInt(letterMap.size());
}
char[] output = new char[2];
Set<Character> letterSet = letterMap.keySet();
Iterator<Character> iter = letterSet.iterator();
int count = 0;
int index3 = 0;
while (iter.hasNext() && index3 < 2) {
Character key = iter.next();
if (count == index1 || count == index2) {
if (index3 < 2) {
output[index3++] = key;
}
}
count++;
}
return output;
}
public void addVote(char c) {
Integer vote = getVotes(c);
letterMap.put(c, ++vote);
}
public int getVotes(char c) {
return letterMap.get(c);
}
}
}
推荐阅读
- javascript - Javascript - 获取
- python - 拆分文件 .log 字段以在 Dataframe 中使用
- google-apps-script - 谷歌工作表应用程序脚本如何复制具有相同权限的选项卡
- compatibility - 尝试使用 GeckoView 制作浏览器时出现 java.lang.ClassNotFoundException
- javascript - react中useEffect钩子的执行顺序是什么?
- perforce - 如何 p4 将文件从仓库复制到我的密码?
- c# - 获取非项目文件的 FileCodeModel
- python - 为什么这个网页抓取脚本不起作用?
- python - Selenium ActionChains 将光标移动到下拉对象并在其后面单击
- spring-boot - 如何配置 kubernetes 以允许将 ConfingMaps 与 SpringBoot 一起使用