This script is to be a 5x5 grid of buttons, one saying "Click Me" and the rest "Don't Click Me." A correct click scores a point, an incorrect click costs a point. The buttons get shuffled after each click. The player has 60 seconds to maximize his score.

The script is incomplete because I'm having two problems:
1. The individual ttk widget styles are refusing to apply (only the global widget styles are applying).
2. There is an extraneous column at the right of frame2 that I can't get rid of despite monkeying with the row/column/span/configure setttings for a geological age.

Any help appreciated.

from tkinter import Tk
from tkinter.ttk import Frame, Label, Button, Style
from random import randrange
from functools import partial

class Game:

    def __init__(self):
        self.window = Tk()
        self.window.title("Onager Ornery Clicker")
        self.createwidgets()

    def create_styles(self):
        frame_style = Style()
        frame_style.theme_use('normal')
        frame_style.configure("TFrame",
                              background='blue',
                              foreground='gold',
                              borderwidth='10',
                              relief='raised')

        title_style = Style()
        title_style.configure("TLabel", font='serif 30')

        instr_style = Style()
        instr_style.configure("TLabel", font='serif 12')



    def create_frames(self):
        self.frame = Frame(self.window)
        self.frame.rowconfigure(4)
        self.frame.columnconfigure(5)
        self.frame.grid(row=0, column=0)
        self.frame2 = Frame(self.window)
        self.frame2.rowconfigure(5)
        self.frame2.columnconfigure(5)
        self.frame2.grid(row=4, column=0)

    def create_title(self):
        self.title = Label(self.window,
                           style="title_style.TLabel",
                           text='Onager Ornery Clicker')
        self.title.grid(row=0, column=0, columnspan=5)

    def create_instr(self):
        self.instr = """        Correct click scores a point.
        Wrong click costs a point.
        You have 60 seconds.
        Click Start to begin.
        HAVE FUN!"""
        self.instr = Label(self.window,
                           style="instr_style.TLabel",
                           text=self.instr)
        self.instr.grid(row=1, column=0, rowspan=3, columnspan=4)

    def create_start_button(self):
        self.start = Button(self.window, text='Start')
        self.start.grid(row=1, column=4)

    def create_timer(self):
        self.timer = Label(self.window, text='Time')
        self.timer.grid(row=2, column=4)

    def create_score(self):
        self.score = Label(self.window, text='Score')
        self.score.grid(row=3, column=4)

    def shuffle(self):
        for i, button in enumerate(self.buttons, 1):
            button['text'] = "Don't Click Me!"
        index = randrange(len(self.buttons))
        self.buttons[index]['text'] = "Click Me!"

    def create_buttons(self):
        self.buttons = []
        for item in range(25):
            button = Button(self.frame2, width=len("Don't Click me!"))
            button['command'] = partial(self.button_clicked, button)
            row_num, col_num = divmod(item, 5)
            button.grid(row=(row_num+4), column=col_num)
            self.buttons.append(button)
        self.shuffle()

    def button_clicked(self, button):
        if button['text'] == "Click Me!":
            self.shuffle()

    def createwidgets(self):
       self.create_styles()
        self.create_frames()
        self.create_title()
        self.create_instr()
        self.create_start_button()
        self.create_timer()
        self.create_score()
        self.create_buttons()

clicker = Game()
clicker.window.mainloop()

Recommended Answers

All 8 Replies

I can't run the script in kubuntu 14.04. I get

Traceback (most recent call last):                                                                                                                                                                                       
  File "foo.py", line 99, in <module>                                                                                                                                                                                    
    clicker = Game()                                                                                                                                                                                                     
  File "foo.py", line 11, in __init__                                                                                                                                                                                    
    self.createwidgets()                                                                                                                                                                                                 
  File "foo.py", line 90, in createwidgets                                                                                                                                                                               
    self.create_styles()
  File "foo.py", line 15, in create_styles
    frame_style.theme_use('normal')
  File "/usr/lib/python3.4/tkinter/ttk.py", line 523, in theme_use
    self.tk.call("ttk::setTheme", themename)
_tkinter.TclError: can't find package ttk::theme::normal

That's because it looks like there isn't a "normal" ttk theme in your version of python3-tk. To find out which themes are available do this in the python3 interpreter:

>>>from tkinter.ttk import Style
>>>s = Style()
>>>s.theme_use()

That will output available styles in console. Then you can replace "normal" with some other style available on your system (that's line 15).
Alternatively, just comment out line 15 and use your OS's default theme.

I only have the 'default' style. I get something better with a single frame

from tkinter import Tk
from tkinter.ttk import Frame, Label, Button, Style
from random import randrange
from functools import partial

class Game:

    def __init__(self):
        self.window = Tk()
        self.window.title("Onager Ornery Clicker")
        self.createwidgets()

    def create_styles(self):
        frame_style = Style()
        frame_style.theme_use('default')
        frame_style.configure("TFrame",
                              background='blue',
                              foreground='gold',
                              borderwidth='10',
                              relief='raised')

        title_style = Style()
        title_style.configure("TLabel", font='serif 30')

        instr_style = Style()
        instr_style.configure("TLabel", font='serif 12')



    def create_frames(self):
        self.frame = Frame(self.window)
        self.frame.rowconfigure(4+5)
        self.frame.columnconfigure(5)
        self.frame.grid(row=0, column=0)
        self.frame2 = self.frame

    def create_title(self):
        self.title = Label(self.frame,
                           style="title_style.TLabel",
                           text='Onager Ornery Clicker')
        self.title.grid(row=0, column=0, columnspan=5)

    def create_instr(self):
        self.instr = """        Correct click scores a point.
        Wrong click costs a point.
        You have 60 seconds.
        Click Start to begin.
        HAVE FUN!"""
        self.instr = Label(self.frame,
                           style="instr_style.TLabel",
                           text=self.instr)
        self.instr.grid(row=1, column=0, rowspan=3, columnspan=4)

    def create_start_button(self):
        self.start = Button(self.frame, text='Start')
        self.start.grid(row=1, column=4)

    def create_timer(self):
        self.timer = Label(self.frame, text='Time')
        self.timer.grid(row=2, column=4)

    def create_score(self):
        self.score = Label(self.frame, text='Score')
        self.score.grid(row=3, column=4)

    def shuffle(self):
        for i, button in enumerate(self.buttons, 1):
            button['text'] = "Don't Click Me!"
        index = randrange(len(self.buttons))
        self.buttons[index]['text'] = "Click Me!"

    def create_buttons(self):
        self.buttons = []
        for item in range(25):
            button = Button(self.frame2, width=len("Don't Click me!"))
            button['command'] = partial(self.button_clicked, button)
            row_num, col_num = divmod(item, 5)
            button.grid(row=(row_num+4), column=col_num)
            self.buttons.append(button)
        self.shuffle()

    def button_clicked(self, button):
        if button['text'] == "Click Me!":
            self.shuffle()

    def createwidgets(self):
        self.create_styles()
        self.create_frames()
        self.create_title()
        self.create_instr()
        self.create_start_button()
        self.create_timer()
        self.create_score()
        self.create_buttons()

clicker = Game()
clicker.window.mainloop()

Would you mind uploading that code so I can work further on it? (If I copy what's in your message I'll have to delete all the line numbers.)

Your help much appreciated. :)

BTW how does it look with standard tk widgets instead of ttk ones? Just replace:

from tkinter import Tk...
from tkinter.ttk import Frame...

with:

from tkinter import Tk, Frame ...

Putting everything on one line.

In principle, you can double-click on the code and then use ^C to copy the code without the line numbers.

Here's a version of the game where the look issues seem to have been fixed. Let me know how it looks on your system:

from tkinter import Tk, Frame, Label, IntVar
from tkinter.ttk import Button
from functools import partial
from random import randrange

class Game:

    def __init__(self):
        self.window = Tk()
        self.window.title("Onager Ornery Clicker")
        self.score = IntVar()
        self.createwidgets()

    def createframes(self):
        self.frame1 = Frame(self.window)
        self.frame2 = Frame(self.window)
        self.frame1.configure(bg='silver',
                              relief='raised', border='15')
        self.frame2.configure(bg='silver',
                              relief='raised', border='15')
        self.frame1.rowconfigure(6)
        self.frame1.columnconfigure(5)
        self.frame2.rowconfigure(15)
        self.frame2.columnconfigure(5)
        self.frame1.grid(row=0, column=0, rowspan=6,
                         columnspan=5)
        self.frame2.grid(row=6, column=0, rowspan=15,
                         columnspan=5)

    def createtitle(self):
        self.title = Label(self.frame1)
        self.title.configure(bg='silver', fg='SlateBlue4',
                             font='serif 30', justify='center',
                             padx='10', pady='10',
                             text='Onager Ornery Clicker')
        self.title.grid(row=0, column=0, rowspan=1,
                        columnspan=5)

    def createinstr(self):
        textstring="""Correct click scores a point.
        Incorrect click costs you a point.
        How quickly can you score 30 points?
        Click Start to begin.
        HAVE FUN!!!"""
        self.instr = Label(self.frame1)
        self.instr.configure(bg='Silver', fg='SlateBlue4',
                             font='serif 12', justify='center',
                             text=textstring, pady='10')
        self.instr.grid(row=1, column=0, rowspan=5,
                        columnspan=1)

    def createstart(self):
        self.start = Button(self.frame1)
        self.start['text'] = 'Start'
        self.start['command'] = partial(self.play)
        self.start.grid(row=1, column=2, rowspan=1,
                        columnspan=1)

    def createscore(self):
        self.timer = Label(self.frame1)
        self.timer.configure(bg='black', fg='white',
                             font='serif 16',
                             textvariable=str(self.score))
        self.timer.grid(row=3, column=2, rowspan=1,
                        columnspan=1)

    def createbuttons(self):
        index = randrange(0,74)
        for item in range(75):
            self.button = Button(self.frame2)
            if item == index:
                self.button['text'] = 'click Me!'
            else:
                self.button['text'] = "Don't Click Me!"
            rn, cn = divmod(item, 5)
            self.button.grid(row=rn, column=cn, rowspan=1,
                            columnspan=1)

    def play(self):
        pass

    def createwidgets(self):
        self.createframes()
        self.createtitle()
        self.createinstr()
        self.createstart()
        self.createscore()
        self.createbuttons()


def main():
    onager = Game()
    onager.window.mainloop()

if __name__=='__main__':
    main()

Very nice, here is how it looks here.

With the help of a fellow on Reddit I've got an almost-completed version of the game. Here's the latest:

    from tkinter import Tk, Frame, Label, IntVar
    from tkinter.ttk import Button
    from functools import partial
    from random import randrange

    class Game:

        def __init__(self):
            self.window = Tk()
            self.window.title("Onager Ornery Clicker")
            self.createwidgets()

        def createframes(self):
            self.frame1 = Frame(self.window)
            self.frame2 = Frame(self.window)
            self.frame1.configure(bg='silver',
                                  relief='raised', border='15')
            self.frame2.configure(bg='silver',
                                  relief='raised', border='15')
            self.frame1.rowconfigure(6)
            self.frame1.columnconfigure(5)
            self.frame2.rowconfigure(15)
            self.frame2.columnconfigure(5)
            self.frame1.grid(row=0, column=0, rowspan=6,
                             columnspan=5)
            self.frame2.grid(row=6, column=0, rowspan=15,
                             columnspan=5)

        def createtitle(self):
            self.title = Label(self.frame1)
            self.title.configure(bg='silver', fg='SlateBlue4',
                                 font='serif 30', justify='center',
                                 padx='10', pady='10',
                                 text='Onager Ornery Clicker')
            self.title.grid(row=0, column=0, rowspan=1,
                            columnspan=5)

        def createinstr(self):
            textstring="""Correct click scores a point.
    Incorrect click costs you a point.
    How quickly can you score points?
    Click Start to begin.
    HAVE FUN!!!"""
            self.instr = Label(self.frame1)
            self.instr.configure(bg='Silver', fg='SlateBlue4',
                                 font='serif 12', justify='center',
                                 text=textstring, pady='10')
            self.instr.grid(row=1, column=0, rowspan=5,
                            columnspan=1)

        def createstart(self):
            self.start = Button(self.frame1)
            self.start['text'] = 'Start'
            self.start['command'] = partial(self.start_game)
            self.start.grid(row=1, column=2, rowspan=1,
                            columnspan=1)

        def createstop(self):
            self.stop = Button(self.frame1)
            self.stop['text'] = 'Stop.'
            self.stop['command'] = partial(self.stop_game)
            self.stop.grid(row=1, column=3, rowspan=1,
                           columnspan=1)

        def createscore(self):
            self.score_label = Label(self.frame1)
            self.score_label.configure(fg='black',
                                       font='serif 10')
            self.score_label['text'] = 'Score:'
            self.score_label.grid(row=3, column=2, rowspan=1,
                                  columnspan=1)
            self.score = Label(self.frame1)
            self.score.configure(bg='black', fg='white',
                                 font='serif 16')
            self.score.grid(row=5, column=2, rowspan=1,
                            columnspan=1)

        def createtime(self):
            self.time_label = Label(self.frame1)
            self.time_label.configure(fg='black',
                                      font='serif 10')
            self.time_label['text'] = 'Time:'
            self.time_label.grid(row=3, column=3, rowspan=1,
                                 columnspan=1)
            self.time = Label(self.frame1)
            self.time.configure(bg='black', fg='white',
                                font='seriv 16')
            self.time.grid(row=5, column=3, rowspan=1,
                            columnspan=1)

        def createbuttons(self):
            index = randrange(0,74)
            for item in range(75):
                self.button = Button(self.frame2)
                if item == index:
                    self.button['text'] = 'Click Me!'
                else:
                    self.button['text'] = "Don't Click Me!"
                self.button['command'] = partial(self.clicked, self.button)
                rn, cn = divmod(item, 5)
                self.button.grid(row=rn, column=cn, rowspan=1,
                                columnspan=1)

        def createwidgets(self):
            self.createframes()
            self.createtitle()
            self.createinstr()
            self.createstart()
            self.createstop()
            self.createscore()
            self.createtime()
            self.createbuttons()


    class Play(Game):

        def __init__(self):
            Game.__init__(self)
            self.scorevar = IntVar()
            self.timevar = IntVar()
            self.initialize()

        def initialize(self):
            self.score['textvariable'] = str(self.scorevar)
            self.time['textvariable'] = str(self.timevar)

        def clicked(self, button):
            if self.button['text'] == 'Click Me!':
                self.scorevar.set(self.scorevar.get() + 1)
            else:
                self.scorevar.set(self.scorevar.get() - 1)


        def start_game(self):
            self.game_running = True
            self.update_time()

        def stop_game(self):
            self.game_running = False

        def update_time(self):
            if self.game_running:
                self.timevar.set(self.timevar.get() + 1)
                self.window.after(1000, self.update_time)


    def main():
        onager = Play()
        onager.window.mainloop()

    if __name__=='__main__':
        main()
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.