Python文件管理器:一个基于wxPython的桌面应用

在当今的软件开发世界中,管理大量的源代码文件变得越来越重要。无论是个人项目还是大型团队协作,有一个强大而灵活的文件管理工具都可以大大提高工作效率。今天,我们要介绍一个基于Python和wxPython构建的文件管理器,它专门用于管理.py文件。

C:\pythoncode\new\managefiles.py

全部代码

python 复制代码
import wx
import wx.lib.mixins.listctrl as listmix
import sqlite3
import os
import subprocess
from datetime import datetime
import openpyxl

class EditableListCtrl(wx.ListCtrl, listmix.TextEditMixin):
    def __init__(self, parent, style):
        wx.ListCtrl.__init__(self, parent, style=style)
        listmix.TextEditMixin.__init__(self)

class MyFrame(wx.Frame):
    def __init__(self):
        super().__init__(parent=None, title="Manage .py Files", size=(1000, 600))
        panel = wx.Panel(self)

        vbox = wx.BoxSizer(wx.VERTICAL)

        # Folder selection and scan button
        hbox1 = wx.BoxSizer(wx.HORIZONTAL)
        self.folder_picker = wx.DirPickerCtrl(panel)
        scan_btn = wx.Button(panel, label="Scan")
        scan_btn.Bind(wx.EVT_BUTTON, self.on_scan)
        hbox1.Add(self.folder_picker, proportion=1, flag=wx.EXPAND | wx.ALL, border=5)
        hbox1.Add(scan_btn, flag=wx.ALL, border=5)

        # ListView1 for displaying .py files
        self.listview1 = wx.ListCtrl(panel, style=wx.LC_REPORT | wx.LC_SINGLE_SEL)
        self.listview1.InsertColumn(0, "File Name", width=200)
        self.listview1.InsertColumn(1, "Full Path", width=400)
        self.listview1.InsertColumn(2, "Date Modified", width=200)
        self.listview1.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.on_listview1_double_click)

        # Search box for ListView1
        hbox2 = wx.BoxSizer(wx.HORIZONTAL)
        self.search1 = wx.TextCtrl(panel)
        search1_btn = wx.Button(panel, label="Search ListView1")
        search1_btn.Bind(wx.EVT_BUTTON, self.on_search1)
        hbox2.Add(self.search1, proportion=1, flag=wx.EXPAND | wx.ALL, border=5)
        hbox2.Add(search1_btn, flag=wx.ALL, border=5)

        # ListView2 for selected files with editable remarks and valid checkbox
        self.listview2 = wx.ListCtrl(panel, style=wx.LC_REPORT | wx.LC_SINGLE_SEL)
        self.listview2.InsertColumn(0, "File Name", width=200)
        self.listview2.InsertColumn(1, "Full Path", width=400)
        self.listview2.InsertColumn(2, "Date Modified", width=200)
        self.listview2.InsertColumn(3, "Remarks", width=150)
        self.listview2.InsertColumn(4, "Valid", width=50)
        self.listview2.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.on_listview2_double_click)

        # Search box for ListView2
        hbox3 = wx.BoxSizer(wx.HORIZONTAL)
        self.search2 = wx.TextCtrl(panel)
        search2_btn = wx.Button(panel, label="Search ListView2")
        search2_btn.Bind(wx.EVT_BUTTON, self.on_search2)
        hbox3.Add(self.search2, proportion=1, flag=wx.EXPAND | wx.ALL, border=5)
        hbox3.Add(search2_btn, flag=wx.ALL, border=5)

        # Buttons for opening, saving, and deleting
        hbox4 = wx.BoxSizer(wx.HORIZONTAL)
        open_btn = wx.Button(panel, label="Open in VSCode")
        open_btn.Bind(wx.EVT_BUTTON, self.on_open)
        save_btn = wx.Button(panel, label="Save to Database")
        save_btn.Bind(wx.EVT_BUTTON, self.save_to_database)
        delete_btn = wx.Button(panel, label="Delete Selected")
        delete_btn.Bind(wx.EVT_BUTTON, self.on_delete)
        hbox4.Add(open_btn, flag=wx.ALL, border=5)
        hbox4.Add(save_btn, flag=wx.ALL, border=5)
        hbox4.Add(delete_btn, flag=wx.ALL, border=5)

        # ListView3 for displaying database records
        self.listview3 = wx.ListCtrl(panel, style=wx.LC_REPORT | wx.LC_SINGLE_SEL)
        self.listview3.InsertColumn(0, "File Name", width=200)
        self.listview3.InsertColumn(1, "Full Path", width=400)
        self.listview3.InsertColumn(2, "Date Modified", width=200)
        self.listview3.InsertColumn(3, "Remarks", width=150)
        self.listview3.InsertColumn(4, "Valid", width=50)

        # Buttons for refreshing and deleting database records, opening in VSCode, and exporting to Excel
        hbox5 = wx.BoxSizer(wx.HORIZONTAL)
        refresh_btn = wx.Button(panel, label="Refresh Database Records")
        refresh_btn.Bind(wx.EVT_BUTTON, self.on_refresh)
        delete_db_btn = wx.Button(panel, label="Delete Database Record")
        delete_db_btn.Bind(wx.EVT_BUTTON, self.on_delete_db)
        open_vscode_btn = wx.Button(panel, label="Open in VSCode")
        open_vscode_btn.Bind(wx.EVT_BUTTON, self.on_open_vscode)
        export_excel_btn = wx.Button(panel, label="Export to Excel")
        export_excel_btn.Bind(wx.EVT_BUTTON, self.on_export_excel)
        hbox5.Add(refresh_btn, flag=wx.ALL, border=5)
        hbox5.Add(delete_db_btn, flag=wx.ALL, border=5)
        hbox5.Add(open_vscode_btn, flag=wx.ALL, border=5)
        hbox5.Add(export_excel_btn, flag=wx.ALL, border=5)

        # Adding all to the main vertical box
        vbox.Add(hbox1, flag=wx.EXPAND | wx.ALL, border=5)
        vbox.Add(self.listview1, proportion=1, flag=wx.EXPAND | wx.ALL, border=5)
        vbox.Add(hbox2, flag=wx.EXPAND | wx.ALL, border=5)
        vbox.Add(self.listview2, proportion=1, flag=wx.EXPAND | wx.ALL, border=5)
        vbox.Add(hbox3, flag=wx.EXPAND | wx.ALL, border=5)
        vbox.Add(hbox4, flag=wx.ALIGN_CENTER | wx.ALL, border=5)
        vbox.Add(self.listview3, proportion=1, flag=wx.EXPAND | wx.ALL, border=5)
        vbox.Add(hbox5, flag=wx.ALIGN_CENTER | wx.ALL, border=5)

        panel.SetSizer(vbox)

        self.db_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "files1.db")

    def on_scan(self, event):
        folder_path = self.folder_picker.GetPath()
        if not folder_path:
            wx.MessageBox("Please select a folder.", "Error", wx.OK | wx.ICON_ERROR)
            return

        self.listview1.DeleteAllItems()

        py_files = []
        for root, dirs, files in os.walk(folder_path):
            for file in files:
                if file.endswith(".py"):
                    full_path = os.path.join(root, file)
                    date_modified = os.path.getmtime(full_path)
                    date_str = wx.DateTime.FromTimeT(int(date_modified)).FormatISOCombined()
                    py_files.append((file, full_path, date_str, date_modified))

        # Sort files by date modified (most recent first)
        py_files.sort(key=lambda x: x[3], reverse=True)

        for file, full_path, date_str, _ in py_files:
            index = self.listview1.InsertItem(self.listview1.GetItemCount(), file)
            self.listview1.SetItem(index, 1, full_path)
            self.listview1.SetItem(index, 2, date_str)

    def on_listview1_double_click(self, event):
        selected = self.listview1.GetFirstSelected()
        if selected == -1:
            return

        file_name = self.listview1.GetItemText(selected)
        full_path = self.listview1.GetItem(selected, 1).GetText()
        date_modified = self.listview1.GetItem(selected, 2).GetText()

        new_index = self.listview2.InsertItem(self.listview2.GetItemCount(), file_name)
        self.listview2.SetItem(new_index, 1, full_path)
        self.listview2.SetItem(new_index, 2, date_modified)
        self.listview2.SetItem(new_index, 3, "")
        self.listview2.SetItem(new_index, 4, "No")

    def on_listview2_double_click(self, event):
        selected = self.listview2.GetFirstSelected()
        if selected == -1:
            return

        remarks = self.listview2.GetItem(selected, 3).GetText()
        valid = self.listview2.GetItem(selected, 4).GetText()

        dlg = EditDialog(self, remarks, valid == "Yes")
        if dlg.ShowModal() == wx.ID_OK:
            new_remarks, new_valid = dlg.get_values()
            self.listview2.SetItem(selected, 3, new_remarks)
            self.listview2.SetItem(selected, 4, new_valid)
        
        dlg.Destroy()

    def on_search1(self, event):
        search_term = self.search1.GetValue().lower()
        self.search_in_listview(self.listview1, search_term)

    def on_search2(self, event):
        search_term = self.search2.GetValue().lower()
        self.search_in_listview(self.listview2, search_term)

    # def search_in_listview(self, listview, search_term):
    #     listview.DeleteAllItems()
    #     for index in range(listview.GetItemCount()):
    #         item_text = listview.GetItemText(index).lower()
    #         full_path = listview.GetItem(index, 1).GetText().lower()
    #         if search_term in item_text or search_term in full_path:
    #             new_index = listview.InsertItem(listview.GetItemCount(), listview.GetItemText(index))
    #             for col in range(1, listview.GetColumnCount()):
    #                 listview.SetItem(new_index, col, listview.GetItem(index, col).GetText())
    def search_in_listview(self, listview, search_term):
        for i in range(listview.GetItemCount()):
            item = listview.GetItem(i)
            if search_term in item.GetText().lower() or search_term in listview.GetItem(i, 1).GetText().lower():
                item.SetBackgroundColour(wx.YELLOW)
                listview.SetItem(item)
                listview.EnsureVisible(i)
            else:
                item.SetBackgroundColour(wx.WHITE)
                listview.SetItem(item)

        if not search_term:
            for i in range(listview.GetItemCount()):
                item = listview.GetItem(i)
                item.SetBackgroundColour(wx.WHITE)
                listview.SetItem(item)

    def on_open(self, event):
        self.open_in_vscode(self.listview2)

    def on_open_vscode(self, event):
        self.open_in_vscode(self.listview3)

    def open_in_vscode(self, listview):
        selected = listview.GetFirstSelected()
        if selected == -1:
            wx.MessageBox("Please select a file to open", "Error", wx.OK | wx.ICON_ERROR)
            return

        full_path = listview.GetItem(selected, 1).GetText()
        subprocess.Popen(["C:\\Users\\86182\\AppData\\Local\\Programs\\Microsoft VS Code\\Code.exe", full_path])

    # def save_to_database(self, event):
    #     try:
    #         conn = sqlite3.connect(self.db_path)
    #         cursor = conn.cursor()

    #         # Ensure table exists
    #         cursor.execute('''CREATE TABLE IF NOT EXISTS files (
    #                             id INTEGER PRIMARY KEY AUTOINCREMENT,
    #                             file_name TEXT,
    #                             full_path TEXT,
    #                             date_modified TEXT,
    #                             remarks TEXT,
    #                             valid INTEGER)''')

    #         cursor.execute('DELETE FROM files')  # Clear old records

    #         for index in range(self.listview2.GetItemCount()):
    #             file_name = self.listview2.GetItemText(index)
    #             full_path = self.listview2.GetItem(index, 1).GetText()
    #             date_modified = self.listview2.GetItem(index, 2).GetText()
    #             remarks = self.listview2.GetItem(index, 3).GetText()
    #             valid = self.listview2.GetItem(index, 4).GetText()
    #             valid = 1 if valid == "Yes" else 0

    #             cursor.execute('INSERT INTO files (file_name, full_path, date_modified, remarks, valid) VALUES (?, ?, ?, ?, ?)',
    #                         (file_name, full_path, date_modified, remarks, valid))

    #         conn.commit()  # Save changes
    #     except sqlite3.Error as e:
    #         wx.MessageBox(f"Database error: {e}", "Error", wx.OK | wx.ICON_ERROR)
    #     finally:
    #         conn.close()  # Ensure connection is closed

    #     wx.MessageBox("Data saved to the database.", "Info", wx.OK | wx.ICON_INFORMATION)
    def save_to_database(self, event):
        try:
            conn = sqlite3.connect(self.db_path)
            cursor = conn.cursor()

            # Ensure table exists
            cursor.execute('''CREATE TABLE IF NOT EXISTS files (
                                id INTEGER PRIMARY KEY AUTOINCREMENT,
                                file_name TEXT,
                                full_path TEXT,
                                date_modified TEXT,
                                remarks TEXT,
                                valid INTEGER)''')

            # Append new records instead of deleting old ones
            for index in range(self.listview2.GetItemCount()):
                file_name = self.listview2.GetItemText(index)
                full_path = self.listview2.GetItem(index, 1).GetText()
                date_modified = self.listview2.GetItem(index, 2).GetText()
                remarks = self.listview2.GetItem(index, 3).GetText()
                valid = self.listview2.GetItem(index, 4).GetText()
                valid = 1 if valid == "Yes" else 0

                # Check if the record already exists
                cursor.execute('SELECT * FROM files WHERE full_path = ?', (full_path,))
                if cursor.fetchone() is None:
                    # If it doesn't exist, insert a new record
                    cursor.execute('INSERT INTO files (file_name, full_path, date_modified, remarks, valid) VALUES (?, ?, ?, ?, ?)',
                                (file_name, full_path, date_modified, remarks, valid))
                else:
                    # If it exists, update the existing record
                    cursor.execute('UPDATE files SET file_name = ?, date_modified = ?, remarks = ?, valid = ? WHERE full_path = ?',
                                (file_name, date_modified, remarks, valid, full_path))

            conn.commit()  # Save changes
        except sqlite3.Error as e:
            wx.MessageBox(f"Database error: {e}", "Error", wx.OK | wx.ICON_ERROR)
        finally:
            conn.close()  # Ensure connection is closed

        wx.MessageBox("Data saved to the database.", "Info", wx.OK | wx.ICON_INFORMATION)

    def on_delete(self, event):
        selected = self.listview2.GetFirstSelected()
        if selected == -1:
            wx.MessageBox("Please select a file to delete", "Error", wx.OK | wx.ICON_ERROR)
            return

        self.listview2.DeleteItem(selected)

    def on_refresh(self, event):
        self.listview3.DeleteAllItems()

        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        cursor.execute('SELECT file_name, full_path, date_modified, remarks, valid FROM files')

        for row in cursor.fetchall():
            file_name, full_path, date_modified, remarks, valid = row
            valid_text = "Yes" if valid == 1 else "No"

            index = self.listview3.InsertItem(self.listview3.GetItemCount(), file_name)
            self.listview3.SetItem(index, 1, full_path)
            self.listview3.SetItem(index, 2, date_modified)
            self.listview3.SetItem(index, 3, remarks)
            self.listview3.SetItem(index, 4, valid_text)

        conn.close()

    def on_delete_db(self, event):
        selected = self.listview3.GetFirstSelected()
        if selected == -1:
            wx.MessageBox("Please select a database record to delete", "Error", wx.OK | wx.ICON_ERROR)
            return

        full_path = self.listview3.GetItem(selected, 1).GetText()

        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        # cursor.execute('DELETE FROM

        cursor.execute('DELETE FROM files WHERE full_path = ?', (full_path,))
        conn.commit()
        conn.close()

        self.listview3.DeleteItem(selected)

        wx.MessageBox("Record deleted from the database.", "Info", wx.OK | wx.ICON_INFORMATION)

    def on_export_excel(self, event):
        if self.listview3.GetItemCount() == 0:
            wx.MessageBox("No data to export.", "Error", wx.OK | wx.ICON_ERROR)
            return

        with wx.FileDialog(self, "Save Excel file", wildcard="Excel files (*.xlsx)|*.xlsx",
                           style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT) as fileDialog:

            if fileDialog.ShowModal() == wx.ID_CANCEL:
                return

            pathname = fileDialog.GetPath()
            try:
                workbook = openpyxl.Workbook()
                sheet = workbook.active
                sheet.title = "Python Files"

                # Write headers
                headers = ["File Name", "Full Path", "Date Modified", "Remarks", "Valid"]
                for col, header in enumerate(headers, start=1):
                    sheet.cell(row=1, column=col, value=header)

                # Write data
                for row in range(self.listview3.GetItemCount()):
                    for col in range(self.listview3.GetColumnCount()):
                        value = self.listview3.GetItem(row, col).GetText()
                        sheet.cell(row=row+2, column=col+1, value=value)

                workbook.save(pathname)
                wx.MessageBox(f"Data exported to {pathname}", "Info", wx.OK | wx.ICON_INFORMATION)
            except Exception as e:
                wx.MessageBox(f"Failed to export data: {str(e)}", "Error", wx.OK | wx.ICON_ERROR)

class EditDialog(wx.Dialog):
    def __init__(self, parent, remarks, valid):
        super().__init__(parent, title="Edit Record", size=(350, 200))

        vbox = wx.BoxSizer(wx.VERTICAL)

        hbox1 = wx.BoxSizer(wx.HORIZONTAL)
        lbl1 = wx.StaticText(self, label="Remarks:")
        self.remarks_ctrl = wx.TextCtrl(self, value=remarks, style=wx.TE_MULTILINE)
        hbox1.Add(lbl1, flag=wx.ALL, border=5)
        hbox1.Add(self.remarks_ctrl, proportion=1, flag=wx.EXPAND | wx.ALL, border=5)

        hbox2 = wx.BoxSizer(wx.HORIZONTAL)
        lbl2 = wx.StaticText(self, label="Valid:")
        self.valid_checkbox = wx.CheckBox(self)
        self.valid_checkbox.SetValue(valid)
        hbox2.Add(lbl2, flag=wx.ALL, border=5)
        hbox2.Add(self.valid_checkbox, flag=wx.ALL, border=5)

        hbox3 = wx.BoxSizer(wx.HORIZONTAL)
        ok_btn = wx.Button(self, label="OK")
        ok_btn.Bind(wx.EVT_BUTTON, self.on_ok)
        cancel_btn = wx.Button(self, label="Cancel")
        cancel_btn.Bind(wx.EVT_BUTTON, self.on_cancel)
        hbox3.Add(ok_btn, flag=wx.ALL, border=5)
        hbox3.Add(cancel_btn, flag=wx.ALL, border=5)

        vbox.Add(hbox1, proportion=1, flag=wx.EXPAND | wx.ALL, border=10)
        vbox.Add(hbox2, flag=wx.ALIGN_CENTER | wx.ALL, border=10)
        vbox.Add(hbox3, flag=wx.ALIGN_CENTER | wx.ALL, border=10)

        self.SetSizer(vbox)

    def on_ok(self, event):
        self.EndModal(wx.ID_OK)

    def on_cancel(self, event):
        self.EndModal(wx.ID_CANCEL)

    def get_values(self):
        remarks = self.remarks_ctrl.GetValue()
        valid = "Yes" if self.valid_checkbox.GetValue() else "No"
        return remarks, valid

class MyApp(wx.App):
    def OnInit(self):
        frame = MyFrame()
        frame.Show()
        return True

if __name__ == "__main__":
    app = MyApp(False)
    app.MainLoop()                       

应用概述

这个应用程序提供了一个图形用户界面,允许用户浏览文件系统,查看和管理Python源代码文件。它的主要功能包括:

  1. 扫描指定文件夹中的所有.py文件
  2. 在列表视图中显示文件信息
  3. 搜索文件
  4. 编辑文件备注和有效性标志
  5. 将文件信息保存到SQLite数据库
  6. 从数据库中检索和显示文件信息
  7. 在Visual Studio Code中打开选定的文件
  8. 将文件信息导出到Excel

让我们深入了解这个应用的一些关键特性和它们的实现方式。

核心功能解析

1. 文件扫描和显示

应用程序使用Python的os模块来遍历指定文件夹及其子文件夹,查找所有的.py文件。文件信息(包括文件名、完整路径和修改日期)被收集并按最近修改日期排序,然后显示在一个wx.ListCtrl控件中。

python 复制代码
def on_scan(self, event):
    folder_path = self.folder_picker.GetPath()
    if not folder_path:
        wx.MessageBox("Please select a folder.", "Error", wx.OK | wx.ICON_ERROR)
        return

    self.listview1.DeleteAllItems()

    py_files = []
    for root, dirs, files in os.walk(folder_path):
        for file in files:
            if file.endswith(".py"):
                full_path = os.path.join(root, file)
                date_modified = os.path.getmtime(full_path)
                date_str = wx.DateTime.FromTimeT(int(date_modified)).FormatISOCombined()
                py_files.append((file, full_path, date_str, date_modified))

    # Sort files by date modified (most recent first)
    py_files.sort(key=lambda x: x[3], reverse=True)

    for file, full_path, date_str, _ in py_files:
        index = self.listview1.InsertItem(self.listview1.GetItemCount(), file)
        self.listview1.SetItem(index, 1, full_path)
        self.listview1.SetItem(index, 2, date_str)

2. 文件搜索

搜索功能允许用户在文件名或完整路径中查找匹配项。匹配的项目会被高亮显示,使用户能够快速定位所需的文件。

python 复制代码
def search_in_listview(self, listview, search_term):
    for i in range(listview.GetItemCount()):
        item = listview.GetItem(i)
        if search_term in item.GetText().lower() or search_term in listview.GetItem(i, 1).GetText().lower():
            item.SetBackgroundColour(wx.YELLOW)
            listview.SetItem(item)
            listview.EnsureVisible(i)
        else:
            item.SetBackgroundColour(wx.WHITE)
            listview.SetItem(item)

    if not search_term:
        for i in range(listview.GetItemCount()):
            item = listview.GetItem(i)
            item.SetBackgroundColour(wx.WHITE)
            listview.SetItem(item)

3. 数据库集成

应用程序使用SQLite数据库来持久化文件信息。用户可以将文件信息保存到数据库,也可以从数据库中检索信息。这个功能特别有用,因为它允许用户在不同的会话中保留他们的文件管理状态。

python 复制代码
def save_to_database(self, event):
    try:
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()

        # Ensure table exists
        cursor.execute('''CREATE TABLE IF NOT EXISTS files (
                            id INTEGER PRIMARY KEY AUTOINCREMENT,
                            file_name TEXT,
                            full_path TEXT,
                            date_modified TEXT,
                            remarks TEXT,
                            valid INTEGER)''')

        # Append new records or update existing ones
        for index in range(self.listview2.GetItemCount()):
            file_name = self.listview2.GetItemText(index)
            full_path = self.listview2.GetItem(index, 1).GetText()
            date_modified = self.listview2.GetItem(index, 2).GetText()
            remarks = self.listview2.GetItem(index, 3).GetText()
            valid = self.listview2.GetItem(index, 4).GetText()
            valid = 1 if valid == "Yes" else 0

            # Check if the record already exists
            cursor.execute('SELECT * FROM files WHERE full_path = ?', (full_path,))
            if cursor.fetchone() is None:
                # If it doesn't exist, insert a new record
                cursor.execute('INSERT INTO files (file_name, full_path, date_modified, remarks, valid) VALUES (?, ?, ?, ?, ?)',
                            (file_name, full_path, date_modified, remarks, valid))
            else:
                # If it exists, update the existing record
                cursor.execute('UPDATE files SET file_name = ?, date_modified = ?, remarks = ?, valid = ? WHERE full_path = ?',
                            (file_name, date_modified, remarks, valid, full_path))

        conn.commit()
    except sqlite3.Error as e:
        wx.MessageBox(f"Database error: {e}", "Error", wx.OK | wx.ICON_ERROR)
    finally:
        conn.close()

    wx.MessageBox("Data saved to the database.", "Info", wx.OK | wx.ICON_INFORMATION)

4. 与Visual Studio Code集成

为了提高开发效率,应用程序允许用户直接在Visual Studio Code中打开选定的Python文件。这是通过使用Python的subprocess模块来启动VS Code实现的。

python 复制代码
def open_in_vscode(self, listview):
    selected = listview.GetFirstSelected()
    if selected == -1:
        wx.MessageBox("Please select a file to open", "Error", wx.OK | wx.ICON_ERROR)
        return

    full_path = listview.GetItem(selected, 1).GetText()
    subprocess.Popen(["C:\\Users\\86182\\AppData\\Local\\Programs\\Microsoft VS Code\\Code.exe", full_path])

5. 导出到Excel

为了方便数据共享和报告生成,应用程序提供了将文件信息导出到Excel的功能。这是使用openpyxl库实现的。

python 复制代码
def on_export_excel(self, event):
    if self.listview3.GetItemCount() == 0:
        wx.MessageBox("No data to export.", "Error", wx.OK | wx.ICON_ERROR)
        return

    with wx.FileDialog(self, "Save Excel file", wildcard="Excel files (*.xlsx)|*.xlsx",
                       style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT) as fileDialog:

        if fileDialog.ShowModal() == wx.ID_CANCEL:
            return

        pathname = fileDialog.GetPath()
        try:
            workbook = openpyxl.Workbook()
            sheet = workbook.active
            sheet.title = "Python Files"

            # Write headers
            headers = ["File Name", "Full Path", "Date Modified", "Remarks", "Valid"]
            for col, header in enumerate(headers, start=1):
                sheet.cell(row=1, column=col, value=header)

            # Write data
            for row in range(self.listview3.GetItemCount()):
                for col in range(self.listview3.GetColumnCount()):
                    value = self.listview3.GetItem(row, col).GetText()
                    sheet.cell(row=row+2, column=col+1, value=value)

            workbook.save(pathname)
            wx.MessageBox(f"Data exported to {pathname}", "Info", wx.OK | wx.ICON_INFORMATION)
        except Exception as e:
            wx.MessageBox(f"Failed to export data: {str(e)}", "Error", wx.OK | wx.ICON_ERROR)

效果如下

结论

这个Python文件管理器应用程序展示了如何使用Python和wxPython创建一个功能丰富的桌面应用。它不仅提供了基本的文件管理功能,还集成了数据库持久化、外部编辑器启动和数据导出等高级特性。

相关推荐
这个DBA有点耶2 小时前
NULL不是空——数据库里最反直觉的设计,90%新人踩过的坑
数据库·mysql·代码规范
用户8356290780512 小时前
Python 实现 PDF 文件加密与解密方法
后端·python
用户8356290780512 小时前
使用 Python 冻结与拆分 Excel 窗格教程
后端·python
这个DBA有点耶4 小时前
AI写的SQL跑崩了生产库,这锅谁背?
数据库·人工智能·程序员
镜舟科技5 小时前
Databricks 再提 LTAP,AI 时代的数据底座为何重回大一统叙事?
数据库·架构·agent
Databend5 小时前
从湖仓升级为 Agent 时代的数据控制面,Snowflake 和 Databricks 有哪些布局
大数据·数据库·agent
ClouGence9 小时前
SQL Server CDC 能放到 Always On 备库读吗?一文讲透原理与实践
数据库·sql server
你好潘先生10 小时前
别再记命令了,用 yeero do 说句人话就能跑脚本,而且不烧 token
服务器·python·命令行
Agent_大师11 小时前
WebSocket 行情重连成功,K线缺口不会自动消失
python
荣码11 小时前
LLM结构化输出:让AI返回JSON而不是废话,我踩了4个坑
java·python