0

I'm trying to add another button to my GUI by pressing a button on the GUI itself. Essentially I'm just trying to update it but I'm relatively new to OOP so I'm having issues with scope.

This is what I have so far...

  1 #!/usr/bin/env python
  2 import random, gi, sys
  3 from gi.repository import Gtk
  4 import itertools

 23 class Deck:
 24   """A sample card deck"""
 25   def __init__(self):
 26     deck = []
 27     self.color_list = ["red", "green", "blue"]
 28     for color in self.color_list:
 29       for i in range (1,2):
 30         deck.append((color, i))
 31     self.deck = deck
 32 
 33   def draw_card(self):
 34     print self.deck
 35     try:
 36       card = self.deck.pop()
 37       print self.deck
 38       return card
 39     except IndexError:
 40       print "No cards in deck!"
 41       return

 56 class MyWindow(Gtk.Window):
 57 
 58   def __init__(self):
 59     Gtk.Window.__init__(self, title="RGB 3, 2, 1... GO!")
 60     self.set_border_width(10)
 61     self.set_size_request(450,150)
 62 
 63     grid = Gtk.Grid()
 64     self.add(grid)
 65 
 66     draw_button = Gtk.Button(label="Draw Card")
 67     draw_button.connect("clicked", self.on_draw_button_clicked)
 68     grid.attach(draw_button,0,0,1,1)
 69 
 70     end_button = Gtk.Button(label="End Game")
 71     end_button.connect("clicked", self.on_stop_button_clicked)
 72     grid.attach_next_to(end_button,draw_button,Gtk.PositionType.RIGHT,1,1)
 73 
 74     update_button = Gtk.Button(label="Update")
 75     update_button.connect("clicked", self.update, grid)
 76     grid.attach_next_to(update_button,end_button,Gtk.PositionType.RIGHT,1,1)
 77 
 78   def update(self, widget, grid):
 79     card1_button = Gtk.Button(label="card1")
 80     card1_button.connect("clicked", self.on_card1_button_clicked)
 81     grid.attach_next_to(card1_button,draw_button,Gtk.PositionType.BOTTOM,3,1)
 82     
 83   def on_draw_button_clicked(self, widget):
 84 +--- 13 lines: card = my_deck.draw_card()----------------------------------------------------------------------------------------------------
 97 
 98   def on_stop_button_clicked(self, widget):
 99     Gtk.main_quit()
100     
101   def on_card1_button_clicked(self, widget):
102     Gtk.main_quit()

121 # Objects must be instantiated here
122 my_deck = Deck()
123 print my_deck.deck
124 win = MyWindow()
125 win.connect("delete-event", Gtk.main_quit)
126 win.show_all()
127 Gtk.main()

When I run this, my GUI pops open. And when I hit my update button I get the following error:

Traceback (most recent call last):
  File "game1.py", line 85, in update
    grid.attach_next_to(card1_button,draw_button,Gtk.PositionType.BOTTOM,3,1)
NameError: global name 'draw_button' is not defined

How do I get my update function to recognize the GUI/grid I've already created in the def init function? Is there a better way to do what I want?

1 Answer 1

1

Define an instance variable in your MyWindow class to keep track of that button.

For example, in your code, whenever you see a draw_button change it to self.draw_button. It will let you track this button in other methods. This would look like:

import random, gi, sys
from gi.repository import Gtk
import itertools

class Deck:
  """A sample card deck"""
  def __init__(self):
    deck = []
    self.color_list = ["red", "green", "blue"]
    for color in self.color_list:
      for i in range(1,2):
        deck.append((color, i))
    self.deck = deck

  def draw_card(self):
    print self.deck
    try:
      card = self.deck.pop()
      print self.deck
      return card
    except IndexError:
      print "No cards in deck!"
      return

class MyWindow(Gtk.Window):

  def __init__(self):
    Gtk.Window.__init__(self, title="RGB 3, 2, 1... GO!")
    self.set_border_width(10)
    self.set_size_request(450,150)

    grid = Gtk.Grid()
    self.add(grid)

    # Here we create the instance variable and use it afterward
    self.draw_button = Gtk.Button(label="Draw Card")
    self.draw_button.connect("clicked", self.on_draw_button_clicked)
    grid.attach(self.draw_button,0,0,1,1)

    end_button = Gtk.Button(label="End Game")
    end_button.connect("clicked", self.on_stop_button_clicked)
    grid.attach_next_to(end_button, self.draw_button, Gtk.PositionType.RIGHT, 1, 1)

    update_button = Gtk.Button(label="Update")
    update_button.connect("clicked", self.update, grid)
    grid.attach_next_to(card1_button, self.draw_button, Gtk.PositionType.BOTTOM, 3, 1)

  def update(self, widget, grid):
    card1_button = Gtk.Button(label="card1")
    card1_button.connect("clicked", self.on_card1_button_clicked)
    # Here we recall the value stored in self.draw_button
    grid.attach_next_to(card1_button, self.draw_button, Gtk.PositionType.BOTTOM, 3, 1)

  def on_draw_button_clicked(self, widget):
    for x in range(13):
      card = my_deck.draw_card()

  def on_stop_button_clicked(self, widget):
    Gtk.main_quit()

  def on_card1_button_clicked(self, widget):
    Gtk.main_quit()

# Objects must be instantiated here
my_deck = Deck()
print my_deck.deck
win = MyWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()

But there are a few other problems in your code:

  • I presume that you are using Gtk 3.0. If that's the case, you should require it before importing Gtk like this:

    gi.require_version('Gtk', '3.0')
    from gi.repository import Gtk
    
  • In Deck.__init__() you have used range(1,2) in a for-loop. The problem is that range(1, 2) is equivalent to [1] because you have asked for a range beginning at 1 but stopping just before 2. I'm not sure that was what you wanted.

  • You should add a self.show_all() at the end of your MyWindow.update() method otherwise you won't be able to see the freshly created button.
  • You should use self.close() instead of Gtk.main_quit() in your MyWindow.on_stop_button_clicked() and MyWindow.on_card1_button_clicked() methods otherwise your code won't be able to properly destroy your window when clicking those buttons.

This is how this would look with these recommendations:

import random, gi, sys
import itertools

gi.require_version('Gtk', '3.0')
from gi.repository import Gtk

class Deck:
  """A sample card deck"""
  def __init__(self):
    deck = []
    self.color_list = ["red", "green", "blue"]
    for color in self.color_list:
      for i in range(1,2):    # Check to see if this is valid
        deck.append((color, i))
    self.deck = deck

  def draw_card(self):
    print self.deck
    try:
      card = self.deck.pop()
      print self.deck
      return card
    except IndexError:
      print "No cards in deck!"
      return

class MyWindow(Gtk.Window):

  def __init__(self):
    Gtk.Window.__init__(self, title="RGB 3, 2, 1... GO!")
    self.set_border_width(10)
    self.set_size_request(450,150)

    grid = Gtk.Grid()
    self.add(grid)

    self.draw_button = Gtk.Button(label="Draw Card")
    self.draw_button.connect("clicked", self.on_draw_button_clicked)
    grid.attach(self.draw_button,0,0,1,1)

    end_button = Gtk.Button(label="End Game")
    end_button.connect("clicked", self.on_stop_button_clicked)
    grid.attach_next_to(end_button, self.draw_button, Gtk.PositionType.RIGHT, 1, 1)

    update_button = Gtk.Button(label="Update")
    update_button.connect("clicked", self.update, grid)
    grid.attach_next_to(update_button, end_button, Gtk.PositionType.RIGHT, 1, 1)

  def update(self, widget, grid):
    card1_button = Gtk.Button(label="card1")
    card1_button.connect("clicked", self.on_card1_button_clicked)
    grid.attach_next_to(card1_button, self.draw_button, Gtk.PositionType.BOTTOM, 3, 1)
    self.show_all()      # So that we can see the freshly created button

  def on_draw_button_clicked(self, widget):
    for x in range(13):
      card = my_deck.draw_card()

  def on_stop_button_clicked(self, widget):
    self.close()         # Instead of Gtk.main_quit()

  def on_card1_button_clicked(self, widget):
    self.close()         # Instead of Gtk.main_quit()

# Objects must be instantiated here
my_deck = Deck()
print my_deck.deck
win = MyWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you! It would have taken me forever to find self.show_all() Also " It will let you track this button in other methods. " will go a long way in helping me understand how all of this works together :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.