2012-05-10 4 views
1

클래스를 올바르게 사용하고 있는지 잘 모르겠습니다. 파이 게임을 사용하여 간단한 메뉴를 만들려고합니다. 이것은 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) 

입니다 개체를 사용하여 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에 주석이 표시되지 않는 경우

편집 할 수 있습니다. 기본적으로 데이터에 대한 핸들을 잃지 않도록 조심해야합니다 ...

+0

이것은 시원합니다. 감사! 저는 GlobalData Class 아이디어를 정말 좋아합니다. 모든 것을 추적하는 것이 쉬운 것처럼 보입니다. 감사!! – Zack

+0

@Zack - 문제 없습니다. 기꺼이 도와주세요. 나는 파이 게임을 한 번도 사용하지 않았고, 나는 스스로 Tkinter 녀석이다. 여러 가지 일을하는 방법을 보는 것은 흥미로운 일입니다. 내가 방금 생각한 GlobalData 클래스의 하나의 몰락이있다. 나는 편집 할 것이다. – mgilson

0

GUI 물건을 더 좋게 만들 수 있습니다.

예, 컨트롤을 클래스로 래핑하십시오.

시도해 보시기 바랍니다.

먼저 은 사용자 컨트롤에 대한 논리적 인터페이스를 정의합니다. 1 분 동안 구현 세부 사항은 잊어 버리십시오. 모든 컨트롤을 클릭 할 수 있습니다. 메소드 onClick(pos)을 정의하십시오. 확인란을 선택하거나 선택을 취소 할 수 있습니다. setChecked(bool)을 정의하십시오. Windows는 표시하거나 숨길 수 있으며 setVisible(bool) 등을 정의합니다.

클릭 가능한 컨트롤에 대해 공통 조상을 만듭니다. 해당 이벤트 처리기 내에서 onClick(event.pos)으로 전화하십시오. 기본 구현은 아무 것도하지 않습니다. 이제는 클릭을 모방하려고 할 때 onClick() 컨트롤로 호출 할 수 있습니다. onMouseDownonMouseUp을 클릭 애니메이션, onMouseInonMouseOut 호버 이벤트 등을 수행해야합니다. 이벤트 발송에 대한 자세한 내용을 신경 써야하는 유일한 장소는 공통 조상입니다.

글로벌 상태을 직접 참조하지 마십시오. 그것은 모든 종류의 불쾌한 것들로 인도합니다. 대신 모든 컨트롤에 상태와 변경 방법을 알리십시오 (우리는 어쨌든 OOP을 수행하고 있습니다). 따라서 체크 박스는 isChecked() 메서드 등을 가져옵니다.

지금 취소 버튼은 onClick 메서드 및 생성자를 재정 의하여해야합니다. 생성자에서 CheckBox 인스턴스를 전달하십시오. cancel_button.onClick에서 Button.onClick으로 전화 한 다음 self.check_box.setChecked(False)으로 전화하십시오.

관련 문제