Skip to content

Commit 1339b2d

Browse files
committed
add source code
1 parent a1339e6 commit 1339b2d

File tree

7 files changed

+350
-2
lines changed

7 files changed

+350
-2
lines changed

.gitignore

-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ MANIFEST
3131
# Usually these files are written by a python script from a template
3232
# before PyInstaller builds the exe, so as to inject date/other infos into it.
3333
*.manifest
34-
*.spec
3534

3635
# Installer logs
3736
pip-log.txt

README.md

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,7 @@
11
# filesearcher
2-
文件搜索工具
2+
3+
一个简单的文件搜索工具
4+
5+
预览图
6+
7+
![WX20201129-234840@2x](screenshots/WX20201129-234840@2x.png)

build.sh

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# _*_ coding:utf-8 _*_
2+
3+
pyinstaller\
4+
--clean\
5+
--noconfirm\
6+
-w\
7+
build.spec
8+
9+
# or shell
10+
# pyinstaller -F -w --clean -y src/app.py
11+
12+
# sign app
13+
# chmod +x dist/文件搜索工具.app/Contents/MacOS/文件搜索工具
14+
# sudo codesign --force --deep --sign - ./dist/文件搜索工具.app
15+

build.spec

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# -*- mode: python ; coding: utf-8 -*-
2+
3+
BLOCK_CIPHER = None
4+
APP_NAME = '文件搜索工具'
5+
APP_EXE = 'FileSearcher'
6+
APP_APP = '文件搜索工具.app'
7+
APP_VERSION = '0.0.1'
8+
SCRIPTS = ['src/app.py']
9+
BINARIES = []
10+
DATAS = []
11+
HIDDEN_IMPORTS = [] # 源文件的依赖模块
12+
HOOKSPATH = []
13+
EXCLUDES = [] # 不需要打包的模块
14+
RUNTIME_HOOKS = []
15+
BUNDLE_IDENTIFIER = 'org.pythub.app.filesearcher' # 一般情况下Bundle ID的格式为:com.公司名称.项目名称
16+
UPX = True # 如果有UPX安装(执行Configure.py时检测),会压缩执行文件(Windows系统中的DLL也会)
17+
PATHEX = ['.']
18+
COPYRIGHT = 'Copyright © 2020, Pythub Project, All Rights Reserved'
19+
20+
a = Analysis(SCRIPTS,
21+
pathex=PATHEX,
22+
binaries=BINARIES,
23+
datas=DATAS,
24+
hiddenimports=HIDDEN_IMPORTS,
25+
hookspath=HOOKSPATH,
26+
runtime_hooks=RUNTIME_HOOKS,
27+
excludes=EXCLUDES,
28+
win_no_prefer_redirects=False,
29+
win_private_assemblies=False,
30+
cipher=BLOCK_CIPHER,
31+
noarchive=False)
32+
pyz = PYZ(a.pure, a.zipped_data, cipher=BLOCK_CIPHER)
33+
exe = EXE(pyz,
34+
a.scripts, [],
35+
exclude_binaries=True,
36+
name=APP_NAME,
37+
debug=False,
38+
bootloader_ignore_signals=False,
39+
strip=False,
40+
upx=UPX,
41+
console=False)
42+
coll = COLLECT(exe,
43+
a.binaries,
44+
a.zipfiles,
45+
a.datas,
46+
strip=False,
47+
upx=UPX,
48+
upx_exclude=[],
49+
name=APP_NAME)
50+
app = BUNDLE(coll,
51+
name=APP_APP,
52+
icon=None,
53+
bundle_identifier=BUNDLE_IDENTIFIER)
54+
55+
app = BUNDLE(
56+
coll,
57+
name=APP_APP,
58+
icon=None,
59+
bundle_identifier=BUNDLE_IDENTIFIER,
60+
info_plist={
61+
'CFBundleName': APP_NAME,
62+
'CFBundleDisplayName': 'APP_NAME',
63+
'CFBundleExecutable': APP_NAME,
64+
'CFBundlePackageType': 'APPL',
65+
'CFBundleSupportedPlatforms': 'MacOSX',
66+
'CFBundleGetInfoString': "Pythub Project",
67+
'CFBundleIdentifier': BUNDLE_IDENTIFIER,
68+
'CFBundleVersion': APP_VERSION,
69+
'CFBundleInfoDictionaryVersion': APP_VERSION,
70+
'CFBundleShortVersionString': APP_VERSION,
71+
'NSHighResolutionCapable': True,
72+
'NSHumanReadableCopyright': COPYRIGHT
73+
}
74+
)

screenshots/WX20201129-234840@2x.png

250 KB
Loading

src/app.py

+219
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
# -*- coding:utf-8 -*-
2+
'''
3+
文件搜索工具
4+
'''
5+
6+
__author__ = 'Pythub Team'
7+
__version__ = '0.0.1'
8+
__license__ = 'BSD'
9+
10+
import os
11+
import re
12+
from os.path import isdir, join
13+
from tkinter import (Tk, Button, BooleanVar, Checkbutton, Entry, Frame, Label,
14+
Listbox, Scrollbar, StringVar, Toplevel, messagebox)
15+
from tkinter.filedialog import askdirectory
16+
17+
from utils import set_window_center
18+
19+
20+
class App:
21+
def __init__(self, master):
22+
self.master = master
23+
self.fname = StringVar(value='') # 搜索文件名
24+
self.ftype = StringVar(value='') # 搜索文件类型
25+
self.fpath = StringVar(value=os.environ['HOME']) # 搜索路径
26+
self.advance = BooleanVar(value=False) # 遍历子目录
27+
28+
self.view()
29+
30+
def about(self):
31+
'''关于'''
32+
txt = '作者:%s\n版本:%s' % (__author__, __version__)
33+
self.showinfo(title='关于', message=txt)
34+
35+
def close(self):
36+
'''关闭应用'''
37+
self.master.quit()
38+
exit()
39+
40+
def showinfo(self, title, message):
41+
'''显示提示'''
42+
messagebox.showinfo(parent=self.master, title=title, message=message)
43+
44+
def showerror(self, title, message):
45+
'''显示报错'''
46+
messagebox.showerror(parent=self.master, title=title, message=message)
47+
48+
def view(self):
49+
'''加载视图'''
50+
51+
# 区域:文件名
52+
row_1 = Frame(self.master)
53+
row_1.pack(side='top', fill='x', expand=True)
54+
Label(row_1, text='文件名:', width=13, justify='left').pack(side='left')
55+
# 文件名输入框
56+
self.entry_fname = Entry(row_1,
57+
textvariable=self.fname,
58+
borderwidth=1,
59+
highlightcolor='#ddd',
60+
width=60)
61+
self.entry_fname.pack(side='right', fill='x', expand=True)
62+
63+
# 区域:文件类型
64+
row_2 = Frame(self.master)
65+
row_2.pack(side='top', fill='x', expand=True)
66+
Label(row_2, text='文件后缀:', width=13, justify='left').pack(side='left')
67+
# 文件类型输入框
68+
self.entry_ftype = Entry(row_2,
69+
textvariable=self.ftype,
70+
borderwidth=1,
71+
highlightcolor='#ddd')
72+
self.entry_ftype.pack(side='left', fill='x', expand=True)
73+
74+
# 区域:搜索路径
75+
row_3 = Frame(self.master)
76+
row_3.pack(side='top', fill='x', expand=True)
77+
Label(row_3, text='搜索位置:', width=13, justify='left').pack(side='left')
78+
# 路径输入框
79+
self.entry_fpath = Entry(row_3,
80+
textvariable=self.fpath,
81+
borderwidth=1,
82+
highlightcolor='#ddd')
83+
self.entry_fpath.pack(side='left', fill='x', expand=True)
84+
85+
# 按钮:选择路径按钮
86+
# bbb = Label(row_3, text='...', justify='left')
87+
# bbb.bind('<Button-1>', self.select_path) # 绑定双击事件
88+
# bbb.pack(side='left')
89+
button_path = Button(row_3, text='选择', command=self.select_path)
90+
button_path.pack(side='right')
91+
92+
# 区域:选项配置
93+
row_4 = Frame(self.master)
94+
row_4.pack(side='top', fill='x', expand=True)
95+
Label(row_4, text='选项', width=13, justify='left').pack(side='left')
96+
# 是否查找子目录
97+
Checkbutton(row_4, text='高级功能',
98+
variable=self.advance).pack(side='left')
99+
100+
# 区域:操作按钮
101+
row_5 = Frame(self.master)
102+
row_5.pack(side='top', fill='x', expand=True)
103+
# 按钮
104+
Label(row_5, text='操作', width=13, justify='left').pack(side='left')
105+
button = Button(row_5, text='搜索', command=self.do_search)
106+
button.pack(side='left')
107+
button = Button(row_5, text='清理结果', command=self.do_clean)
108+
button.pack(side='left')
109+
button = Button(row_5, text='重置', command=self.do_reset)
110+
button.pack(side='left')
111+
button = Button(row_5, text='关于', command=self.about)
112+
button.pack(side='left')
113+
button = Button(row_5, text='关闭', command=self.close)
114+
button.pack(side='left')
115+
116+
# 区域:搜索结果
117+
row_6 = Frame(
118+
self.master,
119+
# relief='raised', borderwidth=1,highlightbackground='#ddd'
120+
)
121+
row_6.pack(side='bottom', fill='both', expand=True)
122+
# 滚动条
123+
# scroll_x = Scrollbar(row_6)
124+
# scroll_x.pack(side='bottom', fill='x', expand=True)
125+
scroll_y = Scrollbar(row_6)
126+
scroll_y.pack(side='right', fill='y')
127+
# 列表
128+
self.result = Listbox(
129+
row_6,
130+
width=40,
131+
height=200,
132+
relief='ridge',
133+
borderwidth=1,
134+
highlightcolor='#ddd',
135+
# foreground='#ddd',
136+
)
137+
self.result.pack(side='left', fill='both', expand=True)
138+
# 列表与滚动绑定
139+
# self.result['xscrollcommand'] = scroll_x.set
140+
# scroll_x.config(command=self.result.xview)
141+
self.result['yscrollcommand'] = scroll_y.set
142+
scroll_y.config(command=self.result.yview)
143+
# 双击打开
144+
self.result.bind('<Double-Button-1>', self.opendir)
145+
146+
def select_path(self):
147+
'''选择文件夹'''
148+
fpath = askdirectory(parent=self.master,
149+
message='选择搜索位置',
150+
title='选择搜索位置')
151+
if isdir(fpath):
152+
self.fpath.set(fpath)
153+
154+
def do_search(self):
155+
'''搜索'''
156+
fname = self.fname.get()
157+
ftype = self.ftype.get()
158+
fpath = self.fpath.get()
159+
advance = self.advance.get()
160+
161+
if advance:
162+
self.showinfo(title='错误提示', message='高级功能还没想好。。')
163+
elif not ftype:
164+
self.showinfo(title='错误提示', message='文件后缀不能为空')
165+
elif not fpath:
166+
self.showinfo(title='错误提示', message='搜索路径不能为空')
167+
else:
168+
ftype = '.' + ftype
169+
self.result.delete(0, 'end')
170+
fileList = os.walk(fpath) # 所有文件目录
171+
resList = []
172+
for path, _, file in fileList:
173+
# path:路径,_:文件夹,file:文件
174+
for filename in file:
175+
# re.I不区分大小写
176+
rr = re.compile(r'.*?(%s).*(%s)$' % (fname, ftype), re.I)
177+
res = rr.search(filename)
178+
if res != None:
179+
resList.append(filename)
180+
self.result.insert('end', join(path, filename))
181+
if len(resList) == 0:
182+
self.showerror('错误提示', '没有找到相关的文件')
183+
return
184+
185+
def do_reset(self):
186+
'''重置'''
187+
self.fname.set('')
188+
self.ftype.set('')
189+
self.fpath.set(value=os.environ['HOME'])
190+
self.advance.set(False)
191+
self.result.delete(0, 'end')
192+
193+
def do_clean(self):
194+
'''清理结果'''
195+
self.result.delete(0, 'end')
196+
197+
def opendir(self, event):
198+
'''打开所在文件夹'''
199+
index = self.result.curselection() # 获取文件列表索引
200+
print('index', index)
201+
if index == ():
202+
self.showerror('错误提示', '没有找到相关的文件')
203+
else:
204+
p = self.result.get(index)
205+
d = os.path.dirname(p)
206+
# for Mac
207+
os.system('open ' + d)
208+
209+
210+
def run():
211+
master = Tk()
212+
master.title('文件搜索工具 %s' % __version__)
213+
set_window_center(master, 600, 500, resize=True)
214+
App(master)
215+
master.mainloop()
216+
217+
218+
if __name__ == '__main__':
219+
run()

src/utils.py

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# _*_ coding:utf-8 _*_
2+
# utils functions
3+
4+
5+
def set_window_center(window, width=None, height=None, minsize=True, resize=False):
6+
"""设置窗口宽高及居中"""
7+
# 获取窗口宽高
8+
if width == None or height == None:
9+
# 宽高为 None 时取窗口自身大小
10+
window.update_idletasks() # 更新
11+
window.withdraw() # 隐藏重绘
12+
# window.update() # 获取窗口宽高之前需要先刷新窗口
13+
if width is None:
14+
width = window.winfo_width()
15+
if height is None:
16+
height = window.winfo_height()
17+
18+
# 获取屏幕宽高
19+
w_s = window.winfo_screenwidth()
20+
h_s = window.winfo_screenheight()
21+
22+
# 计算 x, y 位置
23+
x_co = (w_s - width) / 2
24+
y_co = (h_s - height) / 2
25+
26+
# 设置窗口宽高和居中定位
27+
window.geometry("%dx%d+%d+%d" % (width, height, x_co, y_co))
28+
window.deiconify() # 显示
29+
# 是否设置窗口最小尺寸
30+
if minsize:
31+
window.minsize(width, height)
32+
# 是否可调整大小
33+
if resize:
34+
window.resizable(True, True)
35+
else:
36+
window.resizable(False, False)

0 commit comments

Comments
 (0)