Everything-文件查找软件制作

写在前边:随着电脑里边的东西越来越多,很多东西放的杂七杂八;今天实在忍不了了,一怒之下,突发奇想,做一个类似Everything的文件查找软件,现在共享出来。

一、软件展示

二、源码展示与讲解

1、所用到的组件

(1)

2、源码分块细嗦

(1)导入模块

import sys			# 通常用于操作系统相关的任务,例如命令行参数和系统退出
import os			# 用于与操作系统交互,例如文件和目录操作
import fnmatch		# 用于文件名匹配
import subprocess	# 用于执行外部命令
from PyQt5.QtWidgets import (QApplication, QMainWindow, QFileDialog, QVBoxLayout, QPushButton,
                             QLineEdit, QListWidget, QWidget, QLabel, QProgressBar, QHBoxLayout, QMenu, QDesktopWidget, QSplashScreen)
# QApplication应用程序的主类,所有的pyQt5应用程序都需要 一个QApplication实例来管理程序的控制流和主要设置           
# QMainWindow 主窗口类,提供了一个主窗口的基本框架,包括菜单栏,工具栏和状态栏
# QFileDialog 用于打开文件和目录选择对话框
# QVBoxLayout:垂直布局管理器,用于在窗口中垂直排列控件
# QPushButton:按钮控件,用于可以点击来触发某些动作
# QLineEdit:单行文本框,允许用户输入文本
# QListWidget:列表控件,用于显示一个可滚动的项目列表
# QWidget:所有界面控件的积累,提供基本的窗口功能
# QLabel:标签控件,用于显示文本和图像
# QProgressBar:进度条控件,现任任务进度
# QHBoxLayout:水平布局管理器,用于在窗口中水平排列控件。
# QMenu:菜单控件,用于创建和管理菜单
# QDesktopWidget:提供有关桌面屏幕的信息,例如屏幕大小和分辨率
# QSplashScreen:启动画面控件,用于在应用程序启东时显示一个临时的图片或动画
from PyQt5.QtCore import Qt, QThread, pyqtSignal, QTimer
# Qt:包含Qt框架的各种常量,例如键盘和鼠标事件的数值、对齐选项等。
# QThread:用于创建和管理线程,通常用于在后台执行耗时操作,避免阻塞主线程。
# pyqtSignal:用于定义和发射自定义信号
# QTimer:用于创建定时器,可以在指定事件时间后触发事件。
from PyQt5.QtGui import QPixmap, QIcon
# QPixmap:用于处理图像,通常用于设置控件的图像(如图标背景)
# QIcon:用于设置窗口、按钮等控件的图标。

(2)线程执行模块

 本模块,定义了一个worker类,继承自pyQT的QThread类。QThread是PyQt中用于创建主管理线程的类。该Worker线程在后台执行文件查找工作,并将进度和结果通过信号发射给主线程。以下是详细的解释。

class Worker(QThread):
	# 用于发射任务进度的百分比(整数)
    progress = pyqtSignal(int)
    # 用于发射任务完成时的结果列表(找到的文件和目录)
    finished = pyqtSignal(list)
    # 用于发射任务出现错误时的错误信息
    error = pyqtSignal(str)

    def __init__(self, directory, pattern):
        super().__init__()
        self.directory = directory
        self.pattern = pattern

    def run(self):
        results = []
        total_files = 0
        file_count = 0
		# 计算total_files 总数
        for root, dirs, files in os.walk(self.directory):
            total_files += len(dirs) + len(files)
		# 开始查找
        for root, dirs, files in os.walk(self.directory):
            for name in fnmatch.filter(dirs, self.pattern):
                results.append(os.path.join(root, name))
            for name in fnmatch.filter(files, self.pattern):
                results.append(os.path.join(root, name))
            file_count += len(dirs) + len(files)
            self.progress.emit(int((file_count / total_files) * 100))

        self.finished.emit(results)

 这个线程可以用于在后台执行文件来查找任务,而不会阻塞主线程(例如用户界面)。在主线程中,可以连接process信号来更新进度条,连接finished信号来处理任务完成后的结果。

(3)路径转换模块

def resource_path(relative_path):
    """ 获取资源文件的绝对路径 """
    try:
        # PyInstaller创建的临时文件夹路径
        base_path = sys._MEIPASS
    except AttributeError:
        # 如果不是打包的环境,使用当前文件夹
        base_path = os.path.dirname(__file__)
    return os.path.join(base_path, relative_path)

 此模块可以将相对路径转换为绝对路径,用于后续的打包操作。

(4)【重头戏】主界面类初始化

class FileSearcher(QMainWindow):
    def __init__(self):
        super().__init__()
        #### FileSearcher继承与QMainWindow,这是PyQt5中的一个主要窗口类
        # __init__ 方法: 构造函数,用于初始化窗口的各种组件和布局。
		# setWindowTitle: 设置窗口的标题为“文件查找器”。
        self.setWindowTitle('文件查找器')
        # setGeometry: 设置窗口的位置和大小。窗口将在屏幕坐标 (100, 100) 处显示,大小为 600x400 像素。
        self.setGeometry(100, 100, 600, 400)

        # 设置窗口的图标。resource_path 是一个函数(假设在其他地方定义),它返回图标文件的路径。
        self.setWindowIcon(QIcon(resource_path('source/image/logo.ico')))

        # 创建主窗口的中心小部件和布局
        central_widget = QWidget()
        # setCentralWidget: 将 central_widget 设为主窗口的中心小部件。
        self.setCentralWidget(central_widget)
        #  创建一个垂直布局 (QVBoxLayout),用于安排中心小部件中的子部件。
        layout = QVBoxLayout()

        # 文件夹目录部分
        dir_layout = QHBoxLayout()
        self.dir_label = QLabel('文件夹目录:')
        self.dir_input = QLineEdit()
        self.dir_button = QPushButton('选择目录')
        self.dir_button.clicked.connect(self.select_directory)
        dir_layout.addWidget(self.dir_label)
        dir_layout.addWidget(self.dir_input)
        dir_layout.addWidget(self.dir_button)
        layout.addLayout(dir_layout)

        # 查找条件部分
        condition_layout = QHBoxLayout()
        self.condition_label = QLabel('查找条件:')
        self.condition_input = QLineEdit()
        self.search_button = QPushButton('开始查找')
        self.search_button.clicked.connect(self.start_search)
        condition_layout.addWidget(self.condition_label)
        condition_layout.addWidget(self.condition_input)
        condition_layout.addWidget(self.search_button)
        layout.addLayout(condition_layout)

        # 进度条
        process_layout = QHBoxLayout()
        self.progress_label = QLabel('进度条:')
        self.progress_bar = QProgressBar()
        self.progress_bar.setRange(0, 100)
        process_layout.addWidget(self.progress_label)
        process_layout.addWidget(self.progress_bar)
        layout.addLayout(process_layout)

        # 结果显示区域
        self.results_list = QListWidget()
        self.results_list.itemDoubleClicked.connect(self.open_item)
        self.results_list.setContextMenuPolicy(Qt.CustomContextMenu)
        self.results_list.customContextMenuRequested.connect(self.show_context_menu)
        layout.addWidget(self.results_list)

        central_widget.setLayout(layout)

(5)界面功能链接

(6)完整代码

from PyQt5.QtWidgets import (QWidget, QVBoxLayout, QLabel, QLineEdit, QPushButton,
                             QListWidget, QProgressBar, QHBoxLayout, QMainWindow, QFileDialog, QMenu,
                             QDesktopWidget, QSplashScreen, QTimeEdit, QApplication)
from PyQt5.QtCore import Qt, QThread, pyqtSignal, QTimer, QTime
from PyQt5.QtGui import QPixmap, QIcon
import sys
import os
import fnmatch
import subprocess

class Worker(QThread):
    progress = pyqtSignal(int)
    finished = pyqtSignal(list)
    error = pyqtSignal(str)

    def __init__(self, directory, pattern):
        super().__init__()
        self.directory = directory
        self.pattern = pattern

    def run(self):
        results = []
        total_files = 0
        file_count = 0

        for root, dirs, files in os.walk(self.directory):
            total_files += len(dirs) + len(files)

        for root, dirs, files in os.walk(self.directory):
            for name in fnmatch.filter(dirs, self.pattern):
                results.append(os.path.join(root, name))
            for name in fnmatch.filter(files, self.pattern):
                results.append(os.path.join(root, name))
            file_count += len(dirs) + len(files)
            self.progress.emit(int((file_count / total_files) * 100))

        self.finished.emit(results)

def resource_path(relative_path):
    """ 获取资源文件的绝对路径 """
    try:
        # PyInstaller创建的临时文件夹路径
        base_path = sys._MEIPASS
    except AttributeError:
        # 如果不是打包的环境,使用当前文件夹
        base_path = os.path.dirname(__file__)
    return os.path.join(base_path, relative_path)

class ClockWidget(QWidget):
    def __init__(self):
        super().__init__()
        self.time_edit = QTimeEdit()
        self.time_edit.setDisplayFormat("HH:mm:ss")
        self.time_edit.setTime(QTime.currentTime())

        # Set up layout for the clock widget
        layout = QVBoxLayout()
        layout.addWidget(QLabel("数字时钟"))
        layout.addWidget(self.time_edit)
        layout.addStretch()
        self.setLayout(layout)

class FileSearcher(QMainWindow):
    def __init__(self):
        super().__init__()

        self.setWindowTitle('文件查找器')
        self.setGeometry(100, 100, 800, 400)  # Adjusted size to accommodate clocks

        self.setWindowIcon(QIcon(resource_path('source/image/logo.ico')))

        # Create the central widget and layout
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        main_layout = QHBoxLayout()  # Use HBoxLayout for left and right sections

        # Clock section
        clock_widget = QWidget()
        clock_layout = QVBoxLayout()

        # # Create and add clocks
        # self.digital_clock = ClockWidget()  # Digital clock
        # clock_layout.addWidget(self.digital_clock)
        #
        # clock_widget.setLayout(clock_layout)
        # main_layout.addWidget(clock_widget)

        # Main content section
        content_widget = QWidget()
        content_layout = QVBoxLayout()

        # File folder section
        dir_layout = QHBoxLayout()
        self.dir_label = QLabel('查找目录:')
        self.dir_input = QLineEdit()
        self.dir_button = QPushButton('选择目录')
        self.dir_button.clicked.connect(self.select_directory)
        dir_layout.addWidget(self.dir_label)
        dir_layout.addWidget(self.dir_input)
        dir_layout.addWidget(self.dir_button)
        content_layout.addLayout(dir_layout)

        # Search condition section
        condition_layout = QHBoxLayout()
        self.condition_label = QLabel('查找条件:')
        self.condition_input = QLineEdit()
        self.search_button = QPushButton('开始查找')
        self.search_button.clicked.connect(self.start_search)
        condition_layout.addWidget(self.condition_label)
        condition_layout.addWidget(self.condition_input)
        condition_layout.addWidget(self.search_button)
        content_layout.addLayout(condition_layout)

        # Progress bar
        process_layout = QHBoxLayout()
        self.progress_label = QLabel('进度条:')
        self.progress_bar = QProgressBar()
        self.progress_bar.setRange(0, 100)
        process_layout.addWidget(self.progress_label)
        process_layout.addWidget(self.progress_bar)
        content_layout.addLayout(process_layout)

        # Results display area
        self.results_list = QListWidget()
        self.results_list.itemDoubleClicked.connect(self.open_item)
        self.results_list.setContextMenuPolicy(Qt.CustomContextMenu)
        self.results_list.customContextMenuRequested.connect(self.show_context_menu)
        content_layout.addWidget(self.results_list)

        content_widget.setLayout(content_layout)
        main_layout.addWidget(content_widget)

        central_widget.setLayout(main_layout)

        # # Update the clock every second
        # self.timer = QTimer()
        # self.timer.timeout.connect(self.update_clocks)
        # self.timer.start(1000)  # Update every 1000 milliseconds

    def select_directory(self):
        folder = QFileDialog.getExistingDirectory(self, '选择目录')
        if folder:
            self.dir_input.setText(folder)
        else:
            default_directory = os.path.expanduser('~')  # Default path for Windows
            self.dir_input.setText(default_directory)

    def start_search(self):
        directory = self.dir_input.text()
        pattern = '*' + self.condition_input.text() + '*'

        if not os.path.isdir(directory):
            self.results_list.clear()
            self.results_list.addItem('无效的目录!')
            return

        self.progress_bar.setValue(0)
        self.results_list.clear()
        self.results_list.addItem('正在查找...')

        self.worker = Worker(directory, pattern)
        self.worker.progress.connect(self.progress_bar.setValue)
        self.worker.finished.connect(self.display_results)
        self.worker.error.connect(self.display_error)
        self.worker.start()

    def display_results(self, results):
        self.results_list.clear()
        if results:
            for result in results:
                self.results_list.addItem(result)
        else:
            self.results_list.addItem('没有找到符合条件的文件或文件夹')

    def display_error(self, message):
        self.results_list.clear()
        self.results_list.addItem(message)

    def open_item(self, item):
        path = item.text()
        if os.path.isfile(path):
            try:
                if sys.platform == 'win32':
                    os.startfile(path)
                elif sys.platform == 'darwin':
                    subprocess.call(('open', path))
                else:
                    subprocess.call(('xdg-open', path))
            except Exception as e:
                self.results_list.addItem(f"无法打开文件: {e}")

    def show_context_menu(self, pos):
        context_menu = QMenu(self)
        open_action = context_menu.addAction('定位到文件夹')
        action = context_menu.exec_(self.results_list.viewport().mapToGlobal(pos))

        if action == open_action:
            item = self.results_list.currentItem()
            if item:
                path = item.text()
                if os.path.isfile(path):
                    path = os.path.dirname(path)
                try:
                    if sys.platform == 'win32':
                        os.startfile(path)
                    elif sys.platform == 'darwin':
                        subprocess.call(('open', path))
                    else:
                        subprocess.call(('xdg-open', path))
                except Exception as e:
                    self.results_list.addItem(f"无法定位到文件夹: {e}")

    def update_clocks(self):
        self.digital_clock.time_edit.setTime(QTime.currentTime())

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Enter or event.key() == Qt.Key_Return:
            self.start_search()

def main():
    app = QApplication(sys.argv)

    splash_pix = QPixmap(resource_path('source/image/loading.png'))
    splash = QSplashScreen(splash_pix)
    splash.show()

    window = FileSearcher()

    QTimer.singleShot(500, lambda: (splash.close(), window.show()))

    screen = QDesktopWidget().screenGeometry()
    size = window.geometry()
    window.move((screen.width() - size.width()) // 2, (screen.height() - size.height()) // 2)

    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

三、总结

四、展望

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

风栖柳白杨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值