1. wxPython모듈 사용 - import wx: 라이브러리 로딩
(1) Python에 기반한 GUI toolkit
(2) Python 언어를 이용해서 GUI를 간단하고 빠른 시간에 제작 가능하도록 도와준다.
(3) GUI 라이브러리인 wxWindows를 Python에서 지원이 가능하도록 c++ 로 제작되었으며, 크로스 플랫폼 toolkit 이다.
(4) Index of /Phoenix/snapshot-builds (wxpython.org)에서 wxPython-4.1.2a1.dev5103+4ab028d7-cp38-cp38-win_amd64.whl다운
2. 실행 메소드
(1) wx.App(): 어플리케이션 객체를 생성
(2) Show(): 생성한 윈도우 출력
(3) app.MainLoop()
1) 이벤트 루프 생성
2) app만들어서 창을 띄우는 것
3) 무한루프에 빠지는 것 - x를 누르면 멈춤
<cmd창에서 실행 시>
3. 윈도우 프레임 생성방법 2가지
(1) wx.Frame(None, title): 어플리케이션 객체안에 윈도우 프레임 생성
import wx
app = wx.App(False)
frame = wx.Frame(None, wx.ID_ANY, 'Hi')
frame.Show(True)
app.MainLoop()
(2) wx.Frame을 상속받는 클래스 생성
1) 클래스 내에서 self.Show() 선언
2) 클래스 밖에서 다음 블록 선언: Ex는 클래스 이름.
3) 생성자
① 부모의 생성자를 상속받음
② 추가로 title, size, 위치(pos) 등을 설정
import wx
import wx.xrc
class MyFrame1 ( wx.Frame ):
def __init__( self, parent ):
wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = u"연습", pos = wx.DefaultPosition, size = wx.Size( 313,187 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL )
4. layout
(1) wx.Panel()
1) 윈도우 창에 넣을 공간(패널) 생성
2) panel위에 여러 layout을 올려놓는다.
3) 구역을 나누는 역할
(2) wx.BoxSizer: 기본 레이아웃 관리자
1) sizer클래스: 레이아웃 디자인하는 관리자
2) 각각의 layout들을 배치
① wx.BoxSizer(wx.HORIZONTAL)
② wx.BoxSizer(wx.VERTICAL)
3) layout삽입: BoxSizer 객체 명.Add(삽입대상명,차지할 비율,[wx.EXPAND])
4) BoxSizer 설정 적용: self.SetSizer(BoxSizer 객체 명)
import wx
class MyFrame(wx.Frame):
def __init__(self, parent, title):
super(MyFrame, self).__init__(parent, title = title, size=(300, 350))
panel1 = wx.Panel(self, -1, style = wx.SUNKEN_BORDER)
panel2 = wx.Panel(self, -1, style = wx.SUNKEN_BORDER)
panel1.SetBackgroundColour('BLUE')
panel2.SetBackgroundColour('red')
box = wx.BoxSizer(wx.HORIZONTAL) #(wx.VERTICAL)
box.Add(panel1,1,wx.EXPAND)
box.Add(panel2,1,wx.EXPAND)
#box안에 panel1과 panel2를 1:1로 나눠가진 것
self.SetSizer(box)
self.Center()
self.Show()
if __name__ == '__main__':
app = wx.App()
MyFrame(None, title = '연습')
app.MainLoop()
(3) 텍스트 추가
1) 텍스트 박스 – TextCtrl
① 싱글라인
i. panel 미사용: TextCtrl(self)
ii. panel 사용: TextCtrl(wx.Panel())
② 멀티라인
i. panel 미사용: wx.TextCtrl(self, style = wx.TE_MULTILINE)
ii. panel 사용: wx.TextCtrl(wx.Panel(), style = wx.TE_MULTILINE)
2) 고정 텍스트 - StaticText
① panel 미사용: wx.StaticText(self, label = “ “, [size = (너비, 높이),pos = (왼쪽에서 떨어진 거리, 위에서부터 떨어진 거리)])
② panel 사용: wx.StaticText(wx.Panel(), label = “ “, [size = (너비, 높이),pos = (왼쪽에서 떨어진 거리, 위에서부터 떨어진 거리)])
# 2. 라벨과 텍스트박스 사용
panel = wx.Panel(self)
#밑에 panel을 깔고 그위에 id, pwd 입력
#보이기만 하니깐 이름은 안줌
wx.StaticText(panel, label = 'i d : ', pos = (5, 5)) #일방적인 텍스트 뿌려주기
# 왼쪽에서 5 위에서 5 떨어진 곳에 id띄우기
wx.StaticText(panel, label = 'pwd : ', pos = (5, 40))
#이름을 줌(self가 붙어서 이 클래스 내에서는 유효, 이 클래스 내에서 호출가능)
self.txtId = wx.TextCtrl(panel, pos = (40, 5))
self.txtPwd = wx.TextCtrl(panel, pos = (40, 40), size = (200, -1))
#size = (너비, 높이),pos = (왼쪽에서 떨어진 거리, 위에서부터 떨어진 거리): 위치
#-1은 시스템이 자동 설정 해줌
(4) 버튼
1) panel 미사용: wx.Button(self, label = ' ', [size = (너비, 높이),pos = (왼쪽에서 떨어진 거리, 위에서부터 떨어진 거리)])
2) panel 사용: wx.Button(panel, label = ' ', [size = (너비, 높이),pos = (왼쪽에서 떨어진 거리, 위에서부터 떨어진 거리)])
#3. 버튼 - 버튼 레이아웃만
#이름을 줌(self가 안붙어서 이 메소드 내에서만 유효, 다른메소드에서 사용불가)
btn1 = wx.Button(panel, label = '일반버튼', pos = (5, 100))
btn2 = wx.Button(panel, label = '일반버튼', pos = (100, 100))
btn3 = wx.Button(panel, label = '종료', pos = (200, 100))
(5) 버튼 이벤트 처리
1) id 미사용
① 형식: 버튼 명.Bind(wx.EVT_BUTTON, self.이벤트 메소드)
② id를 미사용 시 여러 개의 버튼에 각기 다른 이름의 이벤트 메소드를 따로 설정
2) id 사용:
① 형식:
버튼 명.id = ?
버튼 명.Bind(wx.EVT_BUTTON, self.이벤트 메소드)
② id사용할 땐 여러 개의 버튼에 같은 이름의 이벤트 메소드를 설정가능. 메소드 블록안에서 id별로 다른 이벤트 설정
#4-1. 버튼에 대한 이벤트 처리작업1
btn1.Bind(wx.EVT_BUTTON, self.btn1Method)
btn2.Bind(wx.EVT_BUTTON, self.btn2Method)
btn3.Bind(wx.EVT_BUTTON, self.btn3Method)
#4-2. 버튼에 대한 이벤트 처리작업2
btn1.id = 1
btn2.id = 2
btn3.id = 3
btn1.Bind(wx.EVT_BUTTON, self.onClickMethod)
btn2.Bind(wx.EVT_BUTTON, self.onClickMethod)
btn3.Bind(wx.EVT_BUTTON, self.onClickMethod)
3) event handler method: 이벤트 처리 메소드
① 반드시 argument가 self말고 하나 더 있어야한다.
② event가 발생하면 event 정보를 받을 수 있는 역할로 argument가 하나 더 있어야한다.
③ 명칭은 자유롭게 설정 가능
def abc(self): #일반메소드
print('일반메소드')
def btn1Method(self, event):
#이벤트 처리 메소드 . event handler 메소드는 반드시 argument가 self말고 하나더 있어야한다.
#event가 발생하면 event 정보를 받을 수 있는 역할로 argument가 하나 더 있어야한다. 명칭은 꼭 event가 아니어도 된다.
print('버튼1을 누르다니')
imsi = self.txtId.GetValue()
self.txtPwd.SetLabelText(imsi)
(6) 메시지 박스
1) 버튼 타입
① wx.OK: 확인버튼
② wx.YES_NO: 예/아니오 버튼
③ OK, YES, NO등은 ID => wx.ID_ OK, wx.ID_YES, wx.ID_NO
2) wx.MessageDialog
① panel 미사용 생성: wx.MessageDialog(self, ‘내용’, '제목', 버튼타입)
② panel 사용 생성: wx.MessageDialog(wx.Panel(), ‘내용’, '제목', 버튼타입)
③ 모달창 보여주기: 모달창 생성 명.ShowModal()
④ 종료: 모달창 생성 명.Destroy()
msgDial = wx.MessageDialog(self,'메세지', '제목', wx.OK)
msgDial.ShowModal()
msgDial.Destroy()
3) wx.MessageBox('내용','제목', 버튼타입) – 생성, 보여주기, 종료 한번에 해결
(7) 라디오버튼
1) 라디오버튼 값 리스트: 라디오버튼 객체 이름Choices = [ u"+", u"-", u"*", u"/" ]
2) 라디오버튼 생성: wx.RadioBox( )
3) 기본 선택 값: 라디오버튼 객체 이름.SetSelection( 리스트 요소 번호 )
4) 라디오버튼의 값 얻기: 라디오버튼 객체 이름.GetStringSelection()
rdoOpChoices = [ u"+", u"-", u"*", u"/" ]
self.rdoOp = wx.RadioBox( self.m_panel6, wx.ID_ANY, u"연산자 선택", wx.DefaultPosition, wx.DefaultSize, rdoOpChoices, 1, wx.RA_SPECIFY_ROWS )
self.rdoOp.SetSelection( 0 )
bSizer8.Add( self.rdoOp, 1, wx.ALL, 5 )
(8) 표
1) 표 생성: wx.ListCtrl()
2) 컬럼 추가: 표 객체명.InsertColumn(컬럼순서(0부터), '컬럼이름',[사이즈 등])
3) 행 추가: 표 객체명.InsertItem(1000, 0) – 최대 1000개 행
4) 내용 입력: 표 객체명. SetItem(행 번호, 열 번호, ‘내용’)
5) 표 내용 전체삭제: 표 객체명.DeleteAllItems()
self.lstGogek = wx.ListCtrl( self.m_panel3, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LC_REPORT )
bSizer4.Add( self.lstGogek, 1, wx.ALL|wx.EXPAND, 5 )
#lstGogek 객체에 제목
self.lstGogek.InsertColumn(0, '고객번호', width=100)
self.lstGogek.InsertColumn(1, '고객명', width=100)
self.lstGogek.InsertColumn(2, '고객전화번호', width=100)
def DisplayData(self, no):
try:
conn = MySQLdb.connect(**config)
cursor = conn.cursor()
sql = "select gogek_no, gogek_name, gogek_tel from gogek where gogek_damsano={}".format(no)
#print(sql)
cursor.execute(sql)
datas = cursor.fetchall()
self.lstGogek.DeleteAllItems() #ListCtrl의 초기화
for d in datas:
i = self.lstGogek.InsertItem(1000, 0) # ListCtrl의 최대 행 수를 적어줌
self.lstGogek.SetItem(i, 0, str(d[0]))
self.lstGogek.SetItem(i, 1, str(d[1]))
self.lstGogek.SetItem(i, 2, str(d[2]))
(9) 관련 메소드
1) 값 얻을 곳 이름.GetValue(): 텍스트 박스의 값을 얻는 메소드
2) 입력할 곳 이름.SetLabel[Text](입력할 값): text를 입력하는 메소드
3) 이벤트 받는 매개변수명.GetEventObject().id: 이벤트 실행 대상의 id 반환 메소드
4) 적용객체명.SetBackgroundColour(‘color’): 배경색 지정 메소드
5) 적용객체명. SetFocus(): 마우스 커서를 설정하는 메소드 - UX/UI:사용자 편의
def onClickMethod(self, event):
print('onClick')
print(event.GetEventObject().id)
if event.GetEventObject().id == 1:
self.txtId.SetLabelText('kbs')
elif event.GetEventObject().id == 2:
self.txtPwd.SetLabelText('mbc')
else:
self.Close()
5. wxformbuilder
(1) GUI를 좀 더 편리하게 사용하는 디자인 툴
(2) http://sourceforge.net/projects/wxformbuilder/ 에서 윈도우 운영체제용 다운로드 3.5
종합 예제1)
#wxformbuilder로 만들기
import wx
import wx.xrc
class MyFrame1 ( wx.Frame ):
def __init__( self, parent ):
wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = u"연습", pos = wx.DefaultPosition, size = wx.Size( 313,187 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL )
#self.SetSizeHintsSz( wx.DefaultSize, wx.DefaultSize ) - 명령 안먹힘
self.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_MENU ) )
bSizer1 = wx.BoxSizer( wx.VERTICAL )
self.m_panel1 = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
bSizer2 = wx.BoxSizer( wx.HORIZONTAL )
self.m_staticText1 = wx.StaticText( self.m_panel1, wx.ID_ANY, u"이름:", wx.DefaultPosition, wx.DefaultSize, 0 )
self.m_staticText1.Wrap( -1 )
bSizer2.Add( self.m_staticText1, 0, wx.ALL, 5 )
self.txtName = wx.TextCtrl( self.m_panel1, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
bSizer2.Add( self.txtName, 0, wx.ALL, 5 )
self.m_panel1.SetSizer( bSizer2 )
self.m_panel1.Layout()
bSizer2.Fit( self.m_panel1 )
bSizer1.Add( self.m_panel1, 0, wx.ALL|wx.EXPAND, 5 )
self.m_panel2 = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
bSizer3 = wx.BoxSizer( wx.HORIZONTAL )
self.m_staticText2 = wx.StaticText( self.m_panel2, wx.ID_ANY, u"나이:", wx.DefaultPosition, wx.DefaultSize, 0 )
self.m_staticText2.Wrap( -1 )
bSizer3.Add( self.m_staticText2, 0, wx.ALL, 5 )
self.txtAge = wx.TextCtrl( self.m_panel2, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
bSizer3.Add( self.txtAge, 0, wx.ALL, 5 )
self.btnOk = wx.Button( self.m_panel2, wx.ID_ANY, u"확인", wx.DefaultPosition, wx.DefaultSize, 0 )
bSizer3.Add( self.btnOk, 0, wx.ALL, 5 )
self.m_panel2.SetSizer( bSizer3 )
self.m_panel2.Layout()
bSizer3.Fit( self.m_panel2 )
bSizer1.Add( self.m_panel2, 0, wx.EXPAND |wx.ALL, 5 )
self.m_panel3 = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
bSizer4 = wx.BoxSizer( wx.HORIZONTAL )
self.m_staticText3 = wx.StaticText( self.m_panel3, wx.ID_ANY, u"결과:", wx.DefaultPosition, wx.DefaultSize, 0 )
self.m_staticText3.Wrap( -1 )
bSizer4.Add( self.m_staticText3, 0, wx.ALL, 5 )
self.staShow = wx.StaticText( self.m_panel3, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
self.staShow.Wrap( -1 )
bSizer4.Add( self.staShow, 0, wx.ALL, 5 )
self.m_panel3.SetSizer( bSizer4 )
self.m_panel3.Layout()
bSizer4.Fit( self.m_panel3 )
bSizer1.Add( self.m_panel3, 0, wx.EXPAND |wx.ALL, 5 )
self.SetSizer( bSizer1 )
self.Layout()
self.Centre( wx.BOTH ) # = center
# Connect Events
self.btnOk.Bind( wx.EVT_BUTTON, self.OnClickMethod )
def __del__( self ):
pass
# Virtual event handlers, overide them in your derived class
def OnClickMethod( self, event ):
name = self.txtName.GetValue()
if name == "":
"""m = wx.MessageDialog(self, '이름입력', '알림', wx.OK)
m.ShowModal()"""
wx.MessageBox('이름입력','알림',wx.OK)
return
age = self.txtAge.GetValue()
self.staShow.SetLabelText(name + age)
if __name__ == '__main__':
app = wx.App()
MyFrame1(None).Show()
app.MainLoop()
종합 예제2)
import wx
import wx.xrc
class MyFrame2 ( wx.Frame ):
def __init__( self, parent ):
wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = wx.EmptyString, pos = wx.DefaultPosition, size = wx.Size( 393,317 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL )
#self.SetSizeHintsSz( wx.DefaultSize, wx.DefaultSize )
self.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_MENU ) )
bSizer5 = wx.BoxSizer( wx.VERTICAL )
self.m_panel4 = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
bSizer6 = wx.BoxSizer( wx.HORIZONTAL )
self.m_staticText5 = wx.StaticText( self.m_panel4, wx.ID_ANY, u"숫자1:", wx.DefaultPosition, wx.DefaultSize, 0 )
self.m_staticText5.Wrap( -1 )
bSizer6.Add( self.m_staticText5, 0, wx.ALL, 5 )
self.txtNum1 = wx.TextCtrl( self.m_panel4, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
bSizer6.Add( self.txtNum1, 0, wx.ALL, 5 )
self.m_panel4.SetSizer( bSizer6 )
self.m_panel4.Layout()
bSizer6.Fit( self.m_panel4 )
bSizer5.Add( self.m_panel4, 0, wx.EXPAND |wx.ALL, 5 )
self.m_panel5 = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
bSizer7 = wx.BoxSizer( wx.HORIZONTAL )
self.m_staticText6 = wx.StaticText( self.m_panel5, wx.ID_ANY, u"숫자2:", wx.DefaultPosition, wx.DefaultSize, 0 )
self.m_staticText6.Wrap( -1 )
bSizer7.Add( self.m_staticText6, 0, wx.ALL, 5 )
self.txtNum2 = wx.TextCtrl( self.m_panel5, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
bSizer7.Add( self.txtNum2, 0, wx.ALL, 5 )
self.m_panel5.SetSizer( bSizer7 )
self.m_panel5.Layout()
bSizer7.Fit( self.m_panel5 )
bSizer5.Add( self.m_panel5, 0, wx.EXPAND |wx.ALL, 5 )
self.m_panel6 = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
bSizer8 = wx.BoxSizer( wx.HORIZONTAL )
rdoOpChoices = [ u"+", u"-", u"*", u"/" ]
self.rdoOp = wx.RadioBox( self.m_panel6, wx.ID_ANY, u"연산자 선택", wx.DefaultPosition, wx.DefaultSize, rdoOpChoices, 1, wx.RA_SPECIFY_ROWS )
self.rdoOp.SetSelection( 0 )
bSizer8.Add( self.rdoOp, 1, wx.ALL, 5 )
self.m_panel6.SetSizer( bSizer8 )
self.m_panel6.Layout()
bSizer8.Fit( self.m_panel6 )
bSizer5.Add( self.m_panel6, 0, wx.EXPAND |wx.ALL, 5 )
self.m_panel7 = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
bSizer9 = wx.BoxSizer( wx.HORIZONTAL )
self.m_staticText7 = wx.StaticText( self.m_panel7, wx.ID_ANY, u"연산결과:", wx.DefaultPosition, wx.DefaultSize, 0 )
self.m_staticText7.Wrap( -1 )
bSizer9.Add( self.m_staticText7, 0, wx.ALL, 5 )
self.staResult = wx.StaticText( self.m_panel7, wx.ID_ANY, u"0", wx.DefaultPosition, wx.DefaultSize, 0 )
self.staResult.Wrap( -1 )
bSizer9.Add( self.staResult, 0, wx.ALL, 5 )
self.m_panel7.SetSizer( bSizer9 )
self.m_panel7.Layout()
bSizer9.Fit( self.m_panel7 )
bSizer5.Add( self.m_panel7, 0, wx.EXPAND |wx.ALL, 5 )
self.m_panel8 = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
bSizer10 = wx.BoxSizer( wx.HORIZONTAL )
self.btnCalc = wx.Button( self.m_panel8, wx.ID_ANY, u"계산", wx.DefaultPosition, wx.DefaultSize, 0 )
bSizer10.Add( self.btnCalc, 0, wx.ALL, 5 )
self.btnClear = wx.Button( self.m_panel8, wx.ID_ANY, u"초기화", wx.DefaultPosition, wx.DefaultSize, 0 )
bSizer10.Add( self.btnClear, 0, wx.ALL, 5 )
self.btnExit = wx.Button( self.m_panel8, wx.ID_ANY, u"종료", wx.DefaultPosition, wx.DefaultSize, 0 )
bSizer10.Add( self.btnExit, 0, wx.ALL, 5 )
self.m_panel8.SetSizer( bSizer10 )
self.m_panel8.Layout()
bSizer10.Fit( self.m_panel8 )
bSizer5.Add( self.m_panel8, 0, wx.EXPAND |wx.ALL, 5 )
self.SetSizer( bSizer5 )
self.Layout()
self.Centre( wx.BOTH )
# Connect Events
self.btnCalc.id = 1
self.btnClear.id = 2
self.btnExit.id = 3
self.btnCalc.Bind( wx.EVT_BUTTON, self.OnCalcProcess )
self.btnClear.Bind( wx.EVT_BUTTON, self.OnCalcProcess )
self.btnExit.Bind( wx.EVT_BUTTON, self.OnCalcProcess )
def __del__( self ): #소멸자
pass
# Virtual event handlers, overide them in your derived class
def OnCalcProcess( self, event ):
sel_id = event.GetEventObject().id
#print(sel_id)
if sel_id == 1:
op = self.rdoOp.GetStringSelection()
#print(op)
num1 = self.txtNum1.GetValue()
num2 = self.txtNum2.GetValue()
if num1 == '' or num2 == '':
wx.MessageBox('값을 입력하시오', '알림', wx.OK)
return
try:
result = eval(num1 + op + num2)
except Exception as e:
wx.MessageBox('연산오류'+str(e), '알림', wx.OK)
self.staResult.SetLabel(str(result))
elif sel_id == 2:
self.txtNum1.SetLabel('')
self.txtNum2.SetLabel('')
self.staResult.SetLabel('')
self.rdoOp.SetSelection(0)
self.txtNum1.SetFocus() #UX/UI:사용자 편의
elif sel_id == 3:
dlg = wx.MessageDialog(self, '정말 종료할까요?','알림', wx.YES_NO)
imsi = dlg.ShowModal()
if imsi ==wx.ID_YES:
dlg.Destroy() #MessageDialog닫기
self.Close() #Frame 닫기
if __name__ == '__main__':
app = wx.App()
MyFrame2(None).Show()
app.MainLoop()
14. 소켓(Socket) (0) | 2021.05.01 |
---|---|
13. 원격(remote) db연동 – MariaDB (0) | 2021.04.29 |
11. 예외처리 (0) | 2021.04.29 |
10. 내장함수 (0) | 2021.04.29 |
8. 사용자 입력과 출력 (0) | 2021.04.29 |