블로그 이미지
자유로운설탕

calendar

1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30

Notice

2017. 3. 5. 18:57 프로그래밍

  9교시는 GUI(Graphic User Interface)에 대한 얘기를 풀어보고, 예전 시간에 사용했던 암호화 모듈을 사용해서 윈도우 화면에 입력한 값을 복호화 해서 보여주는 샘플을 만들어 보려한다. 

 

 

[목차]

0. 왜 파이썬 공부에 구글을 이용하는게 좋은가?

1. 언어를 바라보는 방법. 파이썬을 어떻게 바라봐야 할까?

2. 파이썬 설치와 환경, 버전 선택 하기의 이유.

3. 만들고자 하는 기능을 모르는 조각으로 나눠 조사해 보기

4. 데이터 베이스에서 내용 가져와 출력하기

5. 암호화 모듈을 이용해 암복호화 해보기

6. 퍼즐 조각들을 합쳐보기

7. 엑셀 파일 사용해 보기 -> 부록 : fuction 을 이용해서, 코드 정리해 보기

8. 정규표현식을 왜 사용해야 할까? 언어속의 미니 언어 정규표현식 살펴보기

9. 입력과 결과를 GUI 화면과 연결해 보기

10. Whois API 이용해 보기

11. 웹페이지 호출해 내용 파싱 하기(BeautifulSoup 그리고 한계)

12. 자동화 - 웹 자동화(with Selenium)

13. 자동화 - 윈도우즈 GUI 자동화(with pywinauto)

14. 자동화 - 작업 자동화

15. 수학 라이브러리 살펴보기

16. 그래픽 라이브러리 살펴보기

17. 머신러닝에서의 파이썬의 역활

18. 웹 프로그래밍 - Legacy Web

19. 웹 프로그래밍 - Flask 살펴보기(feat. d3.js)

20. 웹 프로그래밍 - Django 살펴보기

21. 정리 - 이런저런 이야기

 

 

 

[들어가면서]

  GUI 프로그램을 공부하는 것은 초보자 입장으로는 쉬운일은 아니다. 왜냐하면 사실 조금 간략화 되어 있을 뿐이지 Visual C, JAVA 등으로 만드는 윈도우 GUI 프로그래밍 기법과 거의 동일한 선상의 레벨이기 때문이다. 게다가 그 쪽 언어에서는 보통 Visual Studio 나 Eclipse 같은 사용성이 아주 좋은 IDE 를 통해 개발하기 때문에, GUI 디자인이나, GUI 객체들에 이벤트 연결 하는 부분은 거의 신경 쓰지 않고, 실제 실행되는 이벤트 코드 쪽만 집중해 개발할 수 있지만, 아무래도 아직 파이썬 쪽은 모듈별(pyqt, wxpython) 디자이너 툴이 있다고는 하지만 IDE 와 통합된 형태도 아니며, 그나마 디자인만 잡아주는 수준인듯 하다. 게다가 왠지 수동으로 디자인을 잡는건 미련한 거 같아서 wxpython 을 지원 한다고 하는 wxGlade, wxformBuilder 라는 두 개의 툴을 설치해 검토해 봤는데, 둘 다 다른 언어도 같이 지원하는 일반적인 툴이라서 그런지 윈도우 환경의 python 3.5 에서는 아직 제대로 실행이 안 되는거 같다.(이건 제가 잘 몰라서 그럴 수도 있으니 단정은 못 짓겠다). 또 실제 실행은 안됬지만 생성된 파이썬 코드도 왠지 가독성 측면에서 별로 깔끔해 보이지가 않는다. pyqt 모듈 쪽에서는 디자이너 까진 잘 지원되는 거 같으니 그 쪽 모듈을 사용해 보는 것도 고려해 볼만 하다. pyqt 디자이너에 대해서는 아래 잘 설명되 있는 듯 하다.

http://pythonstudy.xyz/python/article/108-PyQt-QtDesigner-%EB%A9%94%EC%9D%B8%EC%9C%88%EB%8F%84%EC%9A%B0

 

  그리고 이 GUI 모듈들의 사용도, 이전 시간에 다룬 SQL, 정규식 같이 파이썬 언어의 기능 밖의 부분이라고 생각해도 무방 할듯 하다. 만약 다른 언어로 GUI 툴을 개발해 봤거나, 꼭 윈도우 어플리케이션이 아니더라도, 웹 어플리케이션에서 자바스크립트로 DOM 개체와 이벤트로 상호 작용을 하는 부분을 만들어 봤다면, GUI 모듈을 사용할 기초 소양 준비는 다 되있다고 보면 된다. 만약 해당 부분의 경험이 거의 없다면, 이클립스나 비주얼스튜디오 같은 좋은 IDE 로 몇 개의 작은 GUI 어플리케이션을 작성해서, GUI 요소들과 사용자 코드가 상호 작용하는 부분에 대해 감을 익힌 후, 맨 뒤에 소개한 레퍼런스를 참조하여 python GUI 모듈의 디테일한 개발 내용을 보는게 개인적으로 조금 더 나아 보인다. (오해할까봐.. 저도 잘 못하는 부분이긴 하다...). 어떻게 보면 파이썬에서 수동으로 디자인할 때도 비쥬얼스튜디오 같은 IDE로 모양만 잡은 후 관련 좌표등을 참고해 수동으로 옮기는 것도 하나의 방법일 듯 싶다.

 

 

 

[GUI 연결 고리 만들어 보기]

  그럼 2교시때 GUI 샘플을 실행하기 위해서 이미 wxpython 모듈을 아래와 같이 설치 했었다. 혹시 모듈 선택 이유 및 설치 과정이 가물가물하면 2교시 내용을 보면 된다.

 

  스택오퍼플로어에 가이드 된데로 cmd 창에서 아래 명령어를 실행시킨다.

pip install -U --pre -f https://wxpython.org/Phoenix/snapshot-builds/ wxPython_Phoenix

 

 

 

  만들려고 하는 기능은 아래와 같다. 윈도우 창에는 입력 박스 한개와 결과를 출력하는 라벨이 한 개, 버튼이 하나 있다(좀 단촐해서 민망하다 --;). 멀뚱히 비워 놓긴 그래서, 여러가지 디폴트 문장을 표시하게 했다.

 

  텍스트 박스에 암호화 하길 원하는 문장을 넣은 후, 암호화 버튼을 누르면, 아래와 같이 암호화 된 값이 하단 텍스트 라벨에 표시된다.

 

 

  언제나 처럼 위 부분을 만드려면 모르는 게 무언지 생각해 보자. (우선 윈도우즈 창 만드는 법은 안다. 샘플 파일을 이미 실행해 봤으니까...)

1) 버튼을 만들수 있어야 한다.

2) 텍스트 박스를 만들 수 있어야 한다. 안에다 디폴드 값도 넣어 주어야 한다.

4) 결과를 뿌릴 텍스트 라벨 영역을 만들 수 있어야 한다. 이건 샘플파일에 이미 StaticText 란 코드로 출력해 봤다. 이것도 디폴트 값은 넣어주어야 한다.

5) '암호화'버튼이 클릭 됬을때, 특정한 함수 A를 실행 해야 한다. 그 A함수 안에서는 텍스트 박스에 입력한 'my word' 항목을 가져와서, 미리 만들어 놓은 암호화 함수 B를 호출해서 암호화 한 값을 리턴 받은 후, 텍스트 라벨 영역에 출력해 주어야 한다.

 

 

  그럼 첫번째로 버튼을 찾아본다. wxPython 메뉴얼을 쭉 훝어봐도 되겠지만, 구글을 찾는게 편할 듯 하다. 'wxpython show input box'. 맨 위의 스택 오버플로우 결과를 클릭한다.

http://stackoverflow.com/questions/18532827/using-wxpython-to-get-input-from-user

 

  오 여기에 버튼 뿐만아니라 텍스트 박스를 만드는 코드도 같이 있다. 디폴드 값 넣는 부분도 존재한다. 자세히 보면 버튼이 클릭 됬을 때 특정한 함수를 호출 하는 부분도 있다. 1타 3피로 거의 다 줏어 온 듯 싶다. (해당 코드 앞에 주석을 달아본다)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#-*- coding: utf-8 -*-
import wx
class Frame(wx.Frame):
    def __init__(self, parent, title):
        wx.Frame.__init__(self, parent, title=title, size=(-1-1))
        self.panel = wx.Panel(self)
        self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
        # 버튼 만드는 코드
        self.btn = wx.Button(self.panel, -1"Name-a-matic")
        # 버튼 클릭 이벤트에 함수(메쏘드) 연결하는 코드
        self.Bind(wx.EVT_BUTTON, self.GetName, self.btn)
        # 텍스트 박스 만들고, 디폴트 값 넣는 코드
        self.txt = wx.TextCtrl(self.panel, -1, size=(140,-1))
        self.txt.SetValue('name goes here')
 
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.btn)
        sizer.Add(self.txt)
 
        self.panel.SetSizer(sizer)
        self.Show()
        
        # 버튼이 눌렸을 때 실행 되는 함수,  사용자의 이름을 얻어 텍스트 박스에 넣어줌
    def GetName(self, e):
 
        dlg = wx.TextEntryDialog(self.panel, 'Whats yo name?:',"name-o-rama",""
                style=wx.OK)
        dlg.ShowModal()
        self.txt.SetValue(dlg.GetValue())
        dlg.Destroy()
 
    def OnCloseWindow(self, e):
        self.Destroy()
 
app = wx.App()
frame = Frame(None, 'My Nameomatic')
app.MainLoop()
cs

 

 

 

 

  그럼 저 뼈대를 거의 그대로 쓰고, 1) 버튼을 만드는 코드는 아래와 같다.

1
        self.btn = wx.Button(self.panel, -1'암호화')
cs

 

  2) 텍스트 박스를 만들고, 디폴트 값을 넣는 코드는 아래와 같다.

1
2
        self.txt = wx.TextCtrl(self.panel, -1, size=(140,-1))
        self.txt.SetValue('input your value')
cs

 

  3) 텍스트 라벨을 만들고, 디폴트 값을 넣는 코드는 아래와 같다.

1
2
        self.some_text = wx.StaticText(self.panel, size=(140,150), pos=(10,60))
        self.some_text.SetLabel('result is...')
cs

 

  4) 버튼을 누르면 이벤트 함수를 연결하는 코드는 아래와 같다.

1
        self.Bind(wx.EVT_BUTTON, self.GetEncryption, self.btn)
cs

 

  5) 위의 4번에 있는 GetEncryption 함수는 텍스트 박스의 값을 가져다, 암호화 함수에 던저주고, 리턴된 값을 다시 라벨에 넣어주여야 한다. 해당 기능의 코드는 아래와 같다.

  ※ 첨에는 버튼 이벤트에 GetEncryption 함수를 호출할 때 암호화 할 값을 전달해 줘야하나 하고 한참 구글을 헤멨는데, 안에서 텍스트 필드에 접근하면 되는 거라서 그냥 기존 코드를 그대로 이용했다. --;

1
2
3
    def GetEncryption(self, e): 
        self.enc = AESCipher(key).encrypt(self.txt.GetValue())
        self.some_text.SetLabel(self.enc)
cs

 

 

 

 

  그럼 해당 코드를 전체적으로 정리한 코드는 아래와 같다. 예전에 달았던 암호화 관련 주석들은 이번 시간 내용과 관련 없는 부분이니 출처만 빼고 삭제 했다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#-*- coding: utf-8 -*-
# 암호화 코드 출처: http://blog.dokenzy.com/
import wx
import base64
import hashlib
from Crypto import Random
from Crypto.Cipher import AES
 
# 암호화 관련 초기화 코드
BS = 16
pad = lambda s: s + (BS - len(s) % BS) * chr(BS - len(s) % BS).encode()
unpad = lambda s: s[:-ord(s[len(s)-1:])]
key = 'abcdefghijklmnopqrstuvwxyz123456'
 
def iv():
    return chr(0* 16
 
 
# 윈도우즈 정의 클래스
class Frame(wx.Frame):
    def __init__(self, parent, title):
        wx.Frame.__init__(self, parent, title=title, size=(-1-1))
        self.panel = wx.Panel(self)
        self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
 
        # 버튼 생성
        self.btn = wx.Button(self.panel, -1'암호화')
 
        # 텍스트 박스 생성
        self.txt = wx.TextCtrl(self.panel, -1, size=(140,-1))
        self.txt.SetValue('input your value')
        
        # 텍스트 라벨 생성
        self.some_text = wx.StaticText(self.panel, size=(140,150), pos=(10,60))
        self.some_text.SetLabel('result is...')
 
        # 버튼 클릭 시 이벤트 연결
        self.Bind(wx.EVT_BUTTON, self.GetEncryption, self.btn)
 
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.btn)
        sizer.Add(self.txt)
 
        self.panel.SetSizer(sizer)
        self.Show()
 
    # 버튼 클릭 시 실행 되어, 암호화 하는 함수
    def GetEncryption(self, e): 
        # 텍스트 박스(self.txt)로 부터 값을 얻어와 암호화 함수로 넘겨준다.
        self.enc = AESCipher(key).encrypt(self.txt.GetValue())
        # 받은 값을 텍스트 라벨에 출력한다.
        self.some_text.SetLabel(self.enc)
 
 
    def OnCloseWindow(self, e):
        self.Destroy()
 
 
# 암호화 관련 클래스
class AESCipher(object):
 
    def __init__(self, key):
        self.key = key
 
    def encrypt(self, message):
        message = message.encode()
        raw = pad(message)
        cipher = AES.new(self.key, AES.MODE_CBC, iv())
        enc = cipher.encrypt(raw)
        return base64.b64encode(enc).decode('utf-8')
 
    def decrypt(self, enc):
        enc = base64.b64decode(enc)
        cipher = AES.new(self.key, AES.MODE_CBC, iv())
        dec = cipher.decrypt(enc)
        return unpad(dec).decode('utf-8')
 
 
 
# 메인코드 #
# 윈도우를 띄우고 제목을 넣는다.
app = wx.App()
frame = Frame(None, 'WxEncryption')
app.MainLoop()
cs

 

 

  그럼 최종 코드를 c:\python\code 폴더에 wxEncyrption.py 이름으로 저장한다(역시 모르면 2교시로 가서 복습을...). 아래와 같이 실행하면 원하는 기능을 하는 윈도우 창이 뜨게 된다. 

 

c:\Python\code>python wxEncyrption.py

 

 

 

 

[마무리 하면서]

  자 그럼 앞으로 더 복잡하거나 새로운 GUI 컨트롤 들을 사용해서 만드려면 어떻게 해야할까?(파일 입력 박스, 라디오 버튼, 텍스트 박스 등등) 우리가 다운받아 사용한 wxPython Phoenix 홈페이지의 문서를 보면 wxPython 에서 현재 지원하고 있는 기능이 망라되어 있는 페이지가 있다. 여기 있는 요소들을 참조해 필요한 경우가 있다면 구글을 찾아서 실제 사용 예들을 참조해 보면 될 것 같다. 예를 들어 파일 다이얼로그인 filepickerctrl 을 사용하고 싶다면, 구글에서 'wxpython use filepickerctrl' 이라고 찾아보면 아마도 절절한 스택오버플로우 페이지들이 반겨줄 것이다.

https://wxpython.org/Phoenix/docs/html/wx.1moduleindex.html

 

 

 

 그럼 이것으로 9교시를 마치려고 한다.

 

 

[부록] 콘치즈파파님 문의 내용 답변

 

  위의 예시와 거의 비슷하고, GetQRCode 메소드 내에서 UI 화면에서 입력한 inputValue 값을 기존 만드신 코드와 연결해 가져와 저장하는 코드를 완료하심 될거 같아요.  해당 액션이 잘 끝나면 "저장완료" 라고 화면에 나올거고요.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import wx
 
 
# 윈도우즈 정의 클래스 입니다.
class Frame(wx.Frame):
    def __init__(self, parent, title):
        wx.Frame.__init__(self, parent, title=title, size=(500200))
        self.panel = wx.Panel(self)
        self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
 
        # 버튼을 생성 합니다.
        self.btn = wx.Button(self.panel, -1'QR 코드 저장')
 
        # 텍스트 박스를 생성합니다.
        self.txt = wx.TextCtrl(self.panel, -1, size=(140,-1))
        self.txt.SetValue('input your url')
        
        # 텍스트 라벨을 생성합니다.
        self.some_text = wx.StaticText(self.panel, size=(140,150), pos=(10,60))
        self.some_text.SetLabel('result is...')
 
        # 버튼 클릭 시 이벤트를 연결 합니다.
        self.Bind(wx.EVT_BUTTON, self.GetQRCode, self.btn)
 
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.btn)
        sizer.Add(self.txt)
 
        self.panel.SetSizer(sizer)
        self.Show()
 
    # 버튼 클릭 시 실행 되어, 암호화 하는 함수 입니다.
    def GetQRCode(self, e): 
        inputValue = self.txt.GetValue()
        
        # 이 inputValue 값을 QR 코드 쪽에 연결하면 됨.
        
        # 받은 값을 텍스트 라벨에 출력합니다.
        self.some_text.SetLabel("저장완료")
 
 
    def OnCloseWindow(self, e):
        self.Destroy()
 
# 메인코드 입니다.
# 윈도우를 띄우고 제목을 넣습니다.
app = wx.App()
frame = Frame(None, 'getQRCode')
app.MainLoop()
 
cs

 

[QR 코드랑 머지한 버전 - 이름을 겹치지 않게 시간을 이용해 만들어 넣음]

  예를 들어 www.google.co.kr 이라고 입력하면 관련된 QR 코드를 만듬.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
import wx
import qrcode
import datetime
 
# 윈도우즈 정의 클래스 입니다.
class Frame(wx.Frame):
    def __init__(self, parent, title):
        wx.Frame.__init__(self, parent, title=title, size=(500200))
        self.panel = wx.Panel(self)
        self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
 
        # 버튼을 생성 합니다.
        self.btn = wx.Button(self.panel, -1'QR 코드 저장')
 
        # 텍스트 박스를 생성합니다.
        self.txt = wx.TextCtrl(self.panel, -1, size=(140,-1))
        self.txt.SetValue('input your url')
        
        # 텍스트 라벨을 생성합니다.
        self.some_text = wx.StaticText(self.panel, size=(140,150), pos=(10,60))
        self.some_text.SetLabel('result is...')
 
        # 버튼 클릭 시 이벤트를 연결 합니다.
        self.Bind(wx.EVT_BUTTON, self.GetQRCode, self.btn)
 
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.btn)
        sizer.Add(self.txt)
 
        self.panel.SetSizer(sizer)
        self.Show()
 
    # 버튼 클릭 시 실행 되어, 암호화 하는 함수 입니다.
    def GetQRCode(self, e): 
        inputValue = self.txt.GetValue()
        
        # 이 inputValue 값을 QR 코드 쪽에 연결하면 됨.
        qr = qrcode.QRCode(version=1, error_correction=qrcode.constants.ERROR_CORRECT_L,box_size=10,border=4)
        qrAddress = "http://" + inputValue + "qrCodeId=CAD20181220041519"
        qr.add_data(qrAddress)
        qr.make(fit=True)
 
        img = qr.make_image()
 
        fileName = datetime.datetime.now().strftime("%Y%m%d_%H%M%S"+ ".png" 
        img.save(fileName)
        qr.clear()
        
        
        # 받은 값을 텍스트 라벨에 출력합니다.
        self.some_text.SetLabel("저장완료")
 
 
    def OnCloseWindow(self, e):
        self.Destroy()
 
# 메인코드 입니다.
# 윈도우를 띄우고 제목을 넣습니다.
app = wx.App()
frame = Frame(None, 'getQRCode')
app.MainLoop()
 
cs

 

 

[입력 창을 2개 만들어서, 이름을 받음]

  예를 들어 www.google.co.kr 과 google 이라고 입력 하면 google.png 로 생성해줌.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
import wx
import qrcode
 
# 윈도우즈 정의 클래스 입니다.
class Frame(wx.Frame):
    def __init__(self, parent, title):
        wx.Frame.__init__(self, parent, title=title, size=(500200))
        self.panel = wx.Panel(self)
        self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
 
        # 버튼을 생성 합니다.
        self.btn = wx.Button(self.panel, -1'QR 코드 저장')
 
        # 텍스트 박스를 생성합니다.
        self.txt = wx.TextCtrl(self.panel, -1, size=(140,-1))
        self.txt.SetValue('input your url')
        
        # 텍스트 박스를 생성합니다.
        self.txt2 = wx.TextCtrl(self.panel, -1, size=(140,-1), pos=(0,50))
        self.txt2.SetValue('input your file name')
        
        # 텍스트 라벨을 생성합니다.
        self.some_text = wx.StaticText(self.panel, size=(140,150), pos=(10,80))
        self.some_text.SetLabel('result is...')
 
        # 버튼 클릭 시 이벤트를 연결 합니다.
        self.Bind(wx.EVT_BUTTON, self.GetQRCode, self.btn)
 
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.btn)
        sizer.Add(self.txt)
 
        self.panel.SetSizer(sizer)
        self.Show()
 
    # 버튼 클릭 시 실행 되어, 암호화 하는 함수 입니다.
    def GetQRCode(self, e): 
        inputValue = self.txt.GetValue()
        
        # 이 inputValue 값을 QR 코드 쪽에 연결하면 됨.
        qr = qrcode.QRCode(version=1, error_correction=qrcode.constants.ERROR_CORRECT_L,box_size=10,border=4)
        qrAddress = "http://" + inputValue + "qrCodeId=CAD20181220041519"
        qr.add_data(qrAddress)
        qr.make(fit=True)
 
        img = qr.make_image()
 
        fileName =  self.txt2.GetValue() + ".png"
        img.save(fileName)
        qr.clear()
        
        
        # 받은 값을 텍스트 라벨에 출력합니다.
        self.some_text.SetLabel("저장완료")
 
 
    def OnCloseWindow(self, e):
        self.Destroy()
 
# 메인코드 입니다.
# 윈도우를 띄우고 제목을 넣습니다.
app = wx.App()
frame = Frame(None, 'getQRCode')
app.MainLoop()
 
cs

 

 

 

1
2017.3.5 by 자유로운설탕
cs

 

 

 

posted by 자유로운설탕