首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 更多程式設計知識

使用 wxPython 從零構建一個簡易記事本

     編輯:更多程式設計知識

wxPython 是成熟的跨平台 GUI 工具包,適合快速開發桌面應用。本文將一步步帶領讀者建立一個具備「開啟檔案、編輯、儲存」核心功能的記事本,並說明關鍵元件(Frame、Panel、TextCtrl、FileDialog、BoxSizer)的協作方式。

完整代碼(約 80 行)

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import wx

class NotepadFrame(wx.Frame):
    def __init__(self):
        super().__init__(None, title='Simple Notepad', size=(700, 500))
        self.current_file = None
        self._build_ui()
        self.Centre()
        self.Show()

    def _build_ui(self):
        panel = wx.Panel(self)
        # 工具列區域
        self.filename_ctrl = wx.TextCtrl(panel, style=wx.TE_READONLY)
        open_btn = wx.Button(panel, label='開啟')
        save_btn = wx.Button(panel, label='儲存')
        save_as_btn = wx.Button(panel, label='另存新檔')

        open_btn.Bind(wx.EVT_BUTTON, self.on_open)
        save_btn.Bind(wx.EVT_BUTTON, self.on_save)
        save_as_btn.Bind(wx.EVT_BUTTON, lambda e: self.on_save(as_new=True))

        # 編輯區
        self.text_ctrl = wx.TextCtrl(panel, style=wx.TE_MULTILINE | wx.TE_RICH2)

        # 版面配置
        tool_sizer = wx.BoxSizer(wx.HORIZONTAL)
        tool_sizer.Add(wx.StaticText(panel, label='檔案:'), 0, wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, 5)
        tool_sizer.Add(self.filename_ctrl, 1, wx.EXPAND | wx.RIGHT, 5)
        tool_sizer.Add(open_btn, 0, wx.RIGHT, 5)
        tool_sizer.Add(save_btn, 0, wx.RIGHT, 5)
        tool_sizer.Add(save_as_btn, 0)

        main_sizer = wx.BoxSizer(wx.VERTICAL)
        main_sizer.Add(tool_sizer, 0, wx.EXPAND | wx.ALL, 8)
        main_sizer.Add(self.text_ctrl, 1, wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, 8)
        panel.SetSizer(main_sizer)

        # 選單列(加分項)
        self._build_menubar()

    def _build_menubar(self):
        menubar = wx.MenuBar()
        file_menu = wx.Menu()
        file_menu.Append(wx.ID_OPEN, '開啟\tCtrl+O')
        file_menu.Append(wx.ID_SAVE, '儲存\tCtrl+S')
        file_menu.Append(wx.ID_SAVEAS, '另存新檔\tCtrl+Shift+S')
        file_menu.AppendSeparator()
        file_menu.Append(wx.ID_EXIT, '離開\tCtrl+Q')
        menubar.Append(file_menu, '檔案(&F)')
        self.SetMenuBar(menubar)
        self.Bind(wx.EVT_MENU, self.on_open, id=wx.ID_OPEN)
        self.Bind(wx.EVT_MENU, self.on_save, id=wx.ID_SAVE)
        self.Bind(wx.EVT_MENU, lambda e: self.on_save(as_new=True), id=wx.ID_SAVEAS)
        self.Bind(wx.EVT_MENU, lambda e: self.Close(), id=wx.ID_EXIT)

    # --- 事件處理 ---
    def on_open(self, event):
        with wx.FileDialog(self, '開啟文字檔', wildcard='文字檔 (*.txt)|*.txt|所有檔案 (*.*)|*.*',
                           style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) as dlg:
            if dlg.ShowModal() == wx.ID_CANCEL:
                return
            path = dlg.GetPath()
            try:
                with open(path, 'r', encoding='utf-8') as f:
                    self.text_ctrl.SetValue(f.read())
                self.current_file = path
                self.filename_ctrl.SetValue(path)
                self.SetTitle(f'Simple Notepad - {path}')
            except Exception as e:
                wx.MessageBox(f'讀取失敗:{e}', '錯誤', wx.OK | wx.ICON_ERROR)

    def on_save(self, event, as_new=False):
        if as_new or self.current_file is None:
            with wx.FileDialog(self, '儲存文字檔', wildcard='文字檔 (*.txt)|*.txt',
                               style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT) as dlg:
                if dlg.ShowModal() == wx.ID_CANCEL:
                    return
                self.current_file = dlg.GetPath()
        try:
            with open(self.current_file, 'w', encoding='utf-8') as f:
                f.write(self.text_ctrl.GetValue())
            self.filename_ctrl.SetValue(self.current_file)
            self.SetTitle(f'Simple Notepad - {self.current_file}')
            wx.MessageBox('儲存成功', '提示', wx.OK | wx.ICON_INFORMATION)
        except Exception as e:
            wx.MessageBox(f'儲存失敗:{e}', '錯誤', wx.OK | wx.ICON_ERROR)

if __name__ == '__main__':
    app = wx.App()
    NotepadFrame()
    app.MainLoop()

關鍵元件解析

元件用途關鍵參數/方法
wx.Frame主視窗容器title, size, Centre(), Show()
wx.Panel承載子元件、支援 Tab 鍵導航SetSizer()
wx.TextCtrl文字編輯區style=TE_MULTILINE|TE_RICH2, SetValue/GetValue()
wx.FileDialog開啟/儲存檔案對話框wildcard, style=FD_OPEN/FD_SAVE, GetPath()
wx.BoxSizer盒狀版面管理(水平/垂直)Add(widget, proportion, flag, border)
wx.MenuBar選單列Append(menu, title), SetMenuBar()

版面配置技巧:Sizer 參數詳解

  • proportion:剩餘空間分配比例。0 表示固定大小,>0 按比例分配。
  • flag:對齊與邊框。常用組合:
    • wx.EXPAND:填滿分配空間
    • wx.ALL | wx.EXPAND:四周留白並填滿
    • wx.ALIGN_CENTER_VERTICAL:垂直置中
  • border:邊距像素。

常見擴充方向

  1. 編碼自動偵測:引入 chardet 或 charset_normalizer。
  2. 語法高亮:改用 wx.stc.StyledTextCtrl(Scintilla 封裝)。
  3. 多頁籤:使用 wx.Notebook 或 wx.AuiNotebook。
  4. 撤銷/重做:TextCtrl 內建支援 Undo()/Redo()。
  5. 打包發布:使用 PyInstaller 產生單一執行檔(--noconsole --icon=app.ico)。

常見坑點提醒

  • macOS 上需安裝 wxPython 4.1+ 並使用 pythonw 執行,否則可能無法顯示視窗。
  • 長時間操作(如大檔讀寫)應放入執行緒,避免阻塞 UI;完成後用 wx.CallAfter 更新介面。
  • 儲存時建議先寫入暫存檔再 os.replace,防止斷電導致檔案損壞。

這個範例雖然簡單,但涵蓋了 wxPython 開發的核心流程:建立視窗 → 佈局元件 → 綁定事件 → 處理邏輯。以此為基礎,即可逐步擴充為功能完整的桌面應用程式。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved