A desktop True/False trivia quiz built with Python's tkinter GUI toolkit, pulling live questions from the Open Trivia Database API. Clean OOP architecture splits data fetching, quiz logic, and UI into separate, single-responsibility modules — a great example of building a small app the way larger real-world codebases are structured.
Every question is fetched fresh from a public API, so no two quiz sessions ever look exactly the same.
- 🌐 Live trivia data fetched from the Open Trivia Database API via
requests— no hardcoded question bank. - ✅❌ True/False gameplay with custom image buttons instead of default tkinter buttons.
- 🧮 Real-time score tracking, updated and displayed after every answer.
- 🎨 Instant visual feedback — the question canvas flashes green for a correct answer and red/pink for an incorrect one.
- 🧹 Clean HTML-decoded question text using Python's built-in
htmlmodule (the API returns entities like"and&, which get unescaped before display). - 🏗️ Modular, class-based architecture — data fetching, quiz logic, question modeling, and UI are each isolated in their own file.
- 🛑 Graceful quiz-end state — buttons disable automatically once all questions have been answered.
| Category | Tool / Concept |
|---|---|
| Language | Python 3 |
| GUI | tkinter (standard library) |
| HTTP Requests | requests |
| Data Source | Open Trivia Database API |
| Text Processing | html (standard library) — for unescaping HTML entities |
| Paradigm | Object-Oriented Programming (OOP) — separate classes for Question, QuizLogic, and AppInterface |
QuizQuest/
│
├── main.py # Entry point — builds the question bank and wires everything together
├── data.py # Fetches trivia questions from the Open Trivia Database API
├── question_model.py # Question class — a simple data container for text + answer
├── quiz_logic.py # QuizLogic class — tracks score, progress, and answer checking
├── ui.py # AppInterface class — builds and manages the tkinter GUI
├── images/
│ ├── true.png
│ └── false.png
└── README.md
Each file has exactly one job: data.py only talks to the API, quiz_logic.py only knows about scoring and progress, and ui.py only knows about rendering — main.py simply wires them together. This separation is what makes the app easy to extend (e.g. swapping the data source or UI framework) without breaking the rest.
- Python 3.x installed
requests— install via pip:
pip install requestsgit clone https://github.com/VISHAL108-Mech/Python-Quiz-Game.git
cd quizquest
python main.py| Button | Action |
|---|---|
| ✅ True | Submit "True" as your answer |
| ❌ False | Submit "False" as your answer |
The canvas flashes green for a correct answer and red for an incorrect one, then automatically advances to the next question after a short delay.
The app requests 10 true/false questions from a specific trivia category, and raise_for_status() ensures the app fails loudly (instead of silently) if the API request doesn't succeed.
parameters = {
"amount": 10,
"type": "boolean",
"category": 18
}
response = requests.get("https://opentdb.com/api.php", params=parameters)
response.raise_for_status()
data = response.json()
question_data = data["results"]A minimal Question class just stores the text and correct answer — no unnecessary complexity, since that's all a question needs to represent.
class Question:
def __init__(self, q_text, q_answer):
self.text = q_text
self.answer = q_answermain.py loops through the raw API results, wraps each one in a Question object, and hands the finished list off to the quiz logic and UI — this is the "glue" that connects all the modules together.
question_bank = []
for question in question_data:
question_text = question["question"]
question_answer = question["correct_answer"]
new_question = Question(question_text, question_answer)
question_bank.append(new_question)
quiz = QuizLogic(question_bank)
app_ui = AppInterface(quiz)QuizLogic tracks the current question index and score, and handles the two core actions of any quiz: getting the next question, and checking whether an answer is correct. html.unescape() is used here to clean up entities like " that the API returns in raw question text.
class QuizLogic:
def __init__(self, q_list):
self.question_number = 0
self.score = 0
self.question_list = q_list
self.current_question = None
def still_has_questions(self):
return self.question_number < len(self.question_list)
def next_question(self):
self.current_question = self.question_list[self.question_number]
self.question_number += 1
q_text = html.unescape(self.current_question.text)
return f"Q.{self.question_number}: {q_text}"
def check_answer(self, user_answer):
correct_answer = self.current_question.answer
if user_answer.lower() == correct_answer.lower():
self.score += 1
return True
else:
return FalseWhen the player answers, the canvas background color changes based on correctness, then window.after() schedules the next question to load automatically after a one-second pause.
def give_feedback(self, is_right):
if is_right:
self.canvas.config(bg="#8BC34A")
else:
self.canvas.config(bg="#E91E63")
self.window.after(1000, self.next_question)Once there are no questions left, the canvas displays "Quiz Over!" and both answer buttons are disabled, preventing further clicks.
def next_question(self):
self.canvas.config(bg="#FFFFFF")
if self.quiz.still_has_questions():
self.score.config(text=f"Score: {self.quiz.score}")
question_text = self.quiz.next_question()
self.canvas.itemconfig(self.q_text, text=question_text)
else:
self.canvas.itemconfig(self.q_text, text="Quiz Over!")
self.true_button.config(state="disabled")
self.false_button.config(state="disabled")- Consuming a third-party REST API with
requestsand handling failures withraise_for_status() - Structuring a multi-file Python application using OOP, with clear separation of concerns
- Cleaning and formatting text data (HTML entity decoding) before displaying it to users
- Managing GUI state transitions (question → feedback → next question → quiz over) with
tkinter - Using
window.after()for timed, non-blocking UI updates
- Let the user pick category, difficulty, and question type before starting
- Add multiple-choice question support (the API supports it — this app only uses
type: boolean) - Show a final results screen with score percentage instead of just "Quiz Over!"
- Add a restart button instead of requiring the app to be relaunched
- Cache questions locally as a fallback if the API is unreachable
VISHAL YADAV
- GitHub: @VISHAL108-Mech
- LinkedIn: vishal-yadav-2a91a7428
- Email: vy4122000@gmail.com