Python GTK:使用另一个按钮将按钮添加到 GUI

Python GTK: Add a button to a GUI with another button

我正在尝试通过按 GUI 本身上的按钮向我的 GUI 添加另一个按钮。本质上我只是想更新它,但我对 OOP 比较陌生,所以我遇到了范围问题。

这是我目前所拥有的...

  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()

当我 运行 执行此操作时,我的 GUI 弹出。当我点击更新按钮时,出现以下错误:

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

如何让我的更新函数识别我已经在 def init 函数中创建的 GUI/grid?有没有更好的方法来做我想做的事?

在您的 MyWindow class 中定义一个 instance variable 以跟踪该按钮。

例如,在您的代码中,只要您看到 draw_button 就将其更改为 self.draw_button。它会让您以其他方法跟踪此按钮。这看起来像:

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()

但是您的代码中还有其他一些问题:

  • 我假设您使用的是 Gtk 3.0。如果是这样的话,你应该像这样在导入 Gtk 之前要求它:

    gi.require_version('Gtk', '3.0')
    from gi.repository import Gtk
    
  • Deck.__init__() 中,您在 for 循环中使用了 range(1,2)。问题是 range(1, 2) 等同于 [1] 因为您要求的范围从 1 开始但在 2 之前停止。我不确定那是您想要的。

  • 您应该在 MyWindow.update() 方法的末尾添加一个 self.show_all() 否则您将看不到新创建的按钮。
  • 您应该在 MyWindow.on_stop_button_clicked()MyWindow.on_card1_button_clicked() 方法中使用 self.close() 而不是 Gtk.main_quit() 否则您的代码将无法正确破坏您的 window 单击这些按钮时。

这是这些建议的样子:

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()