01. wxPython 그래픽 사용자 인터페이스
- https://www.wxwidgets.org
- Python에 내장된 Tkinter UI toolkit에 비하여 더욱 향상된 GUI 환경 지원
- 1992년부터 개발되어온 wxWidget을 파이썬 개발 환경에서 사용가능 하도록 변경한 버전으로
C#, Perl, Java도 지원함.
1. pip를 이용한 라이브러리 설치
- 관련 library를 다운로드 받아 자동으로 설치해줌.
- 공식 지원은 Python 2.7을 지원하나 개발 버전으로 Python 3.0을 지원하는
피닉스(Phoenix)라고하는 프로젝트를 제공함.
1) https://wxpython.org/Phoenix/snapshot-builds/ 접속
- whl: wheel 파일, pip를 이용하여 파이썬 설치를 자동으로 지원하는 형식
파일명: wxPython_Phoenix-3.0.3.dev2864+4fc5f9e-cp35-cp35m-win_amd64.whl
cp35: Python 3.5, amd64: 64 bit
2) 설치
① Python3.5 기반
F:\201701_python\setup>pip install wxPython_Phoenix-3.0.3.dev2864+4fc5f9e-cp35-cp35m-win_amd64.whl
Processing f:\201701_python\setup\wxpython_phoenix-3.0.3.dev2864+4fc5f9e-cp35-cp35m-win_amd64.whl
Collecting six (from wxPython-Phoenix==3.0.3.dev2864+4fc5f9e)
Downloading six-1.10.0-py2.py3-none-any.whl
Installing collected packages: six, wxPython-Phoenix
Successfully installed six-1.10.0 wxPython-Phoenix-3.0.3.dev2864+4fc5f9e
② Python3.6 기반 ★ 2017년 4월 14일 발표된 wxPython library는 PyDev에서 설정 없이 자동 인식됨.
F:\201701_python\setup>pip install wxPython_Phoenix-3.0.3.dev2902+a79cd32-cp36-cp36m-win_amd64.whl
Processing f:\201701_python\setup\wxpython_phoenix-3.0.3.dev2902+a79cd32-cp36-cp36m-win_amd64.whl
Collecting six (from wxPython-Phoenix==3.0.3.dev2902+a79cd32)
Downloading six-1.10.0-py2.py3-none-any.whl
Installing collected packages: six, wxPython-Phoenix
Successfully installed six-1.10.0 wxPython-Phoenix-3.0.3.dev2902+a79cd32
* 32bit: pip install wxPython_Phoenix-3.0.3.dev2902+a79cd32-cp36-cp36m-win32.whl
F:\201701_python\setup>pip list
DEPRECATION: The default format will switch to columns in the future. You can us
e --format=(legacy|columns) (or define a format=(legacy|columns) in your pip.con
f under the [list] section) to disable this warning.
pip (9.0.1)
setuptools (28.8.0)
six (1.10.0)
wxPython-Phoenix (3.0.3.dev2864+4fc5f9e)
2. 삭제
pip uninstall wxPython-Phoenix
3. Update
pip install --upgrade wxPython-Phoenix
4. Search
pip search wxPython-Phoenix
5. Eclipse Neon 2 Pydev에서 wxPython 인식 안됨으로 Python IDLE 사용을 권장함.
02. wx.App class
- wxPython초기화 및 구동, 이벤트 처리등을 실행함으로 wxPython을 이용하는 모든 어플은
반드시 하나의 wx.App의 인스턴스를 갖고 있어야 한다.
1. 처리 흐름
○ 시작
↓
【 wx.App 객체 생성 】 OnInit() 호출
↓
【 위젯 생성 】 Frame, Button, List등 각종 위젯 생성
↓
【 이벤트 처리기 등록 】 이벤트와 이벤트 처리기 연결
↓
【 wx.App.MainLoop() 호출 】 이벤트 루프 실행
↓
○ 종료
2. 기초 코드
import wx
app = wx.App()
top = wx.Frame(parent=None, title="Hello World", size=(300,200))
top.Show()
app.MainLoop()
3. 윈도우 생성
▷ /wxexam/StartingWxPython.py
-------------------------------------------------------------------------------------
# -*- coding: utf-8 -*-
import wx
app = wx.App() # wxPython 사용 객체 생성
# 하나의 화면 생성
frame = wx.Frame(parent=None, title='Hello!')
frame.Show() # 화면 출력
app.MainLoop() # 이벤트 수신 대기
-------------------------------------------------------------------------------------
- OnInit(self): __init__() 내부적으로 생성자를 호출하고 widget 생성을위해 호출됨.
- if __name__ == "__main__": 현재 스크립트가 python 명령에의해 직접 실행 될 경우만 실행
▷ /wxexam/OnInit.py
-------------------------------------------------------------------------------------
# -*- coding: utf-8 -*-
import wx
class MyApp(wx.App): # wx.App 상속
def OnInit(self): # 초기화
frame = wx.Frame(parent=None, title="Hello World", size=(300,200))
frame.Show(True) # 화면 출력
return True
if __name__ == "__main__":
app = MyApp() # 객체 생성
app.MainLoop() # 이벤트 루프 시작
-------------------------------------------------------------------------------------
5. Frame 생성
- wx.Frame.__init__(self, parent=None, title="Empty Window"): 부모클래스의
생성자를 호출하며서 초기값을 전달, 호출시 첫번째 인수로 self를 전달해야함.
▷ /wxexam/EmptyWindow.py
-------------------------------------------------------------------------------------
# -*- coding: utf-8 -*-
import wx
class MyFrame(wx.Frame):
def __init__(self): # 생성자 선언
# 부모 클래스의 생성자 호출
wx.Frame.__init__(self, parent=None, title="Empty Window")
if __name__ == "__main__":
app = wx.App()
frame = MyFrame()
frame.Show()
app.MainLoop()
-------------------------------------------------------------------------------------
6. Event의 등록
- self.Bind(wx.EVT_CLOSE, self.OnClose): 이벤트 등록, 이벤트 처리 핸들러 함수
- wx.MessageBox("윈도우를 닫을까요?", "확인", wx.YES_NO): 메시지, 창 제목, 다이얼로그의 종류
- event.Skip(True): 아니오를 눌러도 윈도우 닫힘.
- https://wxpython.org/Phoenix/docs/html/wx.functions.html#wx.MessageBox
▷ /wxexam/CloseEvent.py
-------------------------------------------------------------------------------------
# -*- coding: utf-8 -*-
import wx
class MyFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, parent=None, title="Close Event")
# 이벤트 등록, 이벤트 종류, 이벤트 핸들러(메소드)
self.Bind(wx.EVT_CLOSE, self.OnClose)
def OnClose(self, event):
sw = wx.MessageBox("윈도우를 닫을까요?", "확인", wx.YES_NO);
print('sw:' + str(sw)); # 2 or 8
print('wx.YES_NO:' + str(wx.YES_NO));
print('wx.YES:' + str(wx.YES)); # 2
print('wx.NO:' + str(wx.NO)); # 8
if sw == wx.YES:
# 창 닫음.
self.Destroy()
else:
# 창 닫지않음
# event.Skip(True) # 아니오를 눌러도 닫힘.
event.Skip(False) # 아니오를 누르면 닫는 이벤트 무시됨.
if __name__ == "__main__":
app = wx.App()
frame = MyFrame()
frame.Show()
app.MainLoop()
print('이벤트 수신 대기');
-------------------------------------------------------------------------------------
- wx.EVT_LEFT_DOWN: 마우스 왼쪽 버튼 클릭
- wx.EVT_RIGHT_DOWN: 마우스 오른쪽 버튼 클릭
▷ /wxexam/WindowSize.py
-------------------------------------------------------------------------------------
# -*- coding: utf-8 -*-
import wx
class MyFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, parent=None, title="Window Size")
# Frame에 마우스 왼쪽 버튼 이벤트등록
self.Bind(wx.EVT_LEFT_DOWN, self.OnMouseLButtonDown)
# Frame에 마우스 오른쪽 버튼 이벤트등록
self.Bind(wx.EVT_RIGHT_DOWN, self.OnMouseRButtonDown)
def OnMouseLButtonDown(self, event):
frame.SetSize(wx.Size(400, 200))
def OnMouseRButtonDown(self, event):
frame.SetSize(wx.Size(200, 400))
if __name__ == "__main__":
app = wx.App()
frame = MyFrame()
frame.Show()
app.MainLoop()
-------------------------------------------------------------------------------------
8. 색상의 지정
▷ /wxexam/WindowColour.py
-------------------------------------------------------------------------------------
# -*- coding: utf-8 -*-
import wx
class MyFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, parent=None, title="Window Size")
# Frame에 마우스 왼쪽 버튼 이벤트등록
self.Bind(wx.EVT_LEFT_DOWN, self.OnMouseLButtonDown)
# Frame에 마우스 오른쪽 버튼 이벤트등록
self.Bind(wx.EVT_RIGHT_DOWN, self.OnMouseRButtonDown)
def OnMouseLButtonDown(self, event):
self.SetSize(wx.Size(400, 200))
def OnMouseRButtonDown(self, event):
self.SetSize(wx.Size(200, 400))
app = wx.App()
frame1 = MyFrame()
frame1.Show()
app.MainLoop()
-------------------------------------------------------------------------------------
- wx.DEFAULT_FRAME_STYLE: 기본 윈도우 Style
- wx.CAPTION: 창 제목 출력
- wx.RESIZE_BORDER: 윈도우 외곽의 크기조정 경계 표시
▷ /wxexam/WindowStyle.py
-------------------------------------------------------------------------------------
# -*- coding: utf-8 -*-
import wx
class MyFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, parent=None, title="Window Style")
self.Bind(wx.EVT_LEFT_DOWN, self.OnMouseLButtonDown)
self.Bind(wx.EVT_RIGHT_DOWN, self.OnMouseRButtonDown)
def OnMouseLButtonDown(self, event):
self.SetWindowStyle(wx.RESIZE_BORDER | wx.CAPTION)
def OnMouseRButtonDown(self, event):
self.SetWindowStyle(wx.DEFAULT_FRAME_STYLE)
if __name__ == "__main__":
app = wx.App()
frame = MyFrame()
frame.Show()
app.MainLoop()
-------------------------------------------------------------------------------------
- class MyFrame(wx.Frame): Frame class의 상속
- btnClick.Bind(wx.EVT_BUTTON, self.OnBtnClickMe): 버튼 클릭 이벤트의 등록
▷ /wxexam/SimpleButton.py
-------------------------------------------------------------------------------------
# -*- coding: utf-8 -*-
import wx
class MyFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, parent=None, title="Simple Button")
btnClick = wx.Button(self, label="Click Me!")
btnClick.Bind(wx.EVT_BUTTON, self.OnBtnClickMe)
def OnBtnClickMe(self, event):
wx.MessageBox("클릭 되었습니다!", "Simple Button", wx.OK)
if __name__ == "__main__":
app = wx.App()
frame = MyFrame()
frame.Show()
app.MainLoop()
-------------------------------------------------------------------------------------
- self.button1.SetPosition((x, y)): 좌측 상단을 0,0으로 사용
┌──────→ X
│0, 0
│
│
↓
Y
▷ /wxexam/Panel.py
-------------------------------------------------------------------------------------
# -*- coding: utf-8 -*-
import wx
class MyFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, parent=None, title="Panel Example")
self.panel = wx.Panel(self)
self.panel.SetBackgroundColour(wx.RED)
self.button1 = wx.Button(self.panel, label="(50, 50)")
self.button1.SetPosition((50, 50))
self.button2 = wx.Button(self.panel, label="(250, 100)")
self.button2.SetPosition((250, 100)) # x,y
if __name__ == "__main__":
app = wx.App()
frame = MyFrame()
frame.Show()
app.MainLoop()
-------------------------------------------------------------------------------------
- 위젯을 수평, 수직으로 정렬 할 수 있음.
- 화면의 크기를 변경해도 레이아웃이 깨지지않음.
- wx.Panel(self.mainPanel): mainPanel에 현재 생성되는 Panel을 붙임.
- wx.Button(self.upperPanel, label="Left"): 생성되는 Button을 upperPanel에 붙일 예정임.
- wx.BoxSizer(wx.HORIZONTAL): 수평으로 위젯을 배치하는 BoxSizer 객체 생성
- self.hzBoxSizer.Add(self.leftButton): 버튼을 hzBoxSizer 객체에 붙임.
- self.upperPanel.SetSizer(self.hzBoxSizer): Panel에 Sizer 적용
- proportion: 0-기본 출력, 1: 나머지 공간 전부 사용,
값이 여러개인경우 전체적인 widget의 합에 비례하여 결정, BoxSizer에만 효과가 있음.
▷ /wxexam/BoxSizer.py
-------------------------------------------------------------------------------------
# -*- coding: utf-8 -*-
import wx
class MyFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, parent=None, title="BoxSizer Example")
'''
MyFrame
└─ mainPanel
└─ upperPanel: leftButton, rightButton
└─ middleButton
└─ lowerButton
'''
self.mainPanel = wx.Panel(self)
self.upperPanel = wx.Panel(self.mainPanel)
self.leftButton = wx.Button(self.upperPanel, label="Left")
self.rightButton = wx.Button(self.upperPanel, label="Right")
self.hzBoxSizer = wx.BoxSizer(wx.HORIZONTAL) # 수평
self.hzBoxSizer.Add(self.leftButton)
self.hzBoxSizer.Add(self.rightButton)
self.upperPanel.SetSizer(self.hzBoxSizer)
self.middleButton = wx.Button(self.mainPanel, label="Middle")
self.lowerButton = wx.Button(self.mainPanel, label="Lower")
self.vtBoxSizer = wx.BoxSizer(wx.VERTICAL) # 수직
self.vtBoxSizer.Add(self.upperPanel, 0, wx.ALIGN_LEFT|wx.TOP|wx.LEFT, 1)
self.vtBoxSizer.Add(self.middleButton, 1, wx.EXPAND|wx.ALL, 1)
self.vtBoxSizer.Add(self.lowerButton, 0, wx.ALIGN_RIGHT|wx.RIGHT|wx.BOTTOM, 1)
self.mainPanel.SetSizer(self.vtBoxSizer)
if __name__ == "__main__":
app = wx.App()
frame = MyFrame()
frame.Show()
app.MainLoop()
-------------------------------------------------------------------------------------
- Fieldset 형태를 만들어줌.
- self.hzBoxSizer = wx.StaticBoxSizer(wx.HORIZONTAL, self.upperPanel, "Upper") : "Upper"를 Caption으로 사용함.
▷ /wxexam/StaticBoxSizer.py
-------------------------------------------------------------------------------------
# -*- coding: utf-8 -*-
import wx
class MyFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, parent=None, title="StaticBoxSizer Example")
'''
MyFrame
└─ mainPanel
└─ upperPanel: leftButton, rightButton
└─ middleButton
└─ lowerButton
'''
self.mainPanel = wx.Panel(self)
self.upperPanel = wx.Panel(self.mainPanel)
self.leftButton = wx.Button(self.upperPanel, label="시작")
self.rightButton = wx.Button(self.upperPanel, label="종료")
self.hzBoxSizer = wx.StaticBoxSizer(
wx.HORIZONTAL, self.upperPanel, "데이터 수집") # 수평
self.hzBoxSizer.Add(self.leftButton)
self.hzBoxSizer.Add(self.rightButton)
self.upperPanel.SetSizer(self.hzBoxSizer)
self.middleButton = wx.Button(self.mainPanel, label="Middle")
self.lowerButton = wx.Button(self.mainPanel, label="Lower")
self.vtBoxSizer = wx.BoxSizer(wx.VERTICAL) # 수직
self.vtBoxSizer.Add(self.upperPanel, 0,
wx.ALIGN_LEFT|wx.TOP|wx.LEFT, 5)
self.vtBoxSizer.Add(self.middleButton, 1,
wx.EXPAND|wx.ALL, 5)
self.vtBoxSizer.Add(self.lowerButton, 0,
wx.ALIGN_RIGHT|wx.RIGHT|wx.BOTTOM, 5)
self.mainPanel.SetSizer(self.vtBoxSizer)
if __name__ == "__main__":
app = wx.App()
frame = MyFrame()
frame.Show()
app.MainLoop()
-------------------------------------------------------------------------------------
- 격자 형태의 레이아웃을 지원
- wx.GridSizer(rows=4, cols=3, hgap=5, vgap=5): 행의 수, 열의 수, 수평 간격 px, 수직 간격 px
- self.vtBoxSizer.Add(self.gridSizer, 1, wx.EXPAND): Sizer, 비중 1(100%), 공간을 채움
▷ /wxexam/GridSizer.py
-------------------------------------------------------------------------------------
# -*- coding: utf-8 -*-
import wx
class MyFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, parent=None, title="GridSizer Example")
self.SetSize(400, 300) # width, height
self.mainPanel = wx.Panel(self)
self.gridSizer = wx.GridSizer(rows=4, cols=3, hgap=30, vgap=5)
self.buttons = (
wx.Button(self.mainPanel, label="1"),
wx.Button(self.mainPanel, label="2"),
wx.Button(self.mainPanel, label="3"),
wx.Button(self.mainPanel, label="4"),
wx.Button(self.mainPanel, label="5"),
wx.Button(self.mainPanel, label="6"),
wx.Button(self.mainPanel, label="7"),
wx.Button(self.mainPanel, label="8"),
wx.Button(self.mainPanel, label="9"),
wx.Button(self.mainPanel, label="*"),
wx.Button(self.mainPanel, label="0"),
wx.Button(self.mainPanel, label="#")
)
for button in self.buttons:
self.gridSizer.Add(button, 0, wx.EXPAND)
self.vtBoxSizer = wx.BoxSizer(wx.VERTICAL) # 위/아래
self.vtBoxSizer.Add(self.gridSizer, 1, wx.EXPAND)
self.mainPanel.SetSizer(self.vtBoxSizer)
if __name__ == "__main__":
app = wx.App()
frame = MyFrame()
frame.Show()
app.MainLoop()
-------------------------------------------------------------------------------------
- GridSizer와 기본 기능이 같으나 특정 열이나 행의 사이즈를 조절 할 수 있음.
▷ /wxexam/FlexGridSizer.py
-------------------------------------------------------------------------------------
# -*- coding: utf-8 -*-
import wx
class MyFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, parent=None, title="FlexGridSizer Example")
self.SetSize(600, 400)
self.mainPanel = wx.Panel(self)
self.fgridSizer = wx.FlexGridSizer(rows=3, cols=2, hgap=5, vgap=5)
# StaticText: Label 기능, 출력 목적
self.nameStatic = wx.StaticText(self.mainPanel, label="성명 :")
self.emailStatic = wx.StaticText(self.mainPanel, label="이메일 :")
self.phoneStatic = wx.StaticText(self.mainPanel, label="전화번호 :")
# TextCtrl: 텍스트 입력
self.nameText = wx.TextCtrl(self.mainPanel)
self.emailText = wx.TextCtrl(self.mainPanel)
self.phoneText = wx.TextCtrl(self.mainPanel)
self.fgridSizer.Add(self.nameStatic)
self.fgridSizer.Add(self.nameText, 0, wx.EXPAND)
self.fgridSizer.Add(self.emailStatic)
self.fgridSizer.Add(self.emailText, 0, wx.EXPAND)
self.fgridSizer.Add(self.phoneStatic)
self.fgridSizer.Add(self.phoneText, 0, wx.EXPAND)
# 윈도우 크기 변경시 두 번째 컬럼의 너비도 따라 변경되도록 지정함.
self.fgridSizer.AddGrowableCol(1)
# 윈도우 크기 변경시 세 번째 행의 높이도 따라 변경되도록 지정함.
self.fgridSizer.AddGrowableRow(2)
self.vtBoxSizer = wx.BoxSizer(wx.VERTICAL)
# 10: gap
self.vtBoxSizer.Add(self.fgridSizer, 1, wx.EXPAND | wx.ALL, 10)
self.mainPanel.SetSizer(self.vtBoxSizer)
if __name__ == "__main__":
app = wx.App()
frame = MyFrame()
frame.Show()
app.MainLoop()
-------------------------------------------------------------------------------------
'빅데이터 프로그래밍 > Python' 카테고리의 다른 글
[Python] 20. [DBMS] 데이터베이스 개론, SQLite3 사용 (0) | 2017.08.02 |
---|---|
[Python] 19. [GUI] wxPython 그래픽 사용자 인터페이스, 다양한 Widget, Menu (0) | 2017.08.02 |
[Python] 17. [Network] threading module, 채팅 서버/클라이언트 제작 (0) | 2017.08.02 |
[Python] 16. [Network] socketserver 네트워크 프레임워크, Echo Server 2, 파일 송수신 (0) | 2017.08.02 |
[Python] 15. [Network] Network(네트워크), Socket, Echo Server 1 (0) | 2017.08.02 |
댓글