How would I make a GUI using Swing that picks two elements from a list and presents the user with two buttons so they could chose the winner?

后端 未结 1 364
南方客
南方客 2021-01-26 09:01

I am working with a list of elements that I want to rank. Ideally the program would randomly choose 2 elements to compare and present them, sort the list with the new ranking, t

1条回答
  •  栀梦
    栀梦 (楼主)
    2021-01-26 09:34

    The OP wants to make a complex Swing GUI. He didn't provide a minimal, runnable, example, so I created my own.

    The best way to make a complex Swing GUI is to construct it one small piece at a time. By testing each small piece in isolation, you too can construct a complex GUI.

    Here's the GUI I created.

    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 Stack Overflow answer.

    The first thing I did was create the main class. I named this class FavoriteCharacter.

    I called the SwingUtilities invokeLater method to ensure that the Swing components were created and executed on the Event Dispatch Thread.

    Next, I wrote the JFrame code. The JFrame code is nearly identical for every Swing GUI I create. The JFrame code is located in the run method of the FavoriteCharacter class.

    Next, I wrote the model class, the LetterMap class. Whenever I create a complex Swing GUI, I use the model / view / controller pattern. This model is pretty simple. I have a map that contains the lower case characters of the English alphabet, along with vote counts.

    Once I had the model working, I went back to creating the view. Each small part of the GUI is contained in a method of the FavoriteCharacter class. That way, I could test each small piece of the view individually. No throwing spaghetti code against the wall and seeing what sticks for me.

    The actual drawing of the characters happens in a LetterPanel class. All Swing custom painting must be done in the paintComponent method of a JPanel.

    After I finished the GUI, I worked on the two controller classes, PassListener and VoteListener. PassListener calls a method in the FavoriteCharacters class to select another pair of characters. VoteListener updates the LetterMap model class, displays the vote total for the selected character in a JOptionPane, and selects another pair of letters.

    Here's the runnable, example code.

    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 letterMap;
    
            private Random random;
    
            public LetterMap() {
                this.letterMap = createLetterMap();
                this.random = new Random();
            }
    
            private Map createLetterMap() {
                Map 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 letterSet = letterMap.keySet();
                Iterator 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);
            }
    
        }
    
    }
    

    0 讨论(0)
提交回复
热议问题