Python写的简易代码统计工具(3)
本文介绍代码统计工具的窗口界面,使用wxPython库实现了简易界面,见下图:
用wxPython编写界面,可以分为以下四步:
第一步:搭好框架,定义wx.App类和wx.Frame类的子类。
第二步:创建控件。
第三步:绑定消息。
第四步:编写响应消息的函数。
界面编写只懂些皮毛,所以这个程序只是实现了功能,并没有什么出彩的地方。
下面是CodeCounterW.pyw文件中的代码:
#
-*- coding: cp936 -*-
'''
这是一个用Python写的简易代码统计工具。
作者:lemene
网址:http://www.cppblog/lemene
'''
import wx
import os
from counter import CodeCounter
# 代码类型和对应的文件后缀名
codetyps = [[ ' C ' , ' Python ' ],
[ ' .c,.cpp,.h ' , ' .py ' ]]
class ResultList(wx.ListCtrl):
''' 显示结果的控件 '''
def __init__ (self, parent, ID =- 1 , pos = wx.DefaultPosition,
size = wx.DefaultSize, style = wx.LC_REPORT):
wx.ListCtrl. __init__ (self, parent, ID, pos, size, style)
self.InsertColumn(0, " 文件名 " )
self.InsertColumn( 1 , " 总行数 " )
self.InsertColumn( 2 , " 代码 " )
self.InsertColumn( 3 , " 注释 " )
self.InsertColumn( 4 , " 空行 " )
def Clear(self):
''' 清空结果 '''
self.DeleteAllItems()
def ShowResult(self, results):
''' 显示结果 '''
i = 0
for res in results:
self.InsertStringItem(i, res[0])
self.SetStringItem(i, 1 , str(res[ 1 ][ 4 ]))
self.SetStringItem(i, 2 , str(res[ 1 ][ 1 ] + res[ 1 ][ 3 ]))
self.SetStringItem(i, 3 , str(res[ 1 ][ 2 ] + res[ 1 ][ 3 ]))
self.SetStringItem(i, 4 , str(res[ 1 ][0]) )
class CounterFrame(wx.Frame):
''' 程序界面 '''
def __init__ (self, parent, title):
wx.Frame. __init__ (self, parent, - 1 , title, size = ( 495 , 435 ),
style = wx.DEFAULT_FRAME_STYLE ^ wx.RESIZE_BORDER)
# 添加界面控件
panel = wx.Panel(self)
# 第一行控件
text1 = wx.StaticText(panel, - 1 , " 代码类型: " ,style = wx.ALIGN_RIGHT)
cb1 = wx.ComboBox(panel, - 1 , codetyps[0][0],choices = codetyps[0],style = wx.CB_READONLY, size = ( 100 , - 1 ))
text2 = wx.StaticText(panel, - 1 , " 后缀名: " )
cb2 = wx.ComboBox(panel, - 1 , codetyps[ 1 ][0],choices = codetyps[ 1 ],size = ( 190 , - 1 ))
sizer1 = wx.BoxSizer(wx.HORIZONTAL)
sizer1.Add(text1, 0, wx.RIGHT | wx.LEFT, 10 )
sizer1.Add(cb1, 0, wx.RIGHT | wx.LEFT, 10 )
sizer1.Add(text2, 0, wx.RIGHT | wx.LEFT, 10 )
sizer1.Add(cb2, 0, wx.RIGHT | wx.LEFT, 10 )
# 第二行控件
rb = wx.RadioBox(panel, - 1 , "" , wx.DefaultPosition, wx.DefaultSize,
[ ' 目录 ' , ' 文件 ' ])
ckb = wx.CheckBox(panel, - 1 , " 包括子目录 " )
fordtx = wx.TextCtrl(panel, - 1 , "" , size = ( 190 , - 1 ))
openfdbtn = wx.Button(panel, - 1 , " " , size = ( 25 , 25 ))
sizer2 = wx.BoxSizer(wx.HORIZONTAL)
sizer2.Add(rb, 0, wx.RIGHT | wx.LEFT | wx.ALIGN_CENTER , 10 )
sizer2.Add(ckb, 0, wx.RIGHT | wx.LEFT | wx.ALIGN_CENTER , 10 )
sizer2.Add(fordtx, 0, wx.RIGHT | wx.LEFT | wx.ALIGN_CENTER , 10 )
sizer2.Add(openfdbtn, 0, wx.RIGHT | wx.LEFT | wx.ALIGN_CENTER , 10 )
# 第三行控件
rzlist = ResultList(panel, - 1 , size = ( 470 , 250 ))
# 第四行控件
countbtn = wx.Button(panel, - 1 , " 统计 " )
savebtn = wx.Button(panel, - 1 , " 保存 " )
aboutbtn = wx.Button(panel, - 1 , " 关于 " )
sizer4 = wx.BoxSizer(wx.HORIZONTAL)
sizer4.Add(countbtn, 0, wx.RIGHT | wx.LEFT, 40 )
sizer4.Add(savebtn, 0, wx.RIGHT | wx.LEFT, 40 )
sizer4.Add(aboutbtn, 0, wx.RIGHT | wx.LEFT, 40 )
# 排列这四行控件
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(sizer1, 0, wx.ALL, 8 )
sizer.Add(sizer2, 0, wx.ALL, 8 )
sizer.Add(rzlist, 0, wx.ALL, 8 )
sizer.Add(sizer4, 0, wx.ALL, 8 )
panel.SetSizer(sizer)
panel.Layout()
# 控件消息
self.Bind(wx.EVT_BUTTON, self.OnOpenForD, openfdbtn)
self.Bind(wx.EVT_BUTTON, self.OnCount, countbtn)
self.Bind(wx.EVT_BUTTON, self.OnSave, savebtn)
self.Bind(wx.EVT_BUTTON, self.OnAbout, aboutbtn)
self.Bind(wx.EVT_COMBOBOX, self.OnChoiceCodeType, cb1)
# 保存控件引用
self.codetype_cb = cb1
self.filetype_cb = cb2
self.fordname_tx = fordtx
self.ford_rb = rb
self.subdir_ckb = ckb
self.result_list = rzlist
# 存放结果
self.result = []
def OnOpenForD(self, evn):
''' 得到需要统计的文件或目录的路径 '''
if self.ford_rb.GetSelection() == 0:
dlg = wx.DirDialog(self, " 选择目录: " ,
style = wx.DD_DIR_MUST_EXIST
)
else :
dlg = wx.FileDialog(
self, message = " 选择文件 " ,
defaultDir = "" ,
defaultFile = "" ,
style = wx.OPEN | wx.CHANGE_DIR
)
if dlg.ShowModal() == wx.ID_OK:
self.fordname_tx.SetValue(dlg.GetPath())
dlg.Destroy()
def OnCount(self, evn):
''' 统计代码 '''
self.result_list.Clear()
self.result = []
try :
counter = CodeCounter(codefiles = [])
self.SetCounter(counter)
counter.Count(self.result)
except :
self.ErrMsg( " 输入错误 " )
all = [0,0,0,0,0]
for ele in self.result:
for i in range(len(ele[ 1 ])):
all[i] += ele[ 1 ][i]
self.result.append([ ' 总计 ' , all])
self.result_list.ShowResult(self.result)
def OnSave(self, evn):
''' 保存统计结果 '''
dlg = wx.FileDialog(
self, message = " Choose a file " ,
defaultDir = "" ,
defaultFile = "" ,
wildcard = " TXT files (*.txt)|*.txt|All files (*.*)|*.* " ,
style = wx.SAVE
)
if dlg.ShowModal() == wx.ID_OK:
f = open(dlg.GetPath(), ' wt ' )
for res in self.result:
f.write(( " %d\t%d\t%d\t%d\t%s\n " % (res[ 1 ][ 4 ],res[ 1 ][ 1 ] + res[ 1 ][ 3 ],
res[ 1 ][ 2 ] + res[ 1 ][ 3 ], res[ 1 ][0], res[0])))
dlg.Destroy()
def OnChoiceCodeType(self, evn):
idx = self.codetype_cb.GetSelection()
self.filetype_cb.SetSelection(idx)
def OnAbout(self, evn):
dlg = wx.MessageDialog(self, __doc__ ,
' About ' ,
wx.OK | wx.ICON_INFORMATION
)
dlg.ShowModal()
dlg.Destroy()
def ErrMsg(self,msg):
dlg = wx.MessageDialog(self, msg,
' Err ' ,
wx.OK | wx.ICON_INFORMATION
)
dlg.ShowModal()
dlg.Destroy()
def SetCounter(self, counter):
''' 从界面读入配置设置统计工具 '''
if self.subdir_ckb.IsChecked(): # 是否包含子目录
counter.SetLevel( - 1 )
if self.fordname_tx.GetValue() != '' :
# 判断是选择文件还是目录
t = ' f '
if self.ford_rb.GetSelection() == 0:
t = ' d '
counter.AddCodeFiles(t, self.fordname_tx.GetValue())
# 设置要统计的代码类型
val = self.codetype_cb.GetValue()
if val == ' C ' :
counter.SetCodeType( ' c ' )
elif val == ' Python ' :
counter.SetCodeType( ' py ' )
# 设置后缀名
counter.SetModes(self.filetype_cb.GetValue())
class CounterApp(wx.App):
def OnInit(self):
frame = CounterFrame(None, " 代码计算器 " )
self.SetTopWindow(frame)
frame.Show(True)
return True
if __name__ == ' __main__ ' :
app = CounterApp(redirect = False)
app.MainLoop()
'''
这是一个用Python写的简易代码统计工具。
作者:lemene
网址:http://www.cppblog/lemene
'''
import wx
import os
from counter import CodeCounter
# 代码类型和对应的文件后缀名
codetyps = [[ ' C ' , ' Python ' ],
[ ' .c,.cpp,.h ' , ' .py ' ]]
class ResultList(wx.ListCtrl):
''' 显示结果的控件 '''
def __init__ (self, parent, ID =- 1 , pos = wx.DefaultPosition,
size = wx.DefaultSize, style = wx.LC_REPORT):
wx.ListCtrl. __init__ (self, parent, ID, pos, size, style)
self.InsertColumn(0, " 文件名 " )
self.InsertColumn( 1 , " 总行数 " )
self.InsertColumn( 2 , " 代码 " )
self.InsertColumn( 3 , " 注释 " )
self.InsertColumn( 4 , " 空行 " )
def Clear(self):
''' 清空结果 '''
self.DeleteAllItems()
def ShowResult(self, results):
''' 显示结果 '''
i = 0
for res in results:
self.InsertStringItem(i, res[0])
self.SetStringItem(i, 1 , str(res[ 1 ][ 4 ]))
self.SetStringItem(i, 2 , str(res[ 1 ][ 1 ] + res[ 1 ][ 3 ]))
self.SetStringItem(i, 3 , str(res[ 1 ][ 2 ] + res[ 1 ][ 3 ]))
self.SetStringItem(i, 4 , str(res[ 1 ][0]) )
class CounterFrame(wx.Frame):
''' 程序界面 '''
def __init__ (self, parent, title):
wx.Frame. __init__ (self, parent, - 1 , title, size = ( 495 , 435 ),
style = wx.DEFAULT_FRAME_STYLE ^ wx.RESIZE_BORDER)
# 添加界面控件
panel = wx.Panel(self)
# 第一行控件
text1 = wx.StaticText(panel, - 1 , " 代码类型: " ,style = wx.ALIGN_RIGHT)
cb1 = wx.ComboBox(panel, - 1 , codetyps[0][0],choices = codetyps[0],style = wx.CB_READONLY, size = ( 100 , - 1 ))
text2 = wx.StaticText(panel, - 1 , " 后缀名: " )
cb2 = wx.ComboBox(panel, - 1 , codetyps[ 1 ][0],choices = codetyps[ 1 ],size = ( 190 , - 1 ))
sizer1 = wx.BoxSizer(wx.HORIZONTAL)
sizer1.Add(text1, 0, wx.RIGHT | wx.LEFT, 10 )
sizer1.Add(cb1, 0, wx.RIGHT | wx.LEFT, 10 )
sizer1.Add(text2, 0, wx.RIGHT | wx.LEFT, 10 )
sizer1.Add(cb2, 0, wx.RIGHT | wx.LEFT, 10 )
# 第二行控件
rb = wx.RadioBox(panel, - 1 , "" , wx.DefaultPosition, wx.DefaultSize,
[ ' 目录 ' , ' 文件 ' ])
ckb = wx.CheckBox(panel, - 1 , " 包括子目录 " )
fordtx = wx.TextCtrl(panel, - 1 , "" , size = ( 190 , - 1 ))
openfdbtn = wx.Button(panel, - 1 , " " , size = ( 25 , 25 ))
sizer2 = wx.BoxSizer(wx.HORIZONTAL)
sizer2.Add(rb, 0, wx.RIGHT | wx.LEFT | wx.ALIGN_CENTER , 10 )
sizer2.Add(ckb, 0, wx.RIGHT | wx.LEFT | wx.ALIGN_CENTER , 10 )
sizer2.Add(fordtx, 0, wx.RIGHT | wx.LEFT | wx.ALIGN_CENTER , 10 )
sizer2.Add(openfdbtn, 0, wx.RIGHT | wx.LEFT | wx.ALIGN_CENTER , 10 )
# 第三行控件
rzlist = ResultList(panel, - 1 , size = ( 470 , 250 ))
# 第四行控件
countbtn = wx.Button(panel, - 1 , " 统计 " )
savebtn = wx.Button(panel, - 1 , " 保存 " )
aboutbtn = wx.Button(panel, - 1 , " 关于 " )
sizer4 = wx.BoxSizer(wx.HORIZONTAL)
sizer4.Add(countbtn, 0, wx.RIGHT | wx.LEFT, 40 )
sizer4.Add(savebtn, 0, wx.RIGHT | wx.LEFT, 40 )
sizer4.Add(aboutbtn, 0, wx.RIGHT | wx.LEFT, 40 )
# 排列这四行控件
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(sizer1, 0, wx.ALL, 8 )
sizer.Add(sizer2, 0, wx.ALL, 8 )
sizer.Add(rzlist, 0, wx.ALL, 8 )
sizer.Add(sizer4, 0, wx.ALL, 8 )
panel.SetSizer(sizer)
panel.Layout()
# 控件消息
self.Bind(wx.EVT_BUTTON, self.OnOpenForD, openfdbtn)
self.Bind(wx.EVT_BUTTON, self.OnCount, countbtn)
self.Bind(wx.EVT_BUTTON, self.OnSave, savebtn)
self.Bind(wx.EVT_BUTTON, self.OnAbout, aboutbtn)
self.Bind(wx.EVT_COMBOBOX, self.OnChoiceCodeType, cb1)
# 保存控件引用
self.codetype_cb = cb1
self.filetype_cb = cb2
self.fordname_tx = fordtx
self.ford_rb = rb
self.subdir_ckb = ckb
self.result_list = rzlist
# 存放结果
self.result = []
def OnOpenForD(self, evn):
''' 得到需要统计的文件或目录的路径 '''
if self.ford_rb.GetSelection() == 0:
dlg = wx.DirDialog(self, " 选择目录: " ,
style = wx.DD_DIR_MUST_EXIST
)
else :
dlg = wx.FileDialog(
self, message = " 选择文件 " ,
defaultDir = "" ,
defaultFile = "" ,
style = wx.OPEN | wx.CHANGE_DIR
)
if dlg.ShowModal() == wx.ID_OK:
self.fordname_tx.SetValue(dlg.GetPath())
dlg.Destroy()
def OnCount(self, evn):
''' 统计代码 '''
self.result_list.Clear()
self.result = []
try :
counter = CodeCounter(codefiles = [])
self.SetCounter(counter)
counter.Count(self.result)
except :
self.ErrMsg( " 输入错误 " )
all = [0,0,0,0,0]
for ele in self.result:
for i in range(len(ele[ 1 ])):
all[i] += ele[ 1 ][i]
self.result.append([ ' 总计 ' , all])
self.result_list.ShowResult(self.result)
def OnSave(self, evn):
''' 保存统计结果 '''
dlg = wx.FileDialog(
self, message = " Choose a file " ,
defaultDir = "" ,
defaultFile = "" ,
wildcard = " TXT files (*.txt)|*.txt|All files (*.*)|*.* " ,
style = wx.SAVE
)
if dlg.ShowModal() == wx.ID_OK:
f = open(dlg.GetPath(), ' wt ' )
for res in self.result:
f.write(( " %d\t%d\t%d\t%d\t%s\n " % (res[ 1 ][ 4 ],res[ 1 ][ 1 ] + res[ 1 ][ 3 ],
res[ 1 ][ 2 ] + res[ 1 ][ 3 ], res[ 1 ][0], res[0])))
dlg.Destroy()
def OnChoiceCodeType(self, evn):
idx = self.codetype_cb.GetSelection()
self.filetype_cb.SetSelection(idx)
def OnAbout(self, evn):
dlg = wx.MessageDialog(self, __doc__ ,
' About ' ,
wx.OK | wx.ICON_INFORMATION
)
dlg.ShowModal()
dlg.Destroy()
def ErrMsg(self,msg):
dlg = wx.MessageDialog(self, msg,
' Err ' ,
wx.OK | wx.ICON_INFORMATION
)
dlg.ShowModal()
dlg.Destroy()
def SetCounter(self, counter):
''' 从界面读入配置设置统计工具 '''
if self.subdir_ckb.IsChecked(): # 是否包含子目录
counter.SetLevel( - 1 )
if self.fordname_tx.GetValue() != '' :
# 判断是选择文件还是目录
t = ' f '
if self.ford_rb.GetSelection() == 0:
t = ' d '
counter.AddCodeFiles(t, self.fordname_tx.GetValue())
# 设置要统计的代码类型
val = self.codetype_cb.GetValue()
if val == ' C ' :
counter.SetCodeType( ' c ' )
elif val == ' Python ' :
counter.SetCodeType( ' py ' )
# 设置后缀名
counter.SetModes(self.filetype_cb.GetValue())
class CounterApp(wx.App):
def OnInit(self):
frame = CounterFrame(None, " 代码计算器 " )
self.SetTopWindow(frame)
frame.Show(True)
return True
if __name__ == ' __main__ ' :
app = CounterApp(redirect = False)
app.MainLoop()