久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

使用wxPython開發(fā)一個簡單GUI應(yīng)用

 dinghj 2014-04-16

 python用的時間不長,,一般用來做字符串處理,、簡單測試的一些小程序。最近工作中需要做一個簡單的GUI應(yīng)用,,使用麥克錄音并存成wave文件,。然后就想拿wxPython練練手。

一,、概述

GUI開發(fā)采用wxPython,,界面編輯工具采用wxGlade,聲音采集和播放采用PyAudio,,小數(shù)據(jù)庫采用sqlite3,,最后使用py2exe打包發(fā)布?;镜膽?yīng)用開發(fā)流程都包括了,。

二、wxGlade

界面編輯工具也是找了幾個,,比如wxFormBuilder,,甚至是收費的DialogBlocks,wxFormBuilder 很漂亮,,不過bug好像較多,,經(jīng)常自動退出。wxGlade有經(jīng)典的Linux GUI界面風(fēng)格,,分立式窗體,,了解了基本的原理后用起來很方便。主要是其中的sizer,,add slot,、insert slot增加空位,,然后添加控件。也可以添加自定義的控件,,只需要設(shè)置自定義控件的Class屬性,。然后在MainFrame的Extra code for this widget增加from YourModule import YourCLass。因為界面比較簡單,,我沒有采用XRC資源導(dǎo)入的模式,,而是直接生成MainFrame的代碼。由于界面設(shè)計可能會變,,在應(yīng)用中新建一 個MainFrameEx類繼承MainFrame,,將事件處理放在繼承類中完成。這樣每次使用wxGlade編輯界面后可以直接覆蓋生成的代碼,。

三,、PyAudio

PyAudio是從PortAudio移植的,現(xiàn)在還是alpha版,。不過使用起來還真是方便,,看看網(wǎng)站上提供的example就可以了。沒有什么大問題,。需要注意多線程的問題,,PyAudio對象盡量復(fù)用。注意線程中刷新wxWidget需要使用wx.CallAfter方法,。

# -*- coding: UTF-8 -*-

import pyaudio
import wave
import threading
import wx
import datetime
import traceback
import os
import logging

logger = logging.getLogger("root")

class BMRecord(threading.Thread):
    CHUNK = 1024
    FORMAT = pyaudio.paInt16  # 至少為16位
    DEVICE = 1
    CHANNELS = 1
    RATE = 44100
    RECORD_SECONDS = 5   

    def __init__(self, window, audio, device, prefix):
        threading.Thread.__init__(self)
        self.window = window
        self.audio = audio
        self.prefix = prefix  # wave文件命名的前綴
        self.DEVICE = device
        self.CHANNELS = 2  # 雙通道采集
        self.RECORD_SECONDS = int(window.params["length"])
        self.RATE = int(window.params["rate"])
        self.FORMAT = pyaudio.paInt16

    def record(self):
        self.filename = ""
        self.filetime = ""
        try :
            stream = self.audio.open(format=self.FORMAT,
                            channels=self.CHANNELS,
                            rate=self.RATE,
                            input=True,
                            input_device_index=self.DEVICE,
                            frames_per_buffer=self.CHUNK)       
            frames = []
            for i in range(0, int(self.RATE * self.RECORD_SECONDS / self.CHUNK)):
                data = stream.read(self.CHUNK)
                frames.append(data)
                i = i                     
            stream.stop_stream()
            stream.close()       
             
            now = datetime.datetime.now()
            strnow = now.strftime('%Y%m%d%H%M%S')
            self.filetime = now.strftime('%Y-%m-%d %H:%M:%S')
            savepath = self.checkPath(strnow)            
            
            # 雙聲道存為兩個單聲道文件
            frames1 = []
            frames2 = []
            wavedata = b''.join(frames)
            for i in range(len(wavedata) / 4):                
                frames1.append(wavedata[i * 4 : i * 4 + 2])
                frames2.append(wavedata[i * 4 + 2 : i * 4 + 4])
            
            # 雙聲道存儲    
            fullpath = savepath + "/" + strnow + self.prefix + "X.wav"
            wf = wave.open(fullpath, 'wb')
            wf.setnchannels(2)
            wf.setsampwidth(self.audio.get_sample_size(self.FORMAT))
            wf.setframerate(self.RATE)
            wf.writeframes(wavedata)
            wf.close()    
            # 兩個單聲道存儲
            filenames = [strnow + self.prefix + "Z.wav", strnow + self.prefix + "Y.wav"]
            fullpath = savepath + "/" + filenames[0]
            wf = wave.open(fullpath, 'wb')
            wf.setnchannels(1)
            wf.setsampwidth(self.audio.get_sample_size(self.FORMAT))
            wf.setframerate(self.RATE)
            wf.writeframes(b''.join(frames1))
            wf.close()
            fullpath = savepath + "/" + filenames[1]
            wf = wave.open(fullpath, 'wb')
            wf.setnchannels(1)
            wf.setsampwidth(self.audio.get_sample_size(self.FORMAT))
            wf.setframerate(self.RATE)
            wf.writeframes(b''.join(frames2))
            wf.close()                                   
            self.message = "錄制成功"
            self.filenames = filenames
            logger.info(filenames[0] + "," + filenames[1] + ", recorded")
            return 0
        except Exception:
            self.message = traceback.format_exc()
            logger.error(traceback.format_exc())
            return -1
    
    def checkPath(self, pathname):
        curpath = os.path.abspath(os.curdir)
        strdate = pathname[0:8]  
        fullpath = curpath + "/data/" + strdate
        if  not os.path.exists(fullpath) :
            os.makedirs(fullpath)  
        return fullpath
            
    def run(self):
        ret = self.record()            
        wx.CallAfter(self.window.recordResult, ret, self.filenames, self.filetime, self.message)

四,、sqlite

sqlite模塊是Python內(nèi)置的用起來很方便:

import sqlite3
import datetime

class BMDatabase():
    
    def loadData(self, whichDay):
        conn = sqlite3.connect("data/bmon.db")         
        cur = conn.cursor()
        start = datetime.datetime.strptime(whichDay, "%Y-%m-%d")      
        end = start + datetime.timedelta(days=1)  
        res = cur.execute("select * from CheckRecord where rec_time between ? and ? order by rec_time", (start, end))          
        return res.fetchall()
    
    def getFile(self, waveFile):
        conn = sqlite3.connect("data/bmon.db")         
        cur = conn.cursor()        
        res = cur.execute("select * from CheckRecord where rec_file=?", (waveFile,))          
        row = res.fetchone()
        return row
        
    def save(self, filename, filetime, result):
        conn = sqlite3.connect("data/bmon.db")
        cur = conn.cursor()
        record = [(filename, filetime, result)]
        cur.executemany('INSERT INTO CheckRecord (rec_file,rec_time,result) VALUES (?,?,?)', record)
        conn.commit()


五、自定義wxWidget控件

自繪控件主要是處理EVT_PAINT事件: self.Bind(wx.EVT_PAINT, self.on_paint)

import wx

class WavePane(wx.StaticText):
    waveData = None
    spectrum = None
    def __init__(self, parent, nid=wx.ID_ANY, caption=""):
        wx.StaticText.__init__(self, parent)
        self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
        self.Bind(wx.EVT_SIZE, self.on_size)
        self.Bind(wx.EVT_PAINT, self.on_paint)
        
    def on_size(self, event):
        self.Refresh()
        event.Skip()
        
    def on_paint(self, event):
        w, h = self.GetClientSize()
        dc = wx.AutoBufferedPaintDC(self)
        brush = wx.Brush(wx.Color(0, 0, 0x80), wx.SOLID)
        dc.SetBrush(brush)
        dc.Clear()
        dc.SetPen(wx.Pen(wx.BLACK, 1))
        dc.SetTextForeground(wx.Color(0, 0xFF, 0))
        font = dc.GetFont()
        font.SetPointSize(8)
        dc.SetFont(font)
        dc.DrawRectangle(0, 0, w - 1, h - 1)
        if self.waveData <> None:
            dc.BeginDrawing()
            dc.SetPen(wx.Pen(wx.Color(0, 0xFF, 0), 1))
            au = self.waveData
            step = int(au.nframes / w)
            height = au.height  # 或者65536 / 2.0
            i = 0
            j = 0
            while i < au.nframes:
                if au.frames[2 * i + 1] >= 0x80:  # 負(fù)數(shù)
                    value = au.frames[2 * i] + au.frames[2 * i + 1] * 256 - 65536
                else:
                    value = au.frames[2 * i] + au.frames[2 * i + 1] * 256                
                dc.DrawLine(j, int(h / 2.0), j, int(h / 2.0 * (1 - value * 1.0 / height))) 
                i += step
                j += 1
                if 2 * i + 1 >= au.nframes * 2:
                    break;            
            dc.DrawText(str(au.maxValue), 1, 1)
            dc.DrawText(str(au.minValue), 1, h - 16)
            dc.EndDrawing()
        elif self.spectrum <> None :
            dc.BeginDrawing()
            dc.SetPen(wx.Pen(wx.Color(0, 0xFF, 0), 1))  
            brush = wx.Brush(wx.Color(0, 0xFF, 0), wx.SOLID)
            dc.SetBrush(brush)          
            dc.SetTextForeground(wx.RED)           
            barWidth = int(w / 72)
            i = 0
            j = barWidth
            while i < 36:
                y = int((1 - self.spectrum[i] * 1.0 / self.maxSpectrum) * h)
                dc.DrawRectangle(j, y , barWidth, h - y - 1) 
                if y < h - 2:
                    dc.FloodFill(j + 1, y + 1, wx.Color(0, 0xFF, 0), wx.FLOOD_BORDER)
                # Bar的編號
                if i == 0 or(i + 1) % 5 == 0:
                    if i < 9:
                        dc.DrawText(str(i + 1), j + 4, h - 13)
                    else:
                        dc.DrawText(str(i + 1), j , h - 13)
                i += 1
                j += barWidth * 2
            dc.SetTextForeground(wx.Color(0, 0xFF, 0))
            dc.DrawText(str(self.maxSpectrum), 1, 1)
            dc.EndDrawing()
        
    def setWaveData(self, waveData):
        self.waveData = waveData
        self.Refresh()
    
    def setSpectrum(self, spectrum):
        self.spectrum = spectrum
        if spectrum <> None:
            maxValue = 0
            for i in range(0, 36):            
                if  spectrum[i] > maxValue :
                    maxValue = spectrum[i]
            self.maxSpectrum = maxValue
        self.Refresh()

六,、日志的使用

使用循環(huán)日志

import logging.handlers
    logger = logging.getLogger("root")
    handler = logging.handlers.RotatingFileHandler(os.path.join(os.getcwd(), 'bmon.log'),
                                                   maxBytes=5 * 1024 * 1024, backupCount=5)
    formatter = logging.Formatter('%(asctime)s %(levelname)s: %(message)s')
    handler.setFormatter(formatter)
    logger.addHandler(handler)
    logger.setLevel(logging.DEBUG)

七,、py2exe

最后一步就是打包成可執(zhí)行文件。setup.py:

from distutils.core import setup
import py2exe


# setup(console=["hello.py"])
py2exe_options = dict({
    "includes":['sip', 'encodings', 'encodings.ascii', 'encodings.utf_8', 'encodings.cp866'],
    "dll_excludes":["MSVCP90.dll"]})

setup(version="1.0",
      description="Bearing Monitor",
      name="bmon",
      zipfile=None,
      dist_dir="bmon",
      windows=["bmon.py"],
      options={'py2exe': py2exe_options},
      icon_resources=[(1, "check_all.ico")],
      data_files=[("", ["check_all.ico"])] 
    )

然后命令行下執(zhí)行:python setup.py py2exe,,就可以生成dist發(fā)布目錄

八,、小結(jié)

這個簡單應(yīng)用涉及的主要模塊就這么幾個,組合成了一個簡單的GUI應(yīng)用,。Python開發(fā)還真是很簡單,,前提是得熟悉各種模塊。 

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購買等信息,,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請點擊一鍵舉報,。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多