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

news2024/9/20 14:49:54

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

全部代码

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控件中。

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. 文件搜索

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

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数据库来持久化文件信息。用户可以将文件信息保存到数据库,也可以从数据库中检索信息。这个功能特别有用,因为它允许用户在不同的会话中保留他们的文件管理状态。

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实现的。

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库实现的。

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创建一个功能丰富的桌面应用。它不仅提供了基本的文件管理功能,还集成了数据库持久化、外部编辑器启动和数据导出等高级特性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2052104.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

GNS3 IOU: License section not found in iourc file /tmp/tmpj54abrhf/iourc

现象: License section not found in iourc file /tmp/tmpj54abrhf/iourc 解决方案: IOU 证书:(直接复制进去即可) [license] gns3-iouvm cd11acbc599f2364; gns3vm 73635fd3b0a13ad0;

记一个坑android Studio:Can‘t bind to local -1 for debugger

AndroidStudio 可编译,安装,设置管理 现象: 唯独 attach 或者调试时报错 Cant bind to local -1 for debugger 控制台日志: 2024-08-15 10:41:59,645 [ 9927] WARN - #com.android.ddmlib - * daemon not running; starting now at tcp:5037 2024-08-15 10:…

DRISSIONPAGE获取图书的封面并保存到本地

一、页面自动截图 二、最终结果 三、代码实现 from DrissionPage import ChromiumPage,ChromiumOptions co =ChromiumOptions().set_paths(browser_path=r"C:\Users\lenovo\AppData\Local\Google\Chrome\Application\chrome.exe") #这里指定浏览器 注意ChromiumOp…

【Oracle篇】统计信息和动态采样的深度剖析(第一篇,总共六篇)

💫《博主介绍》:✨又是一天没白过,我是奈斯,DBA一名✨ 💫《擅长领域》:✌️擅长Oracle、MySQL、SQLserver、阿里云AnalyticDB for MySQL(分布式数据仓库)、Linux,也在扩展大数据方向的知识面✌️…

广州南沙某工厂电力运维系统案例

一、引言 深圳拓扑未来基于物联网的电力运维系统将云计算、大数据与人工智能对采集的数据进行挖掘整合、共享交换,并以数字全息投影的信息技术手段将数据立体化呈现。满足用户监测众多电力回路运行状态和参数、配电室内环境温湿度、电缆及母线运行温度、现场设备或…

配置静态ip地址,也叫网络地址,linux安装tomcat,mysql,java的jdk,如何把java项目部署到linux上

3、linux 所需软件压缩包 4、防火墙的操作 5、Linux网络配置 接下来需要配置Linux系统的网络,这样才能保证软件能够正常安装上去 5.1 配置连接外网 进入etc/sysconfig/network-scripts目录,使用vi打开 ifcfg-ensXXX文件,进行编辑 cd /etc…

快速体验Ollama安装部署并支持AMD ROCm推理加速

序言 Ollama 是一个专注于本地运行大型语言模型(LLM)的框架,它使得用户能够在自己的计算机上轻松地部署和使用大型语言模型,而无需依赖昂贵的GPU资源。Ollama 提供了一系列的工具和服务,旨在简化大型语言模型的安装、…

阵列信号处理1_相控阵天线(CSDN_20240818)

与传统天线相比,相控阵天线的阵面是由许多阵元组成的,在这些阵元的基础上,相控阵天线可以利用一些精妙的算法在天线不旋转的条件下,自动形成波束并对准目标。通常,由相控阵天线形成的波束的质量要比普通天线波束的质量…

LeetCode //C - 319. Bulb Switcher

319. Bulb Switcher There are n bulbs that are initially off. You first turn on all the bulbs, then you turn off every second bulb. On the third round, you toggle every third bulb (turning on if it’s off or turning off if it’s on). For the $i^{th} $roun…

七彩玫瑰与彩虹玫瑰的花语探秘

一、什么是七彩玫瑰和彩虹玫瑰 七彩玫瑰和彩虹玫瑰并非自然界原生的花卉品种,而是通过人工手段精心培育和加工而成的独特花卉。它们的独特之处在于花瓣呈现出七种绚烂的颜色,宛如彩虹般绚丽多彩,令人眼前一亮。 七彩玫瑰和彩虹玫瑰通常是由白…

短链接系统设计方案

背景 需要设计一个短链接系统,主要功能主要有如下几点: ToB: 输入一个长链接,转换成短链接。这个短链接有时效性,可以设定指定过期时间。这个系统的每天会生成千万级别的短链接。数据具备可分析功能。 ToC&#xf…

xss.function靶场(hard)

文章目录 WW3源码分析源码 DOMPpurify框架绕过覆盖变量notifyjs作用域和作用链域构建payload WW3 源码 <!-- Challenge --> <div><h4>Meme Code</h4><textarea class"form-control" id"meme-code" rows"4"><…

MySQL实现SQL Server中UPDLOCK与READPAST组合功能

碰到一位同事求助解决消息中台一个线上的bug&#xff0c;具体描述如下&#xff1a; 首先有一张主表记录消息待发送的内容&#xff0c;一张子表记录本条消息的发送状态。若发送成功则将此条消息的发送状态修改为已发送并做逻辑删除。代码通过定时任务每2s轮询子表&#xff0c;如…

开源AI智能名片O2O商城小程序在社群团购中的创新应用与策略

摘要&#xff1a;随着移动互联网和社交电商的快速发展&#xff0c;传统企业纷纷寻求数字化转型以应对市场变化。然而&#xff0c;许多企业在转型过程中存在误区&#xff0c;认为仅仅是销售渠道的变更&#xff0c;而忽视了针对不同消费群体提供差异化产品和服务的重要性。本文旨…

MSO和WPS文档图标那些事儿

你以为这是MSO的文件图标吗&#xff1f;其实不然 以上图标才是出自MSO&#xff0c;但如果在电脑上安装WPS时勾选了关联文件类型&#xff0c;你的图标可能变成 2019WPS 新版WPS 即使你更改了默认打开方式&#xff0c;文件图标也还可能是WPS的 有一说一。MSO的设计尖锐感太强&a…

从零开始学cv-8:直方图操作进阶

文章目录 一&#xff0c;简介二、直方图匹配三、局部直方图均衡化四、彩色直方图均衡化4.1 rgb彩色直方图均衡化4.2 ycrb 彩色直方图均衡化 一&#xff0c;简介 在上一篇文章中&#xff0c;我们探讨了直方图的基本概念&#xff0c;并详细讲解了如何利用OpenCV来查看图像直方图…

王老师 linux c++ 通信架构 笔记(四)继续介绍 nginx 的编译,生成适合本平台的 nginx 可执行程序

&#xff08;16&#xff09; 继续介绍 nginx 的文件夹组成&#xff1a; 接着介绍 conf 目录 &#xff1a; 接着介绍 contrib 文件夹 &#xff1a; 接着介绍 html 文件夹 &#xff1a; 接着介绍 man 文件夹&#xff1a; 更正一下&#xff1a; 下图即为此帮助文件的内容&#…

电子电气架构---主流主机厂电子电气架构华山论剑(下)

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证明自己,无利益不试图说服别人,是精神上的节…

华为AR1220配置GRE隧道

1.GRE隧道的配置 GRE隧道的配置过程,包括设置接口IP地址、配置GRE隧道接口和参数、配置静态路由以及测试隧道连通性。GRE隧道作为一种标准协议,支持多协议传输,但不提供加密,并且可能导致CPU资源消耗大和调试复杂等问题。本文采用华为AR1220路由器来示例说明。 配置…

Dubbo源码深度解析(六)

上一篇博客《Dubbo源码深度解析(五)》主要讲&#xff1a;当服务消费方发起请求时&#xff0c;服务提供方是通过Netty服务接受请求并处理的&#xff0c;涉及到Netty相关使用及部分原理的讲解&#xff0c;以及最后又是如何将Invoker对象的执行结果返回给服务消费方的等。同时也讲…