コード例 #1
0
class smallAppFrame(wx.Frame):
    """ Derive a new class of wx.Frame. """
    overviewText = "wxPython Overview"

    def __init__(self, parent, id, title):
        # --- a basic window frame/form
        wx.Frame.__init__(self,
                          parent=None,
                          id=-1,
                          title=APP_NAME + " - Developed in wxPython/AHK",
                          pos=wx.Point(0, 0),
                          size=wx.Size(640, 480),
                          name='',
                          style=wx.DEFAULT_FRAME_STYLE)

        if (len(sys.argv)) == 2:
            self.Bind(wx.EVT_ACTIVATE, self.OnFileOpenDirect)
        #   wx.EVT_ACTIVATE(self,  self.OnFileOpenDirect)  # same

        self.printer = Printer(self)
        self.SetMinSize((640, 480))
        # --- real windows programs have icons, so here's ours!
        try:  # - don't sweat it if it doesn't load
            self.SetIcon(wx.Icon("SmallEditor.ico", wx.BITMAP_TYPE_ICO))
        finally:
            pass

        self.codePage = None
        self.finddlg = None

        # --- add a menu, first build the menus (with accelerators)
        self.BuildMenuBar()

        self.finddata = wx.FindReplaceData()
        self.finddata.SetFlags(wx.FR_DOWN)
        #  Not needed!, just put them in text form after tab in menu item!
        # --- add accelerators to the menus
        #self.SetAcceleratorTable(wx.AcceleratorTable([(wx.ACCEL_CTRL, ord('O'), ID_OPEN),
        #                          (wx.ACCEL_ALT, ord('Q'), ID_EXIT)]))

        # --- add a statusBar (with date/time panel)
        sb = self.CreateStatusBar(3)
        sb.SetStatusWidths([-1, 65, 160])
        sb.PushStatusText("Ready", SB_INFO)
        # --- set up a timer to update the date/time (every 5 seconds)
        self.timer = wx.PyTimer(self.Notify)
        self.timer.Start(5000)
        self.Notify()  # - call it once right away

        # --- add a control (a RichTextBox) & trap KEY_DOWN event
        self.rtb = wx.TextCtrl(self,
                               ID_RTB,
                               size=wx.Size(400 * 2, 200 * 2),
                               style=wx.TE_MULTILINE | wx.TE_RICH2)
        ### - NOTE: binds to the control itself!
        wx.EVT_KEY_UP(self.rtb, self.OnRtbKeyUp)

        # --- need to add a sizer for the control - yuck!
        self.sizer = wx.BoxSizer(wx.VERTICAL)
        # self.sizer.SetMinSize(200,400)
        self.sizer.Add(self.rtb, 1, wx.EXPAND)
        # --- now add it to the frame (at least this auto-sizes the control!)
        self.SetSizer(self.sizer)
        self.SetAutoLayout(True)
        self.sizer.SetSizeHints(self)

        # Add some Unicode (Chinese!)
        if not wx.USE_UNICODE:
            self.AddLine(self.sizer)
            self.AddText(
                self.sizer,
                "Sorry, this wxPython was not built with Unicode support.",
                font=wx.Font(12, wx.SWISS, wx.NORMAL, wx.BOLD))
            self.AddLine(self.sizer)
        else:
            f = self.GetFont()
            font = wx.Font(14, f.GetFamily(), f.GetStyle(), wx.BOLD, False,
                           f.GetFaceName(), f.GetEncoding())
            self.AddLine(self.sizer)
            self.AddText(self.sizer, chi_uni[0], chi_uni[1], 'Chinese:', font)
            self.AddLine(self.sizer)

        # --- initialize other settings
        self.dirName = ""
        self.fileName = ""

        # - this is ugly, but there's no static available
        #   once we build a class for RTB, move this there
        self.oldPos = -1
        self.ShowPos()

        # --- finally - show it!
        self.Show(True)

    def BuildMenuBar(self):

        self.mainmenu = wx.MenuBar()
        # file menu
        fileMenu = wx.Menu()

        fileNew = fileMenu.Append(-1, "&New\tCtrl+N", "Create a new file")
        #wx.EVT_MENU(self, ID_NEW, self.OnFileNew) ## same as following
        self.Bind(wx.EVT_MENU, self.OnFileNew, fileNew)

        # check if the application opens with an argument
        fileOpen = fileMenu.Append(-1, "&Open\tCtrl+O",
                                   "Open an existing file")
        self.Bind(wx.EVT_MENU, self.OnFileOpen, fileOpen)

        fileSave = fileMenu.Append(-1, "&Save\tCtrl+S", "Save the active file")
        self.Bind(wx.EVT_MENU, self.OnFileSave, fileSave)

        fileSaveAs = fileMenu.Append(-1, "&Save As...",
                                     "Save the active file with a new name")
        self.Bind(wx.EVT_MENU, self.OnFileSaveAs, fileSaveAs)

        filePrint = fileMenu.Append(-1, "&Print\tCtrl+P",
                                    "Print the active file")
        self.Bind(wx.EVT_MENU, self.OnFilePrint, filePrint)
        """
        pnl = wx.Panel(self)
        self.pnl = pnl        
        # Set up a log window
        self.log = wx.TextCtrl(pnl, -1,
                              style = wx.TE_MULTILINE|wx.TE_READONLY|wx.HSCROLL)
        """

        fileExit = fileMenu.Append(-1, "E&xit\tAlt+Q", "Exit the program")
        self.Bind(wx.EVT_MENU, self.OnFileExit, fileExit)

        # edit menu
        editMenu = wx.Menu()
        """
        # so ben ik Find icoontje kwijt!
        findItem = editMenu.Append(-1, '&Find\tCtrl-F', 'Find in opened text')
        findItem.SetBitmap(images.catalog['find'].GetBitmap())

        if 'wxMac' not in wx.PlatformInfo:
            findNextItem = editMenu.Append(-1, 'Find &Next\tF3', 'Find Next')
        else:
            findNextItem = editMenu.Append(-1, 'Find &Next\tCtrl-G', 'Find Next')
        findNextItem.SetBitmap(images.catalog['findnext'].GetBitmap())
        """
        findItem = wx.MenuItem(editMenu, -1, '&Find\tCtrl+F',
                               'Find in the opened text')
        findItem.SetBitmap(images.catalog['find'].GetBitmap())
        if 'wxMac' not in wx.PlatformInfo:
            findNextItem = wx.MenuItem(editMenu, -1, 'Find &Next\tF3',
                                       'Find Next')
        else:
            findNextItem = wx.MenuItem(editMenu, -1, 'Find &Next\tCtrl+G',
                                       'Find Next')
        findNextItem.SetBitmap(images.catalog['findnext'].GetBitmap())
        # GetBitmap = wx.lib.editor.images.GetBitmap  # in wxPython\lib\editor\images.py
        editMenu.AppendItem(findItem)
        editMenu.AppendItem(findNextItem)
        editMenu.AppendSeparator()
        #
        self.Bind(wx.EVT_MENU, self.OnHelpFind, findItem)
        self.Bind(wx.EVT_MENU, self.OnFindNext, findNextItem)
        self.Bind(wx.EVT_FIND, self.OnFind)
        self.Bind(wx.EVT_FIND_NEXT, self.OnFind)
        self.Bind(wx.EVT_FIND_CLOSE, self.OnFindClose)
        self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateFindItems, findItem)
        self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateFindItems, findNextItem)
        # Tool menu
        toolMenu = wx.Menu()
        easyMemo = toolMenu.Append(-1, "&Easy Memo\tCtrl+M", "Easy Memo")
        self.Bind(wx.EVT_MENU, self.OnEasyMemo, easyMemo)
        easyMemoP = toolMenu.Append(-1, "&Open Easy Memo\tCtrl+E",
                                    "Open Easy Memo")
        self.Bind(wx.EVT_MENU, self.OnEasyMemoOpen, easyMemoP)

        # Help bar
        helpMenu = wx.Menu()
        #        helpMenu.Append(ID_ABOUT, "&About SmallEditor", "Display information about the program")
        #        wx.EVT_MENU(self, ID_ABOUT, self.OnHelpAbout)
        # the following does the same!
        helpItem = helpMenu.Append(-1, '&About SmallEditor',
                                   'wxPython RULES!!!')
        self.Bind(wx.EVT_MENU, self.OnHelpAbout, helpItem)

        # --- now add them to a menubar & attach it to the frame
        menuBar = wx.MenuBar()
        menuBar.Append(fileMenu, "&File")
        menuBar.Append(editMenu, "&Edit")
        menuBar.Append(toolMenu, "&Tool")
        menuBar.Append(helpMenu, "&Help")
        self.SetMenuBar(menuBar)

#---------------------------------------

    def __del__(self):
        """ Class delete event: don't leave timer hanging around! """
        self.timer.stop()
        del self.timer

#---------------------------------------

    def Notify(self):
        """ Timer event """
        t = time.localtime(time.time())
        st = time.strftime(" %b-%d-%Y  %I:%M %p", t)
        # --- could also use self.sb.SetStatusText
        self.SetStatusText(st, SB_DATETIME)
#--------------------------------------

    def OnFilePrint(self, e):
        """ File|FilePrint event """
        docTitle = os.path.join(self.dirName, self.fileName)
        self.printer.Print(self.rtb.GetValue(), docTitle)

#--------------------------------------

    def OnEasyMemo(self, e):
        """ Tool/EasyMemo event """
        # os.system("Diary.exe &")
        subprocess.Popen(["Diary.exe"])

#--------------------------------------

    def OnEasyMemoOpen(self, e):
        """ Tool/EasyMemo event Open """

        self.OnFileOpenDirect(e, "diary.txt")

#---------------------------------------

    def OnFileExit(self, e):
        """ File|Exit event """
        if (self.rtb.IsModified()):
            dlg = wx.MessageDialog(
                self, "would like to save the file?", "Save file confirmation",
                wx.YES_NO | wx.NO_DEFAULT | wx.CANCEL | wx.ICON_INFORMATION)

            result = dlg.ShowModal()
            if (result == wx.ID_YES):
                ### - Use the OnFileSave to save the file
                if self.OnFileSave(e):
                    self.SetTitle(APP_NAME + " - [" + self.fileName + "]")
                dlg.Destroy()
                self.Close(True)

            elif (result == wx.ID_NO):  # NO
                dlg.Destroy()
                self.Close(True)

            elif (result == wx.ID_CANCEL):  # Cancel
                dlg.Destroy()
            else:
                print "Never should be here!!!"

        else:  # nothing changed
            self.Close(True)

#---------------------------------------

    def OnFileNew(self, e):
        """ File|New event - Clear rtb. """
        self.fileName = ""
        self.dirName = ""
        self.rtb.SetValue("")
        self.PushStatusText("Starting new file", SB_INFO)
        self.ShowPos()

#---------------------------------------

    def OnFileOpen(self, e):
        """ File|Open event - Open dialog box. """
        dlg = wx.FileDialog(self, "Open", self.dirName, self.fileName,
                            "Text Files (*.txt)|*.txt|All Files|*.*", wx.OPEN)
        if (dlg.ShowModal() == wx.ID_OK):
            self.fileName = dlg.GetFilename()
            self.dirName = dlg.GetDirectory()

            ## - this will read in Unicode files (since I'm using Unicode wx.Python)
            ## - if NO-BREAK spaces (hex A0) in the text encounterd, it will only show blank!
            ## how to solve???
            if self.rtb.LoadFile(os.path.join(self.dirName, self.fileName)):
                #    print "self.rtb", self.rtb
                self.SetStatusText(
                    "Opened file: " + str(self.rtb.GetLastPosition()) +
                    " characters.", SB_INFO)
                self.ShowPos()
            else:
                self.SetStatusText("Error in opening file.", SB_INFO)

            ### - but we want just plain ASCII files, so:
            """
            try:
                f = file(os.path.join(self.dirName, self.fileName), 'r')
                self.rtb.SetValue(f.read())
                self.SetTitle(APP_NAME + " - [" + self.fileName + "]")
                self.SetStatusText("Opened file: " + str(self.rtb.GetLastPosition()) +
                                   " characters.", SB_INFO)
                self.ShowPos()
                f.close()
            except:
                self.PushStatusText("Error in opening file.", SB_INFO)
            """
        dlg.Destroy()

#---------------------------------------

    def OnFileOpenDirect(self, e, fileName=None):
        """ File|Open event Direct from arg. is not Unicode compatible """
        if fileName == None:
            #self.fileName = sys.argv[1].decode('utf-8') #not yet working for chinese
            #self.fileName = sys.argv[1].decode(sys.getfilesystemencoding()) #not yet working for chinese
            self.fileName = sys.argv[1]
        else:
            self.fileName = fileName

        if self.rtb.LoadFile(self.fileName):
            self.SetStatusText(
                "Opened file: " + str(self.rtb.GetLastPosition()) +
                " characters.", SB_INFO)
            self.ShowPos()
        else:
            self.SetStatusText("Error in opening file.", SB_INFO)

        self.rtb.SetFocus()  # necessary!!!

    #  e.Skip()
#---------------------------------------

    def OnFileSave(self, e):
        """ File|Save event - Just Save it if it's got a name. """
        if (len(sys.argv)) == 2:  #for direct open file
            self.fileName = sys.argv[1]

        #if (self.fileName != "") and (self.dirName != ""): # dirName is not necessary to check (for direct open is not easy)
        if (self.fileName != ""):
            # try to save with Unicode text in the file
            if self.rtb.SaveFile(os.path.join(self.dirName, self.fileName)):
                self.SetStatusText(
                    "Saved file: " + str(self.rtb.GetLastPosition()) +
                    " characters.", SB_INFO)
            else:
                self.SetStatusText("Error in saving file (Unicode).", SB_INFO)
            """
            try: # only valid for Ascii
               # The following does not work for Unicode 
               # f = file(os.path.join(self.dirName, self.fileName), 'w','utf-8')
                f = file(os.path.join(self.dirName, self.fileName), 'w')
                f.write(self.rtb.GetValue())
                self.PushStatusText("Saved file: " + str(self.rtb.GetLastPosition()) +
                                    " characters.", SB_INFO)
                f.close()
                return True
            except:
                self.PushStatusText("Error in saving file: file will be empty! Please remove the
                    last changes and save it again!", SB_INFO)
                # file is empty due to the error!
                return False
            """
        else:
            ### - If no name yet, then use the OnFileSaveAs to get name/directory
            return self.OnFileSaveAs(e)

#--------------------------------------

    def OnFileSaveAs(self, e):
        """ File|SaveAs event - Prompt for File Name. """
        ret = False
        dlg = wx.FileDialog(self, "Save As", self.dirName, self.fileName,
                            "Text Files (*.txt)|*.txt|All Files|*.*", wx.SAVE)
        if (dlg.ShowModal() == wx.ID_OK):
            self.fileName = dlg.GetFilename()
            self.dirName = dlg.GetDirectory()
            ## should check if the file exists
            if os.path.exists(os.path.join(self.dirName, self.fileName)):
                dlg = wx.MessageDialog(
                    self, "File already exists! Do you want to replace it?",
                    "Save as file confirmation", wx.YES_NO | wx.NO_DEFAULT
                    | wx.CANCEL | wx.ICON_INFORMATION)

                result = dlg.ShowModal()
                if (result == wx.ID_YES):

                    ### - Use the OnFileSave to save the file
                    if self.OnFileSave(e):
                        self.SetTitle(APP_NAME + " - [" + self.fileName + "]")
                        ret = True
            else:  # file not exists
                ### - Use the OnFileSave to save the file
                if self.OnFileSave(e):
                    self.SetTitle(APP_NAME + " - [" + self.fileName + "]")
                    ret = True

        dlg.Destroy()

        return ret

#--------------------------------------

    def OnHelpFind(self, event):
        if self.finddlg != None:
            return

        self.finddlg = wx.FindReplaceDialog(
            self, self.finddata, "Find", wx.FR_NOMATCHCASE | wx.FR_NOWHOLEWORD)
        self.finddlg.Show(True)

    def OnUpdateFindItems(self, evt):
        evt.Enable(self.finddlg == None)

#---------------------------------------------

    def OnFind(self, event):
        # these are original
        #  editor = self.codePage.editor
        #  end = editor.GetLastPosition()
        end = self.rtb.GetLastPosition()
        textstring = self.rtb.GetRange(0, end).lower()
        findstring = self.finddata.GetFindString().lower()
        backward = not (self.finddata.GetFlags() & wx.FR_DOWN)
        if backward:
            start = self.rtb.GetSelection()[0]
            loc = textstring.rfind(findstring, 0, start)
        else:
            start = self.rtb.GetSelection()[1]
            loc = textstring.find(findstring, start)
        if loc == -1 and start != 0:
            # string not found, start at beginning
            if backward:
                start = end
                loc = textstring.rfind(findstring, 0, start)
            else:
                start = 0
                loc = textstring.find(findstring, start)
        if loc == -1:
            dlg = wx.MessageDialog(self, 'Find String Not Found',
                                   'Find String Not Found in Demo File',
                                   wx.OK | wx.ICON_INFORMATION)
            dlg.ShowModal()
            dlg.Destroy()
        if self.finddlg:
            if loc == -1:
                self.finddlg.SetFocus()
                return
            else:
                self.finddlg.Destroy()
                self.finddlg = None

        self.rtb.SetFocus()  # Needed for OpenFileDirect!

        self.rtb.ShowPosition(loc)
        self.rtb.SetSelection(loc, loc + len(findstring))

    def OnFindNext(self, event):
        if self.finddata.GetFindString():
            self.OnFind(event)
        else:
            self.OnHelpFind(event)

    def OnFindClose(self, event):
        event.GetDialog().Destroy()
        self.finddlg = None

#---------------------------------------

    def OnShowFind(self, e):
        """ Find|Something event """
        data = wx.FindReplaceData()
        data.SetFlags(wx.FR_DOWN)  # search down by default
        #
        #        #data.SetReplaceString(self._replaceString)
        dlg = wx.FindReplaceDialog(self, data, "Find")
        dlg.data = data  # save a reference to it...
        dlg.Show(True)
#---------------------------------------

    def OnHelpAbout(self, e):
        """ Help|About event """
        title = self.GetTitle()
        title1 = title + "\nBugs found? Please contact: [email protected]"
        d = wx.MessageDialog(self, "About " + title1, title,
                             wx.ICON_INFORMATION | wx.OK)
        d.ShowModal()
        d.Destroy()

#---------------------------------------

    def OnRtbKeyUp(self, e):
        """ Update Row/Col indicator based on position """
        self.ShowPos()
        e.Skip()

#---------------------------------------

    def ShowPos(self):
        """ Update Row/Col indicator """
        (bPos, ePos) = self.rtb.GetSelection()
        if (self.oldPos != ePos):
            (c, r) = self.rtb.PositionToXY(ePos)
            self.SetStatusText(" " + str((r + 1, c + 1)), SB_ROWCOL)
        self.oldPos = ePos

#---------------------------------------

    def AddLine(self, sizer):
        sizer.Add(wx.StaticLine(self, -1), 0, wx.EXPAND)

    def AddText(self, sizer, text1, text2='', lang='', font=None):
        # create some controls
        lang = wx.StaticText(self, -1, lang)
        text1 = wx.StaticText(self, -1, text1)
        text2 = wx.StaticText(self, -1, text2, style=wx.ALIGN_RIGHT)
        if font is not None:
            text1.SetFont(font)

        # put them in a sizer
        row = wx.BoxSizer(wx.HORIZONTAL)
        row.Add(lang)
        row.Add((15, 10))
        row.Add(text1, 1, wx.EXPAND)
        row.Add(text2)

        # put the row in the main sizer
        sizer.Add(row, 0, wx.EXPAND | wx.ALL, 5)