[출처 : http://www.python-forum.org/pythonforum/viewtopic.php?f=2&t=10224]


# create a wx.MemoryDC canvas on top of a blank bitmap
# you can then save the canvas drawings to a standard image file
# source: Dietrich   25nov2008  

import wx
import random

class MyFrame(wx.Frame):
    def __init__(self, parent, mytitle, mysize):
        wx.Frame.__init__(self, parent, wx.ID_ANY, mytitle, size=mysize)
        self.show_bmp = wx.StaticBitmap(self)
        self.draw_image()
        self.save_image()

    def draw_image(self):
        # get the width and height for the blank bitmap
        w, h = self.GetClientSize()
        # create the blank bitmap as a drawing background
        draw_bmp = wx.EmptyBitmap(w, h)
        # create the canvas on top of the draw_bmp
        canvas = wx.MemoryDC(draw_bmp)
        # fill the canvas white
        #canvas.SetBrush(wx.Brush('white'))
        #canvas.Clear()
        
        # pen colour, default is black
        #canvas.SetPen(wx.Pen('red', 1))
        
        # draw a bunch of random circles ...
        bunch = 100
        for k in range(bunch):
            # fill colour
            r = random.randint(0, 255)
            g = random.randint(0, 255)
            b = random.randint(0, 255)
            colour = wx.Colour(r, g, b)
            canvas.SetBrush(wx.Brush(colour))
            x = random.randint(0, w)
            y = random.randint(0, h)
            r = random.randint(10, w/4)
            canvas.DrawCircle(x, y, r)

        # put the canvas drawing into the static bitmap to display it
        # (remember the canvas is on top of a draw_bmp empty bitmap)
        self.show_bmp.SetBitmap(draw_bmp)

    def save_image(self):
        """save the drawing"""
        # get the image object
        circles_image = self.show_bmp.GetBitmap()
        circles_image.SaveFile("mycircles.jpg", wx.BITMAP_TYPE_JPEG)


app = wx.App(0)
mytitle = 'draw random circles and save image'
width = 420
height = 400
MyFrame(None, mytitle, (width, height)).Show()
app.MainLoop()


Circles1.jpg
[출처 : http://www.daniweb.com/code/snippet216704.html]


# experiment with wxPython's
# wx.media.MediaCtrl(parent, id, pos, size, style, backend)
# the backend (szBackend) is usually figured by the control
# wxMEDIABACKEND_DIRECTSHOW   Windows
# wxMEDIABACKEND_QUICKTIME    Mac OS X
# wxMEDIABACKEND_GSTREAMER    Linux (?)
# plays files with extension .mid .mp3 .wav .au .avi .mpg
# tested with Python24 and wxPython26 on Windows XP   vegaseat  10mar2006

import wx
import wx.media
import os

class Panel1(wx.Panel):
    def __init__(self, parent, id):
        #self.log = log
        wx.Panel.__init__(self, parent, -1, style=wx.TAB_TRAVERSAL|wx.CLIP_CHILDREN)

        # Create some controls
        try:
            self.mc = wx.media.MediaCtrl(self, style=wx.SIMPLE_BORDER)
        except NotImplementedError:
            self.Destroy()
            raise

        loadButton = wx.Button(self, -1, "Load File")
        self.Bind(wx.EVT_BUTTON, self.onLoadFile, loadButton)
        
        playButton = wx.Button(self, -1, "Play")
        self.Bind(wx.EVT_BUTTON, self.onPlay, playButton)
        
        pauseButton = wx.Button(self, -1, "Pause")
        self.Bind(wx.EVT_BUTTON, self.onPause, pauseButton)
        
        stopButton = wx.Button(self, -1, "Stop")
        self.Bind(wx.EVT_BUTTON, self.onStop, stopButton)

        slider = wx.Slider(self, -1, 0, 0, 0, size=wx.Size(300, -1))
        self.slider = slider
        self.Bind(wx.EVT_SLIDER, self.onSeek, slider)
        
        self.st_file = wx.StaticText(self, -1, ".mid .mp3 .wav .au .avi .mpg", size=(200,-1))
        self.st_size = wx.StaticText(self, -1, size=(100,-1))
        self.st_len  = wx.StaticText(self, -1, size=(100,-1))
        self.st_pos  = wx.StaticText(self, -1, size=(100,-1))
        
        # setup the button/label layout using a sizer
        sizer = wx.GridBagSizer(5,5)
        sizer.Add(loadButton, (1,1))
        sizer.Add(playButton, (2,1))
        sizer.Add(pauseButton, (3,1))
        sizer.Add(stopButton, (4,1))
        sizer.Add(self.st_file, (1, 2))
        sizer.Add(self.st_size, (2, 2))
        sizer.Add(self.st_len,  (3, 2))
        sizer.Add(self.st_pos,  (4, 2))
        sizer.Add(self.mc, (5,1), span=(5,1))  # for .avi .mpg video files
        self.SetSizer(sizer)

        self.timer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.onTimer)
        self.timer.Start(100)
        
    def onLoadFile(self, evt):
        dlg = wx.FileDialog(self, message="Choose a media file",
                            defaultDir=os.getcwd(), defaultFile="",
                            style=wx.OPEN | wx.CHANGE_DIR )
        if dlg.ShowModal() == wx.ID_OK:
            path = dlg.GetPath()
            self.doLoadFile(path)
        dlg.Destroy()
        
    def doLoadFile(self, path):
        if not self.mc.Load(path):
            wx.MessageBox("Unable to load %s: Unsupported format?" % path, "ERROR", wx.ICON_ERROR | wx.OK)
        else:
            folder, filename = os.path.split(path)
            self.st_file.SetLabel('%s' % filename)
            self.mc.SetBestFittingSize()
            self.GetSizer().Layout()
            self.slider.SetRange(0, self.mc.Length())
            self.mc.Play()
        
    def onPlay(self, evt):
        self.mc.Play()
    
    def onPause(self, evt):
        self.mc.Pause()
    
    def onStop(self, evt):
        self.mc.Stop()
    
    def onSeek(self, evt):
        offset = self.slider.GetValue()
        self.mc.Seek(offset)

    def onTimer(self, evt):
        offset = self.mc.Tell()
        self.slider.SetValue(offset)
        self.st_size.SetLabel('size: %s ms' % self.mc.Length())
        self.st_len.SetLabel('( %d seconds )' % (self.mc.Length()/1000))
        self.st_pos.SetLabel('position: %d ms' % offset)


app = wx.PySimpleApp()
# create a window/frame, no parent, -1 is default ID
frame = wx.Frame(None, -1, "play audio and video files", size = (320, 350))
# call the derived class
Panel1(frame, -1)
frame.Show(1)
app.MainLoop()
[출처 : http://forcecore.tistory.com/1033]


wxGlade가 처음에는 구려보이지만, 있는 것들 중 가장 나은것이라는 점을 알 수 있다 -_-;; 해보면...;; 주의할 점은, 한글 지원이 안 된다는 것이다. 아니면 필자가 못하는건가? 처음에 디자인 단계는 모든 것을 영어로 한 뒤, 나중에 코드생성이 된 이후, 코드를 한글로 좀 고쳐주면, python자체는 한글이 안 되는건 아니라 그럭저럭 한글이 되긴 한다.

우선 wxGlade의 리소스 파일이 저장될 곳을 물색해야 한다.
주의할 점은, 저장되는 곳은 절대로 한글이 들어가지 않는 폴더여야 한다는 점이다. 그런 측면에서, 윈도우 사용자 이름이 한글이거나, 바탕화면, 내 문서 같은 곳은 고르면 안 된다 -_-;;

필자는 c:\mod 폴더를 생성했다.

이제 wxGlade를 실행시킨다.


이런 썰렁한 창이 뜬다. 뭘 하란거지? 처음엔 좀 황당하다.

알아두어야 할 것이, 델파이나 비주얼 스튜디오와는 달리, 거의 모든 요소들이 boxSizer라는 것 안에 들어가야 한다는 점이다.

처음에는 wxGlade:Tree 라고 적힌 창에 Application만 있어야 한다.
팔레트 창에서 add a dialog버튼을 누르면 창을 하나 볼 수 있게 된다.


이렇게 되어 있는데.. class는 적당히 MainDialog 이런 식으로 적고 OK를 누른다. wsDialog를 선택하는건 필수;


아무것도 없는 창이 하나 더 보이게 될 것이다. 여기다가 대고 디자인을 하면 되는데, 버튼을 두개 추가하려고 해도 잘... 안 될 것이다. 이유는... 아까도 말 했지만, BoxSizer라는 것을 이용해야 하기 때문이다. 버튼을 혹시 넣으려고 해봤다면 -_- tree에서 오른 클릭을 해서 지우든, 창에서 선택하고 del버튼을 누르든 선택하여 없애라.

이쯤에서 필자의 최종 목표를 미리 밝혀야 할 듯 싶다.


이런 창을 만드는 것이다. 저 구성을 염두에 두고...

다시 원상 복구가 된 뒤 이번에는, BoxSizer를 넣는다. 그리고 메인창에 클릭을 하면...


이런 창이 뜨는데, vertical을 택하고, slot은 2를 선택한다. 왜 2냐면, 필자는 크게 저 그림을 품는 영역과 버튼을 품는 영역을 나누고 싶기 때문이다. 이런식으로 영역 나눔을 먼저 해야지 그 영역에 버튼을 놓든 말든 할 수 있다는 특징이 있다.


창이 이렇게 될 것이다. 빗금친 영역에는 버튼과 같은 것을 놓을 수 있다.

Static Bitmap을 아래에다 놓고, 그림을 불러오자. StaticBitmap버튼을 클릭한뒤 아래 빗금에 클릭하면, 원하는 이미지를 불러올 수 있게 된다.


두둥. 저 창을 닫았다가 다시 켜보자. 닫은 다음에 다시 켜려면, tree에서 dialog에 더블클릭을 하면 된다.


쪼그라들었다 ㅡ,.ㅡ;; 보통은 wxWidget의 (wxPython이 사용하는 라이브러리!) 구성요소들은, 사이즈가 좀 지멋대로다. 일부러 지정해주지 않는한은...

이제쯤 저장하라. 언두 기능이 없어서, 뭔가 잘못해서 큰 덩어리 하나를 실수로라도 삭제하면, 이제껏 한 작업이 통째로 날아가게 된다 -_-;;;;;; 버전 0.6.3 기준임. 버전업되면 생기겠지... OTL

이제 BoxSizer로 6칸짜리 vertical을 윗 영역에 넣자. 창이 너무 쪼그라 들어서, 제대로 안 보일 것이다. 창을 껐다 다시 켠다.


그러면 이렇게 보인다. 아래 다섯칸에는 버튼을 넣는다.


... 문제가 두개 있다.
1. 버튼 가로길이가 너무 작다 -_-
2. 버튼에 여백이 없어서, 창에 찰싹 달라 붙어 있다.


키우고자 하는 버튼을 선택하고, properties창의 layout탭에서 wxEXPAND를 해주면, 늘어날 수 있는 한도까지 쭉 늘어난다.


그 외에, size에 체크박스를 하고 일부러 크기를 입력해주면 크기를 정확하게 넣을 수 있다. 하지만 필자의 의도는, 로고 그림이 커지면 버튼도 같이 커지는 것이므로, 위에 설명한 wxEXPAND면 충분하다. 버튼의 세로 사이즈가 -1로 되어있는데, 이는, 그냥 default치를 사용하는 것이다?

Properties에서 Widget탭을 보면, 버튼에 어떤 글자가 들어가야 하는지 지정해 줄 수 있다. Common의 name항목도 예쁘게 해주어야 한다. 가령, Quit이라고 적힌 버튼은, name이 button_quit 으로 필자가 설정했다.

이제 여백도 넣어볼까... 두번째에 넣었던 버튼용 BoxSizer의 property에서


이렇게 Border를 0이 아닌 값으로 주고, Border중, 여백을 줄 방향에 체크해주면 됨.

이제 enable, disable버튼 두개를 추가해주고 싶은데... 빈 영역에 horizontal BoxSizer를 넣자. 슬롯 두개짜리.


이 버튼들 가로 크기가 동일하고, 가로로 꽉 채웠으면 좋겠는데... 역시 죽어도 안 된다. 오히려, wxEXPAND를 사용하면 세로로는 늘어나는 것을 볼 수 있다. 그 이유는... BoxSizer가 Horizontal이면 버튼은 세로로 expand되고, vertical이면 가로로 expand되기 때문이다. -_-^;; 어쩔 수 없이... 머리를 좀 써서... 버튼 두개만 삭제하고, 버튼이 있던 자리에, 크기1짜리의 vertical BoxSizer를 넣는다 -_-;; 그러면 된다.


모양은 완성됐다. 두둥.

이제 Quit버튼에 들어갈 이벤트 핸들러 (클릭시 일어나면 프로그램이 취할 행동) 를 넣어보자.
Quit버튼을 선택하고 Events의 EVT_BUTTON에
 

on_btn_quit 과 같은 것을 넣어주자. 마우스 오버같은 이벤트는 디텍트 안 되나? 하긴 그런 프로그램은, "보통은" 나오지 않는... 데...;; 예쁜 프로그램을 만들거 아니면.

이제 모양은 다 디자인 했으니 python코드를 생성하라고 해보자.


트리에서, application을 선택하면, 프로퍼티 창에 저런 게 뜬다. Encoding이 좀 기분나쁜 값으로 되어 있는데, 현재로서는 무시하자. 어차피 우리가 코딩을 좀 하면서 수정할 것이다. 그리고 옵션은 원하는 대로 선택하고, Output path의 ...버튼을 클릭하여, 생성될 코드의 이름을 지정해주자. Generate Code버튼을 클릭하면 코드가 나오고...



코드를 실행하면 원하는대로 창이 뜬다. wxGlade에서 보던 것 보다 버튼같은게 테마 적용이 되어 예쁘게 보인다. Quit버튼을 클릭하면, on_btn_quit이 아직 구현되지 않았다고 뜰 것이다.

아까 생성한 스크립트를 이제 텍스트 편집기로 열어보자.

파일 시작 부분에는
#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-
# generated by wxGlade 0.6.3 on Tue Jun 30 00:20:50 2009

import wx

이런게 있는데 iso어쩌구 대신 cp949를 넣어주자. wsGlade에서 하지 않은 이유는? cp949라고하면, "나는 그런 인코딩은 몰라"라고 wxGlade가 우기기 때문이다 -_-;;

코드를 더 읽다보면
        self.button_en = wx.Button(self, -1, "Enable")
        self.button_dis = wx.Button(self, -1, "Disable")
        self.button_run = wx.Button(self, -1, "Run")
        self.button_modhome = wx.Button(self, -1, "Mod Homepage")
        self.button_red2net = wx.Button(self, -1, "red2.net")
        self.button_quit = wx.Button(self, -1, "Quit" )
이런 버튼에 적힐 글귀가 있는 코드가 있는데 그것도 고쳐주자.


한글도 잘만 된다. +_+

    def on_btn_quit(self, event): # wxGlade: MainDialog.<event_handler>
        print "Event handler `on_btn_quit' not implemented"
        event.Skip()

quit버튼을 누르면 구현이 안 됐다고 뜨게 하는 기능은 여기 있다. 여기있는 place holder 코드를 지우고 원하는 기능으로 고친다.

    def on_btn_quit(self, event): # wxGlade: MainDialog.<event_handler>
        self.Close()

창을 닫는 코드를 실제로 넣어 주었다.

다시 실행을 시켜보면, 창은 닫히는데, 검은창은 없어지지 않는다... 원래 그런거지...
필자가 스크립트의 이름을 mod.py 라고 지었기 때문이다.
mod.pyw로 이름을 변경하라. 그러면 땡이다.

다음 시간에는 exe로 컴파일도 해보자.
출처 : http://forcecore.tistory.com/1032]


Python 2.6기준으로 쓴 글임을 밝힌다. 주요 사용자 계층은 32비트 윈도우 사용자다. 자바는 자바를 따로 설치해야 해서 사용자들의 귀차니즘이 있는고로, python을 선택함.

환경 갖추기:
0. vim이 되었든 뭐가 되었든 좋아하는 에디터가 python 하이라이팅을 지원하게 만든다.

이제부터 프로그램을 여러개 설치하게 되는데... 다 넥스트 넥스트 눌러서 설치하면 된다. 참 쉽죠?

1. python 윈도우용을 받는다.
http://www.python.org/download/
여기에서, 필자는 2.6.2 windows installer를 받아서 설치했다.
python-2.6.2.msi 이런거

2. wxPython도 받아서 설치해야지 GUI 지원이 된다?
http://www.wxpython.org/download.php
여기서 python2.6이라고 된 것에서 win32-unicode를 받는다.

wxPython2.8-win32-unicode-2.8.10.1-py26.exe
이렇게 생겼음.

3. GUI프로그램을 GUI적이지 못하게 코딩으로 만들려면 인생이 고달프므로... 코드를 어느정도 자동으로 생성해주는 프로그램이 필요하다. 필자는 PythonCard, Boa Constructor, wxGlade 세가지를 써봤는데, 가장 나은 것은 wxGlade이다.

wxGlade는 http://wxglade.sourceforge.net/ 여기 있다. 아니, 좀 더 정확히는
http://sourceforge.net/projects/wxglade 여기.
wxGlade-0.6.3-setup.exe 이렇게 생긴 것을 받는다.

4. 마지막으로 python으로 짠 것을 exe로 실행시킬 수 있게 해야 한다.
http://www.py2exe.org/ 여기서
py2exe-0.6.9.win32-py2.6.exe
이런 것을 받는다. 2.6으로, 자신의 python 버전과 맞는 것을 설치해야지 됨.
[출처 : http://www.imp17.com/tc/myevan/95]


일단 리눅스의 사운드 연주 소스입니다.

#!/usr/bin/python
import linuxaudiodev
import wave

src = wave.open("test.wav""rb")
channels, bytes, freq, frameCount, compType, compName  = src.getparams()

dsp = linuxaudiodev.open("/dev/dsp""w")
dsp.setparameters(freq, bytes*8, channels, linuxaudiodev.AFMT_S16_LE, False)

frameStep = 1000
for pos in range(0, frameCount, frameStep):
    buf = src.readframes(frameStep)
    dsp.write(buf)

리눅스에서 사운드 플레이를 정말 쉽습니다 -_-)~ 그냥 모든게 파일이라 좋아요.

하지만 역발상의 대가 윈도우에서는 유닉스와는 다른길을 걷기 때문에
위의 코드로 작동이 되지 않습니다 -_-)> wav 파일이라면 winsound 라는 모듈을 지원하지만
지금 작업은 RAW 데이터를 플레이하는거라서 직접 wave파일에 접근해야합니다.

다행히 http://www.johnnypops.demon.co.uk/ 라는 사이트에서 
녹음 기능을 ctypes 로 구현해놓은것이 있어서 (정말 좋은 사람이예요 >ㅁ<)/ )
이 소스를 활용해 같은 기능을 하는 프로그램을 만들어보았습니다.
(c++ 객체만 ctypes 로 꺼낼수 있으면 정말 행복할거예요)
[출처 : http://www.imp17.com/tc/myevan/72?category=4]


dir 만으로는 원하는 함수를 찾기 힘들때가 있다.

def candi(obj, findName):
    return [itemName for itemName in dir(obj) if itemName[:len(findName)] == findName]

import os
print "dir"
print dir(os.path)
print ""
print "candi"
print candi(os.path, "split")


~(-_-)~ 짠

dir
['__all__', '__builtins__', '__doc__', '__file__', '__name__', '_getfullpathname
', 'abspath', 'altsep', 'basename', 'commonprefix', 'curdir', 'defpath', 'devnul
l', 'dirname', 'exists', 'expanduser', 'expandvars', 'extsep', 'getatime', 'getc
time', 'getmtime', 'getsize', 'isabs', 'isdir', 'isfile', 'islink', 'ismount', '
join', 'lexists', 'normcase', 'normpath', 'os', 'pardir', 'pathsep', 'realpath',
 'sep', 'split', 'splitdrive', 'splitext', 'splitunc', 'stat', 'supports_unicode
_filenames', 'sys', 'walk']

candi
['split', 'splitdrive', 'splitext', 'splitunc']


numpy 
파이썬에서 고속의 수학 연산을 지원합니다.
http://sourceforge.net/projects/numpy/


SciPy
numpy 를 기반으로 수학이나 과학 문제를 풀 때 쓸만한 유틸리티 모듈입니다. 다양한 인터폴레이션 함수 지원이 매력적입니다.
http://sourceforge.net/projects/scipy/files/



matplotlib
파이썬에서 그래프를 그려주는 모듈입니다.
http://matplotlib.sourceforge.net/
[출처 : http://www.imp17.com/tc/myevan/231]


서버 로그는 여러명의 사용자가 엄청난 양을 만들어내기 때문에
눈으로만 분석하기는 많이 어렵습니다. 

로그 분석기를 만들어서 체크하는 것이 좋은데;
문자열 처리가 빈약한 c/c++ 보다는 강력한 문자열 처리 기능을 제공하는 스크립트 언어를 사용하는 것이 좋습니다.

Jan 30 03:20:37 new connection from [192.168.1.1] to fd: 10
위와 같은 로그는 사람이 읽기에는 쉽지만, 컴퓨터에게 이해시키기란 조금 어렵습니다.

가장 무식한 방법은 글자수 센다음 파싱하는 것입니다.
하지만 이런 코드는 로그 형식이 조금만 바뀌어도 고치기가 어려워지죠;

다른 방법으로는 split 과 find 를 사용하는 방법이 있습니다.
아무리 간단하게 작성한다해도 하나의 형식에 5~10줄 정도의 코드가 나오게 됩니다.
문제는 이런 코드들은 나중에 재활용도 쉽지않은 정크 코드인지라; 매번 새로 작성해야합니다.
인터프리터 언어의 특성상 느리기까지 하죠.

로그를 분석하는 가장 좋은 방법은 정규 표현식이라 할 수 있습니다 -_-)/


import re

NEW_CONNECTION
= re.compile("new connection from \[(\d+.\d+.\d+.\d+)\] to fd: (\d+)")

if __name__ == "__main__":
    newConnection
= NEW_CONNECTION.search("new connection from [192.168.1.1] to fd: 10")
   
if newConnection:
       
print "ip:", newConnection.group(1)
       
print "fd:", newConnection.group(2)


파싱 코드는 re.compile("new connection from \[(\d+.\d+.\d+.\d+)\] to fd: (\d+)") 한줄로 끝나게 됩니다.
로그 형식이 바뀌더라도 정규 표현식 문구만 바꾸어주면 되죠 : )

+ Recent posts