使用 drawString() 不会显示字符串

String won't display using drawString()

我正在编写一个简单的问答游戏,我 运行 遇到了问题字符串无法显示的问题 在我的框架中,我使用边框布局,底部(南)有“新游戏”和“结束游戏”,中间有我的 Trivia 面板。 Trivia 面板由 2 行 1 列的网格布局组成,下半部分有 4 个答案,上半部分我使用了另一个带有边框布局的面板,中间是问题字符串,东边是分数。 它应该是这样的:

但是,除了问题字符串外,所有组件都会显示。 我的 paintComponent 是:

@Override
protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    g.setFont(font);
    g.drawString(tf,0,0);
}

其中 tf 是我的字符串,我的 Trivia 面板代码是:

public TriviaPanel(){
    score = 0;
    scoreString = new JTextField();
    scoreString.setFont(font);
    questionPanel = new JPanel();
    questionPanel.setLayout(new BorderLayout());
    questionPanel.add(scoreString,BorderLayout.EAST);
    this.setLayout(new GridLayout(2,1));
    pool = null;
    try {
        pool = new Pool();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }
    question = pool.getQuestion();
    String[] answers = question.shuffle();
    tf = question.getQuestion();
    this.add(questionPanel);
    answersPanel = new JPanel();
    answersPanel.setLayout(new GridLayout(2,2));
    buttons = new JButton[NUM_OF_ANSWERS];
    for (int i = 0; i < NUM_OF_ANSWERS; i++) {
        buttons[i] = new JButton(answers[i]);
        answersPanel.add(buttons[i]);
        buttons[i].addActionListener(lis);

    }
    this.add(answersPanel);
scoreString.setText("Score: "+score+"/"+pool.getIterator()*CORRECT);
}

其中 pool 用于存放我的问题库。 当我调试代码时,我看到 tf 字符串被更新为问题字符串,但它不会显示。 是因为坐标吗? 任何见解将不胜感激。

[编辑]虽然未完成但完整代码如下:

import java.util.Arrays;
import java.util.Collections;

public class Question {
    private final int NUM_OF_ANSWERS = 4;
    private String question;
    private String[] answers = new String[NUM_OF_ANSWERS];
    private final int CORRECT_ANSWER = 0;

    public Question(String qu, String an, String dm1, String dm2, String 
dm3){
        question = qu;
        answers[0] = an;
        answers[1] = dm1;
        answers[2] = dm2;
        answers[3] = dm3;
    }

    public String getCorrectAnswer() {
        return answers[CORRECT_ANSWER];
    }

    public String getQuestion(){
        return question;
    }

    public String[] getAnswers(){
        return answers;
    }
    public String toString(){
        String str = question;
        for (int i = 0; i<4; i++)
            str+=" "+answers[i];
        str+="\n";
        return str;
    }
    public String[] shuffle(){
        String[] shuffled = new String[NUM_OF_ANSWERS];
        for (int i=0;i<NUM_OF_ANSWERS;i++)
            shuffled[i]=answers[i];
        Collections.shuffle(Arrays.asList(shuffled));
        return shuffled;
    }
}


import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Scanner;

public class Pool {

    private ArrayList<Question> questions = new ArrayList<>();
    private Scanner input = new Scanner(new File("src/trivia.txt"));
    private static int iterator = 0;

    public Pool() throws FileNotFoundException {
        while (input.hasNext()){
            String q = input.nextLine();
            String a = input.nextLine();
            String d1 = input.nextLine();
            String d2 = input.nextLine();
            String d3 = input.nextLine();
            Question question = new Question(q,a,d1,d2,d3);
            questions.add(question);
        }
        Collections.shuffle(questions);
        //System.out.println(questions);
    }

    public Question getQuestion(){
        Question q = questions.get(iterator);
        iterator++;
        return q;
    }

    public int getSize(){
        return questions.size();
    }

    public static int getIterator() {
        return iterator;
    }
}

import javax.swing.*;
import java.awt.*;

public class GameFrame extends JFrame {
private JButton restart, finish;
private JPanel buttons;
    public GameFrame(){
        super("Trivia");
        TriviaPanel tp = new TriviaPanel();
        this.setLayout(new BorderLayout());
        this.add(tp,BorderLayout.CENTER);
        restart = new JButton("New game");
        finish = new JButton("End game");
        buttons = new JPanel();
        buttons.add(restart);
        buttons.add(finish);
        this.add(buttons,BorderLayout.SOUTH);
        this.setSize(1000,600);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
    }

    public static void main(String[] args) {
        GameFrame gf = new GameFrame();
    }

}

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.FileNotFoundException;
import java.util.concurrent.TimeUnit;

public class TriviaPanel extends JPanel {
    private TimerListener tl = new TimerListener();
    private Timer timer = new Timer(10000,tl);
    private static int score;
    private JTextField scoreString;
    private final int CORRECT = 10, INCORRECT = 5;
    private JButton[] buttons;
    private Pool pool;
    private Question question;
    private JButton pressed;
    private final int NUM_OF_ANSWERS = 4;
    private Listener lis = new Listener();
    //private JPanel questionPanel;
    private JPanel answersPanel;
    private String tf;
    private Font font = new Font("Serif",Font.BOLD,24);
    private JTextField tf2 = new JTextField();
    private QuestionPanel questionPanel;
public TriviaPanel(){
        score = 0;
        scoreString = new JTextField();
        scoreString.setFont(font);
        questionPanel = new QuestionPanel();
        //questionPanel.setLayout(new BorderLayout());
        //questionPanel.add(scoreString,BorderLayout.EAST);
        this.setLayout(new GridLayout(2,1));
        pool = null;
        try {
            pool = new Pool();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        question = pool.getQuestion();
        String[] answers = question.shuffle();
        tf = question.getQuestion();
        //tf2.setText(question.getQuestion());
        //questionPanel.add(tf2,BorderLayout.CENTER);
        this.add(questionPanel);
        answersPanel = new JPanel();
        answersPanel.setLayout(new GridLayout(2,2));
        buttons = new JButton[NUM_OF_ANSWERS];
        for (int i = 0; i < NUM_OF_ANSWERS; i++) {
            buttons[i] = new JButton(answers[i]);
            answersPanel.add(buttons[i]);
            buttons[i].addActionListener(lis);

        }
        this.add(answersPanel);
    timer.start();
    scoreString.setText("Score: "+score+"/"+pool.getIterator()*CORRECT);
    }

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

    private void next(){
        Question q = pool.getQuestion();
        question=q;
        tf = q.getQuestion();
        String[] answers = q.shuffle();
        for (int i = 0; i < NUM_OF_ANSWERS; i++)
            buttons[i].setText(answers[i]);

    }

    private void gameOver(){
        JOptionPane.showConfirmDialog(null,
                "Score: "+score, "Select an Option...", JOptionPane.YES_NO_CANCEL_OPTION);
    }

    private void check(String guess) {
        timer.stop();
        String answer = question.getCorrectAnswer();
        if (guess.equals(answer)) {
            score += CORRECT;
            tf = "Correct!!!";
        } else {
            score -= INCORRECT;
            tf = "Wrong answer";
        }
        scoreString.setText("Score: "+score+"/"+pool.getIterator()*CORRECT);
        repaint();
        try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    }

    private class QuestionPanel extends JPanel{

    public QuestionPanel(){
            this.setLayout(new BorderLayout());
            this.add(scoreString,BorderLayout.EAST);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.setFont(font);
            g.drawString(tf,0,200);
        }
    }

    private class Listener implements ActionListener{

        @Override
        public void actionPerformed(ActionEvent e) {
            pressed = (JButton) e.getSource();
            String guess = pressed.getText();
            check(guess);
            if (pool.getIterator() < pool.getSize()) {
                timer.restart();
                next();
            }
            else
                gameOver();
        }

    }

    private class TimerListener implements ActionListener{

        @Override
        public void actionPerformed(ActionEvent e) {
            timer.stop();
            score-=INCORRECT;
            scoreString.setText("Score: "+score+"/"+pool.getIterator()*CORRECT);
            repaint();
            timer.restart();
            next();
        }
    }
}

从摆脱

开始
@Override
protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    questionPanel.repaint();
}

说真的,这很危险,可能会让你陷入无限循环,消耗你的 CPU 个周期

接下来,我修改了您的 QuestionPanel,因此文本实际上呈现在概率范围内的某处...

private class QuestionPanel extends JPanel {

    public QuestionPanel() {
        this.setLayout(new BorderLayout());
        this.add(scoreString, BorderLayout.EAST);
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.setFont(font);
        FontMetrics fm = g.getFontMetrics();
        int y = ((getHeight() - fm.getHeight()) / 2) + fm.getAscent();
        g.drawString(tf, 10, y);
    }
}

但说真的,你为什么不直接使用 JLabel

现在,任何时候 tf 发生变化,您都需要调用 QuestionPanelrepaint 方法。

所以,那是在 nextcheck(String) 方法中。

最后(现在),你永远不应该...

try {
    TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
    e.printStackTrace();
}

在事件调度线程的上下文中。这会停止处理重绘,因此,整整一秒钟,什么都不会改变。

如果你想让用户停止一秒钟,请禁用按钮 and/or 其他控件并使用另一个 Swing Timer(为简单起见)

这在这个自包含、可编译和可运行的示例中得到了证明...

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.Timer;

public class Test {

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

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                GameFrame frame = new GameFrame();
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class GameFrame extends JFrame {

        private JButton restart, finish;
        private JPanel buttons;

        public GameFrame() {
            super("Trivia");
            TriviaPanel tp = new TriviaPanel();
            this.setLayout(new BorderLayout());
            this.add(tp, BorderLayout.CENTER);
            restart = new JButton("New game");
            finish = new JButton("End game");
            buttons = new JPanel();
            buttons.add(restart);
            buttons.add(finish);
            this.add(buttons, BorderLayout.SOUTH);
            this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        }

    }

    public static class TriviaPanel extends JPanel {

//        private TimerListener tl = new TimerListener();
//        private Timer timer = new Timer(10000, tl);
        private static int score;
        private JTextField scoreString;
        private final int CORRECT = 10, INCORRECT = 5;
        private JButton[] buttons;
        private Pool pool;
        private Question question;
        private JButton pressed;
        private final int NUM_OF_ANSWERS = 4;
        private Listener lis = new Listener();
        //private JPanel questionPanel;
        private JPanel answersPanel;
        private String tf;
        private Font font = new Font("Serif", Font.BOLD, 24);
        private JTextField tf2 = new JTextField();
        private QuestionPanel questionPanel;

        public TriviaPanel() {
            score = 0;
            scoreString = new JTextField();
            scoreString.setFont(font);
            questionPanel = new QuestionPanel();
            //questionPanel.setLayout(new BorderLayout());
            //questionPanel.add(scoreString,BorderLayout.EAST);
            this.setLayout(new GridLayout(2, 1));
            pool = null;
            try {
                pool = new Pool();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
            question = pool.getQuestion();
            String[] answers = question.shuffle();
            tf = question.getQuestion();
            //tf2.setText(question.getQuestion());
            //questionPanel.add(tf2,BorderLayout.CENTER);
            this.add(questionPanel);
            answersPanel = new JPanel();
            answersPanel.setLayout(new GridLayout(2, 2));
            buttons = new JButton[NUM_OF_ANSWERS];
            for (int i = 0; i < NUM_OF_ANSWERS; i++) {
                buttons[i] = new JButton(answers[i]);
                answersPanel.add(buttons[i]);
                buttons[i].addActionListener(lis);

            }
            this.add(answersPanel);
//            timer.start();
            scoreString.setText("Score: " + score + "/" + pool.getIterator() * CORRECT);
        }

//    @Override
//    protected void paintComponent(Graphics g) {
//        super.paintComponent(g);
//        questionPanel.repaint();
//    }
        private void next() {
            Question q = pool.getQuestion();
            question = q;
            tf = q.getQuestion();
            String[] answers = q.shuffle();
            for (int i = 0; i < NUM_OF_ANSWERS; i++) {
                buttons[i].setText(answers[i]);
            }
            questionPanel.repaint();
        }

        private void gameOver() {
            JOptionPane.showConfirmDialog(null,
                    "Score: " + score, "Select an Option...", JOptionPane.YES_NO_CANCEL_OPTION);
        }

        private void check(String guess) {
//            timer.stop();
            String answer = question.getCorrectAnswer();
            if (guess.equals(answer)) {
                score += CORRECT;
                tf = "Correct!!!";
            } else {
                score -= INCORRECT;
                tf = "Wrong answer";
            }
            questionPanel.repaint();
            scoreString.setText("Score: " + score + "/" + pool.getIterator() * CORRECT);
            // OH GOD THIS IS A BAD IDEA!
//            try {
//                TimeUnit.SECONDS.sleep(1);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }

            Timer timer = new Timer(1000, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    Timer timer = (Timer) e.getSource();
                    timer.stop();
                    // Personally, I'd use a listener, but this will do
                    afterCheckDelay();
                }
            });
            timer.start();
        }

        protected void afterCheckDelay() {
            if (pool.getIterator() < pool.getSize()) {
                //timer.restart();
                next();
            } else {
                gameOver();
            }
        }

        private class QuestionPanel extends JPanel {

            public QuestionPanel() {
                this.setLayout(new BorderLayout());
                this.add(scoreString, BorderLayout.EAST);
            }

            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                g.setFont(font);
                FontMetrics fm = g.getFontMetrics();
                int y = ((getHeight() - fm.getHeight()) / 2) + fm.getAscent();
                g.drawString(tf, 10, y);
            }
        }

        private class Listener implements ActionListener {

            @Override
            public void actionPerformed(ActionEvent e) {
                pressed = (JButton) e.getSource();
                String guess = pressed.getText();
                check(guess);
            }

        }

        private class TimerListener implements ActionListener {

            @Override
            public void actionPerformed(ActionEvent e) {
//                timer.stop();
//                score -= INCORRECT;
//                scoreString.setText("Score: " + score + "/" + pool.getIterator() * CORRECT);
//                repaint();
//                timer.restart();
//                next();
            }
        }
    }

    public static class Pool {

        private ArrayList<Question> questions = new ArrayList<>();
//        private Scanner input = new Scanner(new File("src/trivia.txt"));
        private static int iterator = 0;

        public Pool() throws FileNotFoundException {
            Question question = new Question("Why am I doing this", "Because I'm awesome", "You feel for the trick", "You have no idea", "To much caffine");
            questions.add(question);
//            while (input.hasNext()) {
//                String q = input.nextLine();
//                String a = input.nextLine();
//                String d1 = input.nextLine();
//                String d2 = input.nextLine();
//                String d3 = input.nextLine();
//                Question question = new Question(q, a, d1, d2, d3);
//                questions.add(question);
//            }
            Collections.shuffle(questions);
            //System.out.println(questions);
        }

        public Question getQuestion() {
            Question q = questions.get(iterator);
            iterator++;
            return q;
        }

        public int getSize() {
            return questions.size();
        }

        public static int getIterator() {
            return iterator;
        }
    }

    public static class Question {

        private final int NUM_OF_ANSWERS = 4;
        private String question;
        private String[] answers = new String[NUM_OF_ANSWERS];
        private final int CORRECT_ANSWER = 0;

        public Question(String qu, String an, String dm1, String dm2, String dm3) {
            question = qu;
            answers[0] = an;
            answers[1] = dm1;
            answers[2] = dm2;
            answers[3] = dm3;
        }

        public String getCorrectAnswer() {
            return answers[CORRECT_ANSWER];
        }

        public String getQuestion() {
            return question;
        }

        public String[] getAnswers() {
            return answers;
        }

        public String toString() {
            String str = question;
            for (int i = 0; i < 4; i++) {
                str += " " + answers[i];
            }
            str += "\n";
            return str;
        }

        public String[] shuffle() {
            String[] shuffled = new String[NUM_OF_ANSWERS];
            for (int i = 0; i < NUM_OF_ANSWERS; i++) {
                shuffled[i] = answers[i];
            }
            Collections.shuffle(Arrays.asList(shuffled));
            return shuffled;
        }
    }
}