본문 바로가기
Programming/Python

wxPython 기본 위젯 - 002 - Panel Container Widget

by The Programmer 2026. 9. 6.

1. Introduction

 

wxPython 모듈 속에 들어 있는 주요 컨테이너(Container)인 wx.Panel에 대해 알아보겠습니다.

 

wx.Panel의 특성을 GUI 프로그래밍 관점에서 가장 핵심적인 항목들을 살펴보겠습니다. 이 위젯은 단순한 사각형 영역이 아니라, (특별히 위젯 배치와 관련해서) 애플리케이션의 '논리적 구조'를 담당하는 뼈대입니다.  이 패널은 기본적으로 다음과 같은 특징을 가지고 있습니다. 

■ wx.Panel 핵심 특성 7가지

1) 기본 컨테이너 위젯 : wx.Panel은 다른 위젯(버튼, 텍스트, 슬라이더 등)을 담기 위해 설계된 가장 표준적인 컨테이너입니다. wx.Frame에 직접 위젯을 올리는 것보다 패널 위에 올리는 것이 훨씬 안정적입니다.

2) 무한 중첩 가능 : 패널은 다른 패널을 내포할 수 있습니다. 이를 통해 복잡한 화면 구성을 구역별로 독립적인 '작은 컨테이너(패널)' 단위로 쪼개어 관리할 수 있습니다. (예: 헤더 패널, 본문 패널, 사이드바 패널)

3) 레이아웃(Sizer)의 도화지 : wx.Panel은 Sizer(레이아웃 관리자)를 적용하기에 최적의 대상입니다. 패널에 SetSizer()를 호출하면, 그 패널 내부의 모든 자식 위젯들은 해당 Sizer의 규칙에 따라 자동으로 배치됩니다.

4) 윈도우 간 호환성 및 포커스 관리 : 윈도우(Windows), 맥(macOS), 리눅스 등 OS마다 배경색 처리 방식이나 위젯의 기본 동작이 조금씩 다른데, wx.Panel은 이를 일관되게 처리해 줍니다. 특히 탭 키(Tab)를 눌렀을 때 다음 위젯으로 포커스가 이동하는 순서(Navigation)를 자동으로 관리합니다.

5) 부모-자식 생명주기 연동 : 패널을 부모로 두면, 해당 패널이 파괴될 때 그 안에 담긴 모든 자식 위젯(버튼 등)도 함께 메모리에서 해제됩니다. 즉, 화면의 일부 영역을 통째로 숨기거나 삭제할 때 패널 단위로 처리하면 매우 편리합니다.

6) 객체지향적 제어 (Self 활용) : 패널 내부의 위젯들을 제어하려면 self.위젯이름 형태로 인스턴스 변수로 저장해야 합니다. self가 붙은 위젯들은 프로그램이 실행되는 동안 메모리에 유지되며, 이벤트 핸들러 등 어디에서든 호출하여 속성을 변경할 수 있습니다.

7) 시각적 스타일링의 기초 : SetBackgroundColour() 등을 사용하여 패널 단위로 배경색을 지정할 수 있습니다. 이는 단순히 예쁘게 만드는 것을 넘어, 복잡한 UI에서 각 구역(컨테이너)이 어디까지인지 시각적으로 명확히 구분해 주는 디버깅 도구 역할도 합니다.

이 구조를 바탕으로 실제 버튼 클릭 이벤트를 연결하여 상태바를 바꾸거나, 메뉴를 통해 패널을 제어하는 등의 '상호작용' 단계로 넘어가는 것도 가능합니다.

 

다음은 학습 준비용으로 만든 템플릿(Template) 코드입니다. 템플릿 코드란 미리 만들어두고 복사/붙여넣기 등을 통해서 손쉽게 코드 작성을 하기 위한 일종의 재활용 가능한 샘플 코드를 뜻합니다. 전체 5줄 짜리 코드입니다.

 

■ 코드 템플릿(Template) 작성하기

 

1) 이미 만들어져 있는 외부 모듈 wxPython 모듈 추가. 이름에 주의할 것. wxPython은 외부 모듈이기 때문에 추가로 설치되어야 합니다. 정상적으로 wxPython이 설치되어 있어야만 다음 문장이 작동합니다.

 

import wx

 

2) wx앱 인스턴스 만들기. 이후 wx앱 메인루프 실행. wxPython으로 만든 모든 Windows용 앱의 기본 방식임.앱 인스턴스가 하나는 반드시 필요하고(필수), wx앱 인스턴스 생성후 메인 루프가 반드시 따라와야 합니다.

 

myApp = wx.App()

myApp.MainLoop()

 

3) Visual Window용 프레임 추가. 시각적으로 보이는 윈도우용 프레임은 Show()가 필요합니다.

Panel이나 Button은 이것이 불필요합니다.

 

myFrame = wx.Frame()
myFrame.Show()

 

4) wx.Frame()에 옵션 항목들을 채워넣습니다.

 

myFrame = wx.Frame( parent=None, title=" wxPython Sample Code Template v1.0.0 ", size=(640, 400) )

 

옵션들을 다 채워넣으면 정상 작동 여부를 테스트합니다. 이 시점에서 코드를 실행하면 시각적으로 Window 하나가 나타나야 합니다. 물론 특별한 기능은 없습니다만!

 

5) 완성된 코드 템플릿

코드 템플릿 1-1

import wx

myApp = wx.App()

myFrame = wx.Frame( parent=None, title="wxPython Sample Code Template v1.0.0", size=(640, 400) )
myFrame.Show()

myApp.MainLoop()

# 복사/붙여넣기로 재활용해도 될 듯합니다.

 

 

■ 위 코드 템플릿 실행 결과 :

 

 

2. Code

 

2.1 wx.Panel Code : 초급용/기본 과정용.

 

1) 템플릿 불러오기 : 먼저 템플릿 코드를 그대로 가져와서 최소한의 코드 추가를 합니다.

import wx

myApp = wx.App()

myFrame = wx.Frame( parent=None, title="wxPython Sample Code Template v1.0.0", size=(640, 400) )
myFrame.Show()

myApp.MainLoop()

 

2) wx.Panel 코드 추가하기 : myPanel = wx.Panel()

 

import wx

myApp = wx.App()

myFrame = wx.Frame( parent=None, title="wxPython Sample Code Template v1.0.0", size=(640, 400) )

myPanel = wx.Panel()
myFrame.Show()

myApp.MainLoop()

 

주의 : 위 템플릿의 myFrame.Show()처럼 Frame에는 Show()가 필요하지만, 패널에는 불필요함

 

3) Panel()에 옵션 항목들을 채워넣습니다.

myPanel = wx.Panel( parent=myFrame )

 

4) 패널에 배경색을 추가합니다.

myPanel.SetBackgroundColour(wx.Colour(255, 255, 200))

 

5) 패널에 텍스트 라벨을 추가합니다.

myText = wx.StaticText(myPanel, label="이름을 입력하세요:", pos=(20, 20))

 

6) 텍스트 입력 위젯 추가

myText_Ctrl = wx.TextCtrl(self.myPanel, style=wx.BORDER_SIMPLE, pos=(20, 50), size=(200, 25))  
myText_Ctrl.SetBackgroundColour(wx.Colour(255, 255, 200))  # 연한 노랑색

 

7) 버튼 추가

myBtn1 = wx.Button(self.myPanel, label="(20, 100)")
myBtn1.SetPosition((20, 100))

 

8) 버튼 클릭 이벤트 핸들러 함수 작성

def OnBtn1Click(event):

    print("천재적입니다. 인정하십니까? ^.^;")

 

# 이벤트 핸들러 함수는 상단에 배치할 것. 'event' 빼먹지 않도록 주의할 것.

 

9) 버튼과 이벤트 핸들러 연결하기 : 바인딩

myBtn1.Bind(wx.EVT_BUTTON, OnBtn1Click)

 

코드 템플릿 2 - 1

import wx

# 버튼 클릭 이벤트 핸들러 함수를 작성합니다. 상단에 배치할 것. 그래도 import wx 문장 아래.
def OnBtn1Click(event):
    print("천재적입니다. 인정하십니까? ^.^;")

myApp = wx.App()

# Frame()에 홉션 항목들을 채워넣습니다.
myFrame = wx.Frame( parent=None, title="wxPython Sample Code Template v1.0.0", size=(640, 400) )

# Panel()에 옵션 항목들을 채워넣습니다.
myPanel = wx.Panel( parent=myFrame )    # Frame에는 Show()가 필요하지만, 패널에는 불필요함.
myPanel.SetBackgroundColour(wx.Colour(255, 255, 200))    # 패널에 배경색을 추가합니다.

# 패널에 텍스트 라벨을 추가합니다.
myText = wx.StaticText(myPanel, label="이름을 입력하세요:", pos=(20, 20))

# 텍스트 입력 위젯 추가
myText_Ctrl = wx.TextCtrl(myPanel, style=wx.BORDER_SIMPLE, pos=(20, 50), size=(200, 25))  
myText_Ctrl.SetBackgroundColour(wx.Colour(255, 255, 200))  # 배경색 지정 : 연한 노랑색

# 버튼 추가
myBtn1 = wx.Button(myPanel, label="집중하세요!", pos=(480, 300))
# myBtn1.SetPosition((20, 100))    # 버튼 위치 결정

# 버튼과 이벤트 핸들러 연결하기 : 바인딩
myBtn1.Bind(wx.EVT_BUTTON, OnBtn1Click)

myFrame.Show()

myApp.MainLoop()


# 클래스 구조 없이 평범한 플랫 코딩. 기본적 내용 학습에 적당합니다.

 

 

 

2.1 Result

 

 

 

 

2.2 Code ( 중급용. 클래스 구조로 된 코드임. )

 

"""
Program Name : Panel Container Widget
Version : 1.0.1
Date : 2026-09-06

Comments : 중급용. 클래스 구조를 사용한 앱입니다. 클래스를 모르면 이해하기 힘들 수 있습니다.

 

"""

import wx

class MyFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, wx.ID_ANY,  title="Panel Container v1.0.1", size=(640, 400))
        
        self.myPanel = wx.Panel(self, wx.ID_ANY )
        self.myPanel.SetBackgroundColour(wx.Colour(255, 255, 200))

        self.myBtn1 = wx.Button(self.myPanel, label="(20, 100)")
        self.myBtn1.SetPosition((20, 100))

        self.myBtn2 = wx.Button(self.myPanel, label="(100, 100)")
        self.myBtn2.SetPosition((100, 100))
        # 안내문 역할 라벨 위젯
        myLabel = wx.StaticText(self.myPanel, label="이름을 입력하세요:", pos=(20, 20))  
        # 텍스트 입력 위젯
        myText_Ctrl = wx.TextCtrl(self.myPanel, style=wx.BORDER_SIMPLE, pos=(20, 50), size=(200, 25))  
        myText_Ctrl.SetBackgroundColour(wx.Colour(255, 255, 200))  # 연한 노랑색
        # 확인 버튼 위젯
        myBtn3 = wx.Button(self.myPanel, label="확인", pos=(500, 300))

if __name__ == "__main__":
    myApp = wx.App()

    myFrame = MyFrame()
    myFrame.Show()

    myApp.MainLoop()

 

 

2.2 Result

 

[ Panel Container Widget ]

 

 

3. 중급 연습 과제

 

1) 위 중급용 코드에 버튼 이벤트 핸들러를 작성해서 버튼이 실제로 작동되게 하세요.

위 기본 코드에 있는 이벤트 핸들러 함수 작성법과 바인딩 방법을 참고하세요.

 

2) 초급용 코드와 중급용 클래스 도입 코드를 비교해보면 self 키워드가 돋보입니다. 아래 Notes 내용을 참고해서 self 키워드에 대해 학습하세요.

 

3) 인스턴스 변수와 지역 변수를 구분하세요.

 

4) 버튼 클릭에만 반응하지 않고, 마우스 포인트를 버튼 위에 올리기만 해도 작동하게 할 수 있나요?

이 방식의 장단점은 무엇인가요?

 

 

4. Notes

 

 

wxPython의 패널 컨테이너가 사용되었습니다. wxPython의 sizer와 같은 종류의 대표적 컨테이너 위젯입니다.

 

 

보충 : self 키워드의 유무에 따른 의미 차이


파이썬 객체지향 프로그래밍에서 변수 앞에 self를 붙이느냐 마느냐는
변수의 스코프(Scope, 유효 범위)와 생명주기(Lifespan)를 결정합니다.

self가 있는 경우 (인스턴스 변수)
- 의미 : 클래스로부터 생성된 객체(인스턴스)의 속성(Attribute)이 됩니다.
- 특징 : __init__ 메서드 실행이 끝난 후에도 클래스 내의 다른 메서드(이벤트 핸들러 등)에서
self.myPanel, self.myBtn1 형태로 자유롭게 다시 접근하고 제어할 수 있습니다.
객체가 살아있는 동안 메모리에 유지됩니다.

self가 없는 경우 (지역 변수)
- 의미 : 변수가 선언된 특정 메서드 내부에서만 잠시 사용되는 지역 변수(Local Variable)가 됩니다.
- 특징 : __init__ 메서드가 종료되는 순간 메모리에서 사라집니다.
따라서 클래스 내의 다른 메서드에서는 이 변수들을 전혀 인식하지 못하며,
접근하려고 하면 NameError가 발생합니다.

GUI 프로그램(wxPython) 관점에서의 차이
위 코드에서 self.myPanel, self.myBtn1처럼 self를 붙이는 이유는 나중에 제어하기 위함입니다.
사용자가 버튼을 클릭했을 때 버튼의 텍스트를 바꾸거나, 패널의 배경색을 변경하거나,
위젯을 숨기는 등의 동작(이벤트 처리)을 하려면 다른 메서드에서 해당 위젯을 찾아야 합니다.
만약 버튼에 self를 붙이지 않았다면, 생성만 될 뿐 나중에 코드로 조작할 방법이 사라지게 됩니다.

 

 

■ wx.EVT_BUTTON 보충 수업

더보기

[ wx.EVT_BUTTON 보충]

 

 

- 참고 코드 : 다음 코드를 참고할 것.

▶▶    https://grammar.tistory.com/108

   buttonClick.Bind(wx.EVT_BUTTON, self.OnBtnClickMe)   

 

wx.EVT_BUTTON은 wxPython에서 사용자가 버튼을 클릭했을 때 발생하는 이벤트를 감지하고, 이를 처리할 함수(이벤트 핸들러)와 연결해 주는 이벤트 바인더(Event Binder)입니다

주어진 코드 buttonClick.Bind(wx.EVT_BUTTON, self.OnBtnClickMe)의 각 구성 요소와 동작 방식은 다음과 같습니다.

- buttonClick: 이벤트를 발생시키는 대상 위젯(버튼 인스턴스)입니다.
- .Bind(): 특정 이벤트와 그 이벤트를 처리할 함수를 서로 연결(Binding)해 주는 wxPython 위젯의 기본 메서드입니다.
- wx.EVT_BUTTON: 버튼이 클릭되었음을 알리는 이벤트 타입입니다. 사용자가 마우스로 버튼을 누르거나 키보드(Space, Enter 등)로 버튼을 작동시킬 때 발생합니다.
- self.OnBtnClickMe: 이벤트가 발생했을 때 실제로 실행될 사용자 정의 메서드(콜백 함수)입니다.

 

이벤트 핸들러 작성 방법

 

wx.EVT_BUTTON과 연결되는 메서드는 반드시 이벤트 객체(event)를 인자로 받을 수 있도록 정의해야 합니다.

def OnBtnClickMe(self, event):
    # 버튼이 클릭되었을 때 수행할 작업
    print("버튼이 클릭되었습니다!")
    
    # 이벤트 객체를 통해 추가 정보 확인 가능 (예: 어떤 버튼인지)
    btn = event.GetEventObject()
    print(f"클릭된 버튼의 레이블: {btn.GetLabel()}")

 

동작 흐름

- 사용자가 화면의 버튼(buttonClick)을 클릭합니다.
- wxPython 시스템이 이를 감지하고 wx.CommandEvent 타입의 이벤트 객체를 생성합니다.
- .Bind()를 통해 미리 연결해 둔 self.OnBtnClickMe 메서드가 호출되며, 생성된 이벤트 객체가 인자로 전달됩니다.
- 개발자가 작성한 핸들러 내부의 로직(화면 변경, 데이터 처리 등)이 실행됩니다.

 

이처럼 위젯에 이벤트를 바인딩함으로써 정적인 화면에 동적인 상호작용 기능을 부여할 수 있습니다.

EVT_BUTTON은 마우스 오버(Hover) 시에 발생하지 않습니다. 이 이벤트는 오직 사용자가 버튼을 '활성화(클릭하거나 키보드의 Enter/Space를 누름)'했을 때만 발생합니다.

이름이 EVT_BUTTON이라 버튼에 일어나는 모든 이벤트처럼 보일 수 있지만, 이는 버튼이라는 위젯의 명령(Command) 이벤트, 즉 "버튼이 눌려서 실행되어야 한다"는 의미를 담고 있습니다.

마우스가 버튼 위에 올라오거나 벗어나는 등의 동작을 감지하려면 마우스 이벤트 바인더를 따로 사용해야 합니다.

마우스가 버튼 위로 올라올 때 (Mouse Over)wx.EVT_ENTER_WINDOW

마우스가 버튼에서 벗어날 때 (Mouse Out)wx.EVT_LEAVE_WINDOW

 

사용 예시

# 마우스가 버튼 위에 올라갔을 때
button.Bind(wx.EVT_ENTER_WINDOW, self.OnMouseEnter)

# 마우스가 버튼에서 벗어났을 때

button.Bind(wx.EVT_LEAVE_WINDOW, self.OnMouseLeave)

 

이처럼 버튼의 '상호작용' 종류에 따라 사용하는 이벤트 바인더가 완전히 구분되어 있습니다.

.

.

 

 

■ 예습용. 추가 응용 연습 과제

1) 앱 + 프레임 + 패널 + 버튼

2) 앱 + 프레임 + 패널 + 버튼 + 메뉴 + 상태바

 

 

5. Files

 

wxPython_Intro_Sample_001_.py
0.00MB
wxPython_Intro_Sample_002_.py
0.00MB
wxPython_Intro_Sample_003_.py
0.00MB

 

 

예습용. 중급 추가 연습용

wxPython_Intro_Ex_007_Panel_001_.py
0.00MB
wxPython_Intro_Ex_007_Panel_002_with_MenuBar_n_StatusBar_.py
0.00MB
wxPython_Intro_Ex_007_Panel_003_with_MenuBar_Extended_n_StatusBar_.py
0.01MB

 

 

6. Ref.

 

 

Happy Programming!

^.^;