1

クラスを正しく使用しているかどうかはわかりません。pygame を使用して簡単なメニューを作成しようとしています。これは、GUI に関する私の最初の進出です。コードを構成する方法がわかりません。

マウス オーバー/マウス クリックのすべてを処理する一般的な 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

ご覧のとおり、彼らはまだ何もしていません。チェックボックスのオンとオフを切り替えたり、1 つの「構成」ウィンドウを開いたり閉じたりすることはできますが、それは私の知る限りです。コードの残りの部分:

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 の実践に関する良い記事はありますか。コードの構造などのようなもの..?

うまくいけば、上記は理にかなっています。

4

2 に答える 2

2

screen_flags個人的には、各クラスがコンストラクター ( ) の引数として受け入れられるようにします__init__。次に、各クラスは、必要な「グローバル」データのハンドルを持ちます。これを行うための本当に簡単な方法は...

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)

もちろん、共有データがどのように見えるか (いくつの異なる変数があるかなど) に応じて、5000 個の異なる共有データを渡す必要がないように、辞書やその他のオブジェクトを渡してそれを作成したい場合があります。その周り。

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

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

これが役立つことを願っています。投稿数が多かったので、整理するのが少し大変でした。

編集

クラス変数の処理方法がわからない場合は、 のコメントを参照してくださいdo_action。基本的に、データのハンドルを失わないように注意する必要があります...

于 2012-05-10T18:25:23.850 に答える
0

GUI の操作をより適切に行うことができます。

はい、コントロールをクラスにラップしてください。

これを試すことをお勧めします。

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

クリック可能なコントロールの共通の祖先を作成します。そのイベント ハンドラ内で、 を呼び出しますonClick(event.pos)。デフォルトの実装は何もしません。onClick()クリックを模倣したいときにコントロールを呼び出すことができるようになりました。クリック アニメーションやホバー イベントなどを行いたいonMouseDownと思うでしょう。イベント ディスパッチの悲惨な詳細を気にする唯一の場所は、共通の祖先です。onMouseUponMouseInonMouseOut

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

これで、キャンセル ボタンはそのonClickメソッドとコンストラクタをオーバーライドするだけで済みます。コンストラクターで、CheckBoxインスタンスを渡します。cancel_button.onClickちょうど呼び出してButton.onClickからself.check_box.setChecked(False)

于 2012-05-10T19:03:52.993 に答える