一、tkinter基础语法
tkinter是一个Python中的GUI库,用于创建用户界面。以下是部分常用的tkinter语法:
-
导入模块:
import tkinter
-
创建主窗口:
root = tkinter.Tk()
-
设置主窗口标题:
root.title("窗口标题")
-
设置主窗口大小:
root.geometry("宽x高")
-
添加标签:
tkinter.Label(父容器, text="标签文本")
-
添加按钮:
tkinter.Button(父容器, text="按钮文本", command=按钮响应函数)
-
绑定事件:
组件.bind(事件类型, 响应函数)
-
显示窗口及运行事件循环:
root.mainloop()
注:其中父容器可以是主窗口或其他容器组件。响应函数可以是定义好的函数名,也可以是lambda函数。
以上只是一部分常用的tkinter语法,更多内容还需参考官方文档或教程。
二、入门教程
写一个类,其可以输入一个名称,然后点击搜索,下方有一些文件提示框用于展示文件列表,在最低位置,有一个一键处理按钮
以下是一个可以实现上述功能的类的简单实现:
import tkinter as tk
import os
class FileSearcher:
def __init__(self, master):
self.master = master
# 在窗口顶部添加一个输入框和一个搜索按钮
self.search_entry = tk.Entry(master, width=40)
self.search_button = tk.Button(master, text='搜索', command=self.search_files)
# 在窗口中间添加一个滚动条,用于文件列表展示
self.file_scrollbar = tk.Scrollbar(master)
self.file_scrollbar.pack(side='right', fill='y')
self.file_listbox = tk.Listbox(master, width=60, yscrollcommand=self.file_scrollbar.set)
self.file_scrollbar.config(command=self.file_listbox.yview)
# 在窗口底部添加一个处理按钮
self.process_button = tk.Button(master, text='一键处理', command=self.process_files)
# 设置窗口布局
self.search_entry.pack(side='left')
self.search_button.pack(side='left')
self.file_listbox.pack(side='top', padx=10, pady=10)
self.process_button.pack(side='bottom', pady=10)
def search_files(self):
# 获取搜索关键字
search_text = self.search_entry.get()
# 清空文件列表
self.file_listbox.delete(0, 'end')
# 搜索指定目录下的文件,并将文件名添加到列表框中
for filename in os.listdir('.'):
if search_text in filename:
self.file_listbox.insert('end', filename)
def process_files(self):
# 在这里写一键处理文件的代码
pass
然后可以在程序中实例化这个类,把窗口作为参数传入:
if __name__ == '__main__':
root = tk.Tk()
app = FileSearcher(root)
root.mainloop()
这样就可以运行程序,看到一个带有搜索框、文件列表框和一键处理按钮的界面了。
三、持续优化
为了美化界面,我们可以使用 ttk 模块中的一些部件,它们提供了更好看的外观和更好的交互效果。
以下是一个美化后的 FileSearcher
类:
import tkinter as tk
from tkinter import ttk
import os
class FileSearcher:
def __init__(self, master):
self.master = master
# 在窗口顶部添加一个输入框和一个搜索按钮
self.search_frame = ttk.Frame(master)
self.search_frame.pack(fill='x', padx=10, pady=(10, 0))
self.search_entry = ttk.Entry(self.search_frame, width=40)
self.search_button = ttk.Button(self.search_frame, text='搜索', command=self.search_files)
self.search_entry.pack(side='left', padx=(0, 10))
self.search_button.pack(side='left')
# 在窗口中间添加一个滚动条,用于文件列表展示
self.file_frame = ttk.Frame(master)
self.file_frame.pack(fill='both', padx=10, pady=10, expand=True)
self.file_scrollbar = ttk.Scrollbar(self.file_frame)
self.file_scrollbar.pack(side='right', fill='y')
self.file_listbox = tk.Listbox(self.file_frame, width=60, yscrollcommand=self.file_scrollbar.set)
self.file_listbox.pack(side='left', fill='both', expand=True)
self.file_scrollbar.config(command=self.file_listbox.yview)
# 在窗口底部添加一个处理按钮
self.process_button = ttk.Button(master, text='一键处理', command=self.process_files)
self.process_button.pack(side='bottom', pady=10)
def search_files(self):
# 获取搜索关键字
search_text = self.search_entry.get()
# 清空文件列表
self.file_listbox.delete(0, 'end')
# 搜索指定目录下的文件,并将文件名添加到列表框中
for filename in os.listdir('.'):
if search_text in filename:
self.file_listbox.insert('end', filename)
def process_files(self):
# 在这里写一键处理文件的代码
pass
我们使用了 ttk 模块中的 Frame
、Entry
、Button
和 Scrollbar
部件来代替了原来的部件,从而实现了美化的效果。
运行程序后,界面应该更漂亮了。
四、功能补充与完善
4.1 根据执行结果显示的状态栏,可以显示完成 / 搜索失败
为了添加一个状态栏,我们可以使用 ttk.Label
部件。该部件可以用于在窗口中添加文本标签,我们可以使用它来展示处理的状态。
以下是一个添加了状态栏的 FileSearcher
类:
import tkinter as tk
from tkinter import ttk
import os
class FileSearcher:
def __init__(self, master):
self.master = master
# 在窗口顶部添加一个输入框和一个搜索按钮
self.search_frame = ttk.Frame(master)
self.search_frame.pack(fill='x', padx=10, pady=(10, 0))
self.search_entry = ttk.Entry(self.search_frame, width=40)
self.search_button = ttk.Button(self.search_frame, text='搜索', command=self.search_files)
self.search_entry.pack(side='left', padx=(0, 10))
self.search_button.pack(side='left')
# 在窗口中间添加一个滚动条,用于文件列表展示
self.file_frame = ttk.Frame(master)
self.file_frame.pack(fill='both', padx=10, pady=10, expand=True)
self.file_scrollbar = ttk.Scrollbar(self.file_frame)
self.file_scrollbar.pack(side='right', fill='y')
self.file_listbox = tk.Listbox(self.file_frame, width=60, yscrollcommand=self.file_scrollbar.set)
self.file_listbox.pack(side='left', fill='both', expand=True)
self.file_scrollbar.config(command=self.file_listbox.yview)
# 在窗口底部添加一个处理按钮和一个状态栏
self.status_label = ttk.Label(master, text='未开始搜索')
self.status_label.pack(side='bottom', pady=(0, 10))
self.process_button = ttk.Button(master, text='一键处理', command=self.process_files)
self.process_button.pack(side='bottom', pady=10)
def search_files(self):
# 获取搜索关键字
search_text = self.search_entry.get()
# 清空文件列表
self.file_listbox.delete(0, 'end')
# 搜索指定目录下的文件,并将文件名添加到列表框中
for filename in os.listdir('.'):
if search_text in filename:
self.file_listbox.insert('end', filename)
# 更新状态栏的文本
if self.file_listbox.size() > 0:
self.status_label.config(text='搜索完成')
else:
self.status_label.config(text='搜索失败')
def process_files(self):
# 在这里写一键处理文件的代码
pass
我们添加了一个名为 status_label
的新标签部件,并在搜索和处理函数中更新了它的文本。在搜索完成时,我们设置 status_label
的文本为“搜索完成”,否则设置为“搜索失败”。
运行程序后,应该能看到新的状态栏。
4.2 tkinter中的文件列表如何实现点击打开其文件
要在tkinter中实现文件列表的点击打开文件功能,可以为 Listbox
部件绑定双击事件,然后在事件处理程序中打开所选文件。
以下是一个示例程序,展示如何实现点击文件列表中的文件打开该文件:
import tkinter as tk
from tkinter import ttk
import os
class FileOpener:
def __init__(self, master):
self.master = master
# 在窗口中间添加一个滚动条和文件列表框
self.file_frame = ttk.Frame(master)
self.file_frame.pack(fill='both', padx=10, pady=10, expand=True)
self.file_scrollbar = ttk.Scrollbar(self.file_frame)
self.file_scrollbar.pack(side='right', fill='y')
self.file_listbox = tk.Listbox(self.file_frame, width=60, yscrollcommand=self.file_scrollbar.set)
self.file_listbox.pack(side='left', fill='both', expand=True)
self.file_scrollbar.config(command=self.file_listbox.yview)
# 为文件列表框绑定双击事件
self.file_listbox.bind('<Double-Button-1>', self.open_file)
# 填充文件列表框
self.fill_file_list()
def fill_file_list(self):
# 获取当前目录下的所有文件名
files = os.listdir('.')
# 将文件名添加到文件列表框中
for filename in files:
self.file_listbox.insert('end', filename)
def open_file(self, event):
# 获取双击的文件名
selected_file = self.file_listbox.get(self.file_listbox.curselection())
# 打开文件
os.startfile(selected_file)
我们创建了一个名为 FileOpener
的类,其中包含一个 Listbox
部件用于展示文件列表,并在该部件上绑定了双击事件。当用户双击文件列表中的文件时,open_file
方法将被调用,并打开所选文件。
在 open_file
方法中,我们使用 os.startfile()
函数打开了所选文件。这里使用 os.startfile()
是因为它是一个跨平台的函数,在 Windows、Linux 和 macOS 上都能正常工作。
要使用示例程序,只需创建一个 Tk
对象,然后创建 FileOpener
对象即可。运行程序后,您应该能够在窗口中看到当前目录下的所有文件,并且可以双击其中一个文件来打开它。
4.2.2 需要增加识别其是否已打开此文件,已打开的不需要重复打开
要在tkinter中实现打开文件时检查文件是否已打开,可以借助 platform 模块获取当前运行的操作系统。在Windows系统上,可以使用 ctypes 模块来枚举所有正在运行的句柄,并检查文件是否已在其中打开,而在Linux和macOS上则需要使用其他方法。
以下是一个示例程序,展示如何在Windows系统上使用 ctypes 模块来检查文件是否已打开:
import tkinter as tk
from tkinter import ttk
import os
import platform
import ctypes
import ctypes.wintypes
class FileOpener:
def __init__(self, master):
self.master = master
# 在窗口中间添加一个滚动条和文件列表框
self.file_frame = ttk.Frame(master)
self.file_frame.pack(fill='both', padx=10, pady=10, expand=True)
self.file_scrollbar = ttk.Scrollbar(self.file_frame)
self.file_scrollbar.pack(side='right', fill='y')
self.file_listbox = tk.Listbox(self.file_frame, width=60, yscrollcommand=self.file_scrollbar.set)
self.file_listbox.pack(side='left', fill='both', expand=True)
# 为文件列表框绑定双击事件
self.file_listbox.bind('<Double-Button-1>', self.open_file)
# 填充文件列表框
self.fill_file_list()
def fill_file_list(self):
# 获取当前目录下的所有文件名
files = os.listdir('.')
# 将文件名添加到文件列表框中
for filename in files:
self.file_listbox.insert('end', filename)
def open_file(self, event):
# 获取双击的文件名
selected_file = self.file_listbox.get(self.file_listbox.curselection())
# 检查文件是否已打开
if self.is_file_open(selected_file):
print('文件已打开')
else:
# 打开文件
os.startfile(selected_file)
def is_file_open(self, filename):
if platform.system() == 'Windows':
# Windows系统使用ctypes来枚举所有打开的句柄
kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)
kernel32.CreateToolhelp32Snapshot.argtypes = [ctypes.wintypes.DWORD, ctypes.wintypes.DWORD]
kernel32.CreateToolhelp32Snapshot.restype = ctypes.wintypes.HANDLE
kernel32.Process32FirstW.argtypes = [ctypes.wintypes.HANDLE, ctypes.POINTER(ctypes.wintypes.PROCESSENTRY32W)]
kernel32.Process32FirstW.restype = ctypes.wintypes.BOOL
kernel32.Process32NextW.argtypes = [ctypes.wintypes.HANDLE, ctypes.POINTER(ctypes.wintypes.PROCESSENTRY32W)]
kernel32.Process32NextW.restype = ctypes.wintypes.BOOL
kernel32.CloseHandle.argtypes = [ctypes.wintypes.HANDLE]
kernel32.CloseHandle.restype = ctypes.wintypes.BOOL
handle = kernel32.CreateToolhelp32Snapshot(ctypes.c_ulong(0x2), ctypes.c_ulong(0))
if handle == ctypes.c_ulong(-1).value:
error = kernel32.GetLastError()
raise Exception(f'CreateToolhelp32Snapshot failed: {error}')
try:
pe = ctypes.wintypes.PROCESSENTRY32W()
pe.dwSize = ctypes.sizeof(pe)
if kernel32.Process32FirstW(handle, ctypes.byref(pe)):
while True:
if filename.lower() in pe.szExeFile.decode('utf-8').lower():
return True
if not kernel32.Process32NextW(handle, ctypes.byref(pe)):
break
else:
error = kernel32.GetLastError()
if error != 0x18: # ERROR_NO_MORE_FILES
raise Exception(f'Process32First failed: {error}')
finally:
kernel32.CloseHandle(handle)
return False
我们在 FileOpener
类中添加了一个名为 is_file_open
的方法,该方法使用 ctypes
模块在Windows系统上枚举所有打开的句柄,并检查文件是否在其中打开。如果文件已经打开,则返回True,否则返回False。
在 open_file
方法中,我们在打开文件之前首先调用 is_file_open
方法来检查文件是否已打开。如果文件已打开,我们输出一条消息表示文件已经打开,否则我们使用 os.startfile
打开文件。
请注意,此方法只适用于Windows系统,并且需要管理员权限才能枚举所有打开的句柄。在Linux和macOS上,可以使用其他方法来检查文件是否已打开。
4.3 一键关闭功能及退出时自动关闭所有文档功能
如果您想在单击Qt
窗口的关闭按钮时关闭所有已打开的文档,可以通过以下方式实现:
1.创建一个应用程序类,继承QApplication
, 在__init__
方法中创建一个列表self.processes
,用于跟踪所有打开的进程。并且在exec_()
方法中设置关闭事件处理程序self.closeEvent
。
class MyApp(QApplication):
def __init__(self, argv):
super().__init__(argv)
self.processes = []
def closeEvent(self, event):
for process in self.processes:
process.kill()
2.创建一个主窗口类,继承QMainWindow
。在__init__
方法中创建一个列表self.file_list
,用于显示所有可用的 PDF 文件,并在该列表中添加itemDoubleClicked
信号的处理程序self.open_pdf
。
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.file_list = QListWidget(self)
self.setCentralWidget(self.file_list)
self.file_list.itemDoubleClicked.connect(self.open_pdf)
3.在self.open_pdf
方法中,使用subprocess.Popen
打开所选文件,并将返回的进程对象添加到self.processes
列表中。
def open_pdf(self, item):
file = item.text()
process = subprocess.Popen(["open", "path/to/pdf/files/" + file])
self.app.processes.append(process)
4.在 main
方法中创建QApplication
对象和MainWindow
对象,并设置应用程序图标、窗口标题和窗口大小。最后显示主窗口。
if __name__ == '__main__':
app = MyApp(sys.argv)
main_window = MainWindow()
main_window.setWindowIcon(QIcon('path/to/icon.png'))
main_window.setWindowTitle('My PDF Viewer')
main_window.setGeometry(100, 100, 800, 600)
main_window.show()
sys.exit(app.exec_())
当用户单击主窗口的关闭按钮时,closeEvent
方法会迭代self.processes
列表并关闭所有打开的进程。这将在后台关闭所有 PDF 文件,同时关闭主窗口。
ok! 今天内容tkinter的实例展示就运行完毕!