raser
Posts: 65
Joined: Mon Jan 25, 2016 1:49 pm

Tkinter GUI Magic 8 Ball Program (CODE included)

Mon May 02, 2016 3:02 pm

So if you're trying to learn Python like me, you may have searched online for ideas for little programs to get coding. I found a few cool ones, like Bare Python Battleships, and a Magic 8 Ball. There seems to be numerous ways to do this 8 Ball program, some simpler than others.

Anyway, I have been self-learning for about 3 to 4 months now and I decided to try and write my OWN version using the Thinter skills I have learned so far, and I will post the code below.

If you're a complete beginner Tkinter is a built-in module that comes with Python (Python 2.7 in my case) and allows the writer to build GUI (graphical user interface) type - window like programs.

HERE IS THE CODE:

Code: Select all

# A re-creation of the standard Python Magic 8 Ball Program
# Ben Woodfield / Python 2.7 / Learning exercise in Tkinter

# Import the modules needed for this app
import Tkinter
from Tkinter import *
import random

# Set up the main (top) window's settings
top = Tk()
top.minsize(300,300)
top.title('Magic 8 Ball - Ben Woodfield')
top.configure(bg='Black')

# Put all the answers in one variable [in a tuple]
answers = ["Yes, Most Definately!",
           "The Chances Are High!",
           "Not Likely!",
           "The Odds Look Good!",
           "Is That Your Question?",
           "You Have To Wait And See!",
           "23% Chance!",
           "99.9% Success Rate!",
           "It looks good!",
           "Computer Says NO!",
           "Unable to Decide!"
           "Ask Again Later!",
           "Better Not Tell You Now!",
           "Cannot Predict Result!",
           "Concentrate & Ask Again!",
           "Dont Count On It!",
           "No Chance!",
           "Only Smarties Have The Answer!"]

# Write a new function to either print out a random choice from above
# -or display an error if the user doesn't enter any text
def get_answer():
        msg = "ERROR: Your question must be TEXT"
        i = userentry.get() # gets the text from the entrybox
        y = i.isdigit()
        l = len(userentry.get())

        if y == True or 1 == 0:
               userentry.insert(0,(msg))

        else:
                x = random.choice(answers)
                userentry2.delete(0, END)   # Clear previous output
                userentry2.insert(0,str(x)) # Insert response

# Make the buttons and entry boxes (but not packing them just yet)
# These are the labels (to display text)
lbl1 = Label(top, text='Enter Your Question', bg='Black', fg='Red', font='freesansbold')
lbl2 = Label(top, text='Answer', bg='Black', fg='Red', font='freesansbold')
lbl3 = Label(top, text='0\n-\n0', bg='Black', font='Black')

# These are the two buttons (quit and get-answer)
btn1 =  Button(top, text='Get Answer', bg='darkBlue', fg='Red', font='freesansbold', command=get_answer)
btn2 = Button(top, text='Exit', bg='Red', fg='Black', font='freesansbold', command=quit)

# This allows a string-variable to be added to the window
circleVar = StringVar()
userentry = Entry(top, textvariable=circleVar)

circleVar2 = StringVar()
userentry2 = Entry(top, bg='Black', fg='Red', font='freesansbold, 12')


# Pack everything into the window (in order)
lbl1.pack()
userentry.pack()
btn1.pack()
lbl3.pack()
lbl2.pack()
userentry2.pack()
btn2.pack(side=BOTTOM)

# This loop is needed to actually display the program, and keep it on-screen
top.mainloop()

It should look like this:
[img]
file:///home/raser/Pictures/8ball_screenshot.png
[/img]

It is about 82 lines - give or take a few coments, and the things you will learn from this are as follows:
  • Create a GUI Window (root/top window)
    Add a main title (to the topbar)
    Configure the size and background colour of the root/top window
    Make a list of answers, and store them under ONE variable/name (a tuple)
    Use the Random module to pick one random answer from the list
    Create widgets (buttons, labels and entry widgets)
    Assign quit command to button (when you click exit, it will quit program)
    Assign a StringVar function to a button (to display a string on the window)
    Jazz things up a bit (edit buttons, text colours font and more)
    Pack everything in (with the simplest pack() geometry manager)
    Create an error message (If the user doesn't enter text in the entry box)
I am still learning and there are a few things I would like to add to this program - although I was happy with it when it finally ran!

I would like to add a RESET button to clear the users input and the displayed answer text, allowing the user to enter another question without having to manually delete the previous question. So reset the program to original state -empty of text

I would like to learn other ways to position widgets - I know of grid() and the sticky N,E,S,W way but I have only ever been able to use the basic pack() (side=TOP,BOTTOM,LEFT,RIGHT) method. With the grid method I could design more complex programs

And I would like to add a nice 8-ball image to the Tkinter window. I have the image but it was a nightmare to get it behind everything. The image is 512x512 so to make life easier I made my Tk window that size. I got it to upload and thne the widgets(buttons) wouldn't overlap it, i mean they squeezed underneath. I looked online and found a script to add it into a frame, and the script had a button over the top of the image as I wanted. So I modified the button to pack at the bottom and be my exit button - perfect! BUT... I added another button the same way and whatever I put into the window just squeezes its way under the image (even when I did pack(side=TOP)) It was a major headache and online guides are hard to get precise info.

Anyway I hope you enjoy the code - I welcome any ideas and improvements, and feel free to use it or copy it out!

User avatar
RogerW
Posts: 285
Joined: Sat Dec 20, 2014 12:15 pm
Location: London UK

Re: Tkinter GUI Magic 8 Ball Program (CODE included)

Tue May 03, 2016 8:06 am

Two small points:

Code: Select all

import Tkinter
from Tkinter import *
The first line is redundant.

Code: Select all

        if y == True or 1 == 0:
You have a "one" not an "el"

I will try to look at your main point later today.

User avatar
RogerW
Posts: 285
Joined: Sat Dec 20, 2014 12:15 pm
Location: London UK

Re: Tkinter GUI Magic 8 Ball Program (CODE included)

Tue May 03, 2016 9:54 am

I am not sure how to best put in your graphic - I suggest you look at Canvas widgets.

Clearing the question and answer fileds is easy. Add a "Clear" button and in its command function put null strings into the StringVar objects associated with the widgets.

This is my solution. I user python3 so you might have to change tkinter to Tkinter.

I have put everything in classes because I prefer it that way. Pleas come back if you do not understand anything.

Code: Select all

import tkinter as tk
import random as rn

class BallData:
    # A class object to represent the logic of the program
    # I don't like globals
    
    # Put all the answers in one variable [in a tuple]
    answers = ["Yes, Most Definately!",
           "The Chances Are High!",
           "Not Likely!",
           "The Odds Look Good!",
           "Is That Your Question?",
           "You Have To Wait And See!",
           "23% Chance!",
           "99.9% Success Rate!",
           "It looks good!",
           "Computer Says NO!",
           "Unable to Decide!"
           "Ask Again Later!",
           "Better Not Tell You Now!",
           "Cannot Predict Result!",
           "Concentrate & Ask Again!",
           "Dont Count On It!",
           "No Chance!",
           "Only Smarties Have The Answer!"]
    
    error_msg = "ERROR: Your question must be TEXT"
    
    # takes a string (userentry) and returns an answer
    def get_respose(self,userentry):
        y = userentry.isdigit()
        l = len(userentry)

        if y or l == 0:
            return self.error_msg
        else:
            return rn.choice(self.answers)

class View(tk.Frame):
    # This window contains the user interface
    def __init__(self,master,*args,**kwargs):
        tk.Frame.__init__(self,master,*args,**kwargs)
        
        self.data = BallData()
        
        self.configure(bg='Black')
        
        self.user_question = tk.StringVar()
        self.reply = tk.StringVar()
        
        # Make the buttons and entry boxes (but not packing them just yet)
        # These are the labels (to display text)
        lbl1 = tk.Label(self, text='Enter Your Question', bg='Black', fg='Red', font='freesansbold')
        lbl2 = tk.Label(self, text='Answer', bg='Black', fg='Red', font='freesansbold')
        lbl3 = tk.Label(self, text='0\n-\n0', bg='Black', font='Black')
        self.lbl_reply = tk.Label(self,font='freesansbold',textvariable=self.reply)

        # These are the two buttons (quit and get-answer)
        btn1 = tk.Button(self, text='Get Answer', bg='darkBlue', fg='Red', font='freesansbold', command=self.get_answer)
        btn2 = tk.Button(self, text='Exit', bg='Red', fg='Black', font='freesansbold', command=self.quit)
        btn3 = tk.Button(self, text='Clear', bg='Green', fg='Black', font='freesansbold', command=self.clear)
        # entry field
        self.user_entry = tk.Entry(self, bg='Black', fg='Red', font='freesansbold, 12',textvariable = self.user_question)
        
        # Pack everything into the window (in order)
        lbl1.pack()
        self.user_entry.pack()
        btn1.pack()
        lbl3.pack()
        lbl2.pack()
        self.lbl_reply.pack()
        btn3.pack()
        btn2.pack(side=tk.BOTTOM)
        
    def get_answer(self):
        self.reply.set(self.data.get_respose(self.user_question.get()))
        
    def clear(self):
        self.user_question.set("")
        self.reply.set("")
        
   
class MainWindow(tk.Tk):
    # The main window has the title bar and could have a menu
    def __init__(self):
        tk.Tk.__init__(self)
        
        self.minsize(300,300)
        self.title('Magic 8 Ball - Ben Woodfield')
        View(self).pack()

# create a main window and call mainloop
MainWindow().mainloop()

Return to “Python”