2012-05-10 11 views
1

クラスを正しく使用しているかどうかわかりません。私はpygameを使用して簡単なメニューを構築しようとしています。これは私の最初のGUIのものへの進出です。自分のコードをどのように構造化するのか分かりません。クラス "A"からクラス "B"のインスタンスメソッドをどのように呼び出すのですか?

マウスオーバー/マウスクリックのすべてを処理する一般的なButtonクラスを作成してから、各ボタンのサブクラス化を行い、各ボタンに特定のアクションを与えるためにdo_actionメソッドをオーバーライドすることができます。あなたが見ることができるように

class Button(pygame.sprite.Sprite): 
    global screen_flags 
    def __init__(self, images, pos): 
     pygame.sprite.Sprite.__init__(self) 
     self.images = images 
     self.image = images[0] 
     self.rect = self.image.get_rect() 
     self.rect.move_ip(pos) 


    def update(self, events, surface): 
     # if not screen_flags['config']: 
     for event in events: 
      if event.type == MOUSEMOTION: 
       if self.rect.collidepoint(event.pos): 
        self.image = self.images[1] 
       else: 
        self.image = self.images[0] 
      elif event.type == MOUSEBUTTONDOWN: 
       if event.button == 1 and self.rect.collidepoint(event.pos): 
        self.image = self.images[-1] 
        screen_flags['config'] = 1 
        self.do_action() 
        self.set_flag() 

      elif event.type == MOUSEBUTTONUP: 
       self.image = self.images[0] 


     screen.blit(self.image, self.rect) 

    def do_action(self): 
     pass 
    def set_flag(self): 
     pass 


class CheckBox(Button): 
    def __init__(self, images, pos): 
     Button.__init__(self, images, pos) 
     self.is_clicked = False 

    def update(self, events, surface): 
     for event in events: 
      if event.type == MOUSEMOTION: 
       if not self.is_clicked: 
        if self.rect.collidepoint(event.pos): 
         self.image = self.images[1] 
        else: 
         self.image = self.images[0] 
      elif event.type == MOUSEBUTTONDOWN: 
       if event.button == 1 and self.rect.collidepoint(event.pos): 
        if not self.is_clicked: 
         self.image = self.images[-1] 
         self.is_clicked = True 
        else: 
         self.image = self.images[0] 
         self.is_clicked = False 
     screen.blit(self.image, self.rect) 


class Cancel(Button): 
    def do_action(self): 
     screen_flags['config'] = 0 

そう、彼らは本当にはまだ何もしていません。私はチェックボックスのオンとオフを切り替えることができ、一つの 'config'ウィンドウを開いて閉じることができますが、それは私が得た限りです。コードの残りの部分は次のとおりです。

global count 
global sTime 



config_button_img = load_sliced_images(25, 25, c_buttons) 
config_button = Button(config_button_img, (608,4)) 

input_bar = load_sliced_images(351,33, inpt_bar) 
text_box = Textbox(input_bar, (144,155)) 

s_button = load_sliced_images(110,32, sbmt_bttn) 
submit = Button(s_button, (241,301)) 

c_button = load_sliced_images(110,32, cncl_bttn) 
cancel = Cancel(c_button, (385, 301)) 

c_boxes = load_sliced_images(20,19, chk_box) 
check_box = CheckBox(c_boxes, (200,200))  

try: 
    while True: 
     # **************************** 
     # Pygame section 
     events = pygame.event.get() 
     for event in events: 
      if event.type == QUIT: 
       screen_flags['alert'] = 1 
       ding.play(0,1000) 
      elif event.type == MOUSEBUTTONDOWN: 
       text_box.set_focus(event.button, event.pos) 





     screen.blit(background, (0,0)) 
     screen.blit(client_logo, (0,30)) 
     screen.blit(tag, (174,462)) 

     if screen_flags['config']: 
      screen.blit(config_window_img, (0,0)) 

      submit.update(events, screen) 
      cancel.update(events, screen) 
      check_box.update(events, screen) 
     if screen_flags['alert']: 
      screen.blit(alert_dialog, (0,0)) 

     config_button.update(events, screen) 
     pygame.display.update() 








except KeyboardInterrupt: 
    try: 
     pygame.quit() 
    except: 
     pass 

これは期待どおりの動作です。私はここからどこに行くのか分からない。私はクラスの中でロジックを包み込み続けますか?例えば、私がしようとしている次のことは、「キャンセル」ボタンがクリックされたときにチェックボックスのチェックを外すようにすることです。

私はCancelクラスを変更してみました。

class Cancel(Button): 
    def do_action(self): 
     screen_flags['config'] = 0 
     check_box.is_clicked=False 

しかし、これは私にGlobalNameエラーを与えています。別のクラス内からインスタンスメソッドをどのように対象にしますか?これは正しい方法ですか?または、update()のようないくつかのロジックを持って、マウスの世話をしてから、クラスを処理するの変数を異なるクラスに渡すことで、main()から変数を渡すことができますか?すべてのクラスでグローバル変数を使用する必要がありますか?

guiの実践に関する良い記事はありますか?コードなどを構造化する方法が好きですか?

うまくいけば上のことが当てはまります。

+0

クラス 'A'オブジェクトへの参照を取得し、メソッドを呼び出しますか? –

答えて

2

個人的には、それぞれのクラスでコンストラクタ(__init__)の引数としてscreen_flagsを受け入れるようにしました。そして、それぞれのクラスは必要な "グローバル"データを扱います。これを行うには本当の簡単な方法は、共有データがどのように見えるかに応じて、(あなたが持っているどのように多くの異なる変数など)、あなたは、辞書を渡したいかもしれませんまたはその他の、...もちろん

class Cancel(Button): 
     def __init__(self,*args,**kwargs): 
      self.screen_flags=kwargs.pop('screen_flags') 
      Button.__init__(self,*args,**kwargs) #Some might advise you to use super here... 

     def do_action(self): 
      self.screen_flags['config'] = 0 

#now use the cancel class 
cancel=Cancel(c_button, (385, 301),screen_flags=screen_flags) 

ですオブジェクトを作成して、5,000の異なる共有データを渡す必要はありません。

これに対処する別の方法は、クラス内の "グローバル"データを "クラス変数"として定義し、そのクラスから継承することです。

class GlobalData(object): 
    stuff=None 

class FooButton(Button,GlobalData): 
    def do_action(self): 
     print self.stuff 
     #If you do something in here, don't do: self.stuff = blah 
     #instead, you *should* do: GlobalData.stuff = blah 
     #However, it is fine to change mutable objects in place. 
     #   e.g. self.stuff["dict_key"]=blah 

#Now we can assign to GlobalData and instances of 
#FooButton will see the differences immediately. 
cancel=FooButton(c_button, (385, 301)) 
cancel.do_action() 
GlobalData.stuff="Cows say Moo" 
cancel.do_action() 

これが役立ちます。あなたの投稿にはたくさんのものがあったので、それを並べ替えるのは少し難しかったです。場合

EDIT

あなたはdo_action内のコメントを参照して、クラス変数がどのように扱われるかを理解していません。基本的に、あなたはあなたのデータに手を失わないように注意する必要があります...

+0

これはクールです。ありがとう!私はGlobalDataクラスの考えが本当に好きです。すべてを把握するのが簡単なようだ。ありがとう!! – Zack

+0

@Zack - 問題ありません。喜んで助けてください。私はパイゲームを使ったことは一度もありません。私は自分自身のTkinterの男です。物事を行うさまざまな方法のいくつかを見るのは面白いです。私が考えたばかりのGlobalDataクラスの崩壊が1つあります...私は編集します。 – mgilson

0

GUIのものはより素敵に行うことができます。

はい、コントロールをクラスでラップします。

私はこれを試してみることをお勧めします。

まず、は、コントロールの論理インターフェイスを定義します。実装の詳細については一分忘れてください。任意のコントロールをクリックできます。メソッドonClick(pos)を定義します。チェックボックスをオンまたはオフにすることができます。 setChecked(bool)を定義します。 Windowsは表示または非表示にすることができ、setVisible(bool)などを定義します。

の共通祖先を作成します。イベントハンドラ内でonClick(event.pos)と呼び出します。デフォルトの実装は何もしません。クリックを模倣したいときに今すぐコントロールのonClick()に電話をかけることができます。 onMouseDownonMouseUpにはクリックアニメーション、ホバーイベントの場合はonMouseInonMouseOutなどが必要です。イベントディスパッチの詳細について気になるのは、共通の祖先だけです。

グローバル状態を直接参照しないでください。それはあらゆる種類の不愉快なものにつながります。代わりに、すべてのコントロールに状態とその変更方法を知らせてください(私たちはとにかくOOPをやっています)。したがって、チェックボックスはisChecked()メソッドなどを取得します。

キャンセルボタンは、onClickメソッドとコンストラクタをオーバーライドするだけで済みます。コンストラクタでは、CheckBoxインスタンスを渡します。 cancel_button.onClickButton.onClickと電話をしてからself.check_box.setChecked(False)を呼び出してください。

関連する問題