ОП хочет сделать сложный Swing GUI. Он не предоставил минимального, работоспособного примера, поэтому я создал свой собственный.
Лучший способ создать сложный Swing GUI - это построить его по одной маленькой части за раз. Тестируя каждый маленький кусок по отдельности, вы тоже можете построить сложный GUI.
Вот созданный мной GUI.
The object of this game is to choose your favorite characters from the lower case characters of the English alphabet. You can left-click on the Pass button if neither character is among your favorites.
I'd already written the JPanel
to display a character for a previous Ответ на переполнение стека .
Первое, что я сделал, это создал главный класс. Я назвал этот класс FavoriteCharacter
.
Я вызвал метод SwingUtilities
invokeLater
, чтобы гарантировать, что компоненты Swing были созданы и выполнены в потоке отправки событий .
Затем я написал код JFrame
. Код JFrame
почти идентичен для всех созданных мной Swing GUI. Код JFrame
находится в методе run
класса FavoriteCharacter
.
Затем я написал класс модели, класс LetterMap
. Каждый раз, когда я создаю сложный Swing GUI, я использую шаблон модель / представление / контроллер . Эта модель довольно проста. У меня есть карта, которая содержит символы нижнего регистра английского sh алфавита, а также подсчет голосов.
После того, как модель заработала, я вернулся к созданию представления. Каждая небольшая часть GUI содержится в методе класса FavoriteCharacter
. Таким образом, я мог тестировать каждую маленькую часть представления индивидуально. Не надо бросать спагетти-код об стену и смотреть, что мне нравится.
Фактическое рисование персонажей происходит в классе LetterPanel
. Все пользовательские раскраски Swing должны выполняться методом paintComponent
из JPanel
.
После того, как я закончил GUI, я работал над двумя классами контроллеров, PassListener
и VoteListener
. PassListener
вызывает метод в классе FavoriteCharacters
для выбора другой пары символов. VoteListener
обновляет модельный класс LetterMap
, отображает общее количество голосов для выбранного символа в 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);
}
}
}