Problem with custom undo/redo in TextCtrl

Hey all, it’s me again.
I need some help debugging some of my code. Here’s how it’s set up-

···

class MainWin(wx.Frame):
def init(self, parent, id, title):

    self.undoList = [""]
    self.redoList = [""]

    edit = wx.Menu()
    e_undo = wx.MenuItem(edit, wx.ID_UNDO, '&Undo\tCtrl+Z', 'Undo your changes')

    e_undo.SetBitmap(self.undoImage)
    edit.AppendItem(e_undo)
   
    e_redo = wx.MenuItem(edit, wx.ID_REDO, '&Redo\tCtrl+Y', 'Redo your changes')
    e_redo.SetBitmap(

self.redoImage)
edit.AppendItem(e_redo)
menubar.Append(edit, ‘&Edit’)

    self.code = wx.TextCtrl(self, ID_TEXTBOX, size=(200, 130), style=wx.TE_MULTILINE)
    self.code.SetFont

(wx.Font(11, wx.FONTFAMILY_MODERN, wx.NORMAL, wx.NORMAL))
self.Bind(wx.EVT_UPDATE_UI, self.LookAtCode, id=ID_TEXTBOX)

    self.s = self.code.GetValue()

def LookAtCode(self, event):
    if self.s != self.code.GetValue():
        codeArray = [self.code.GetValue()]
        self.undoList = self.undoList + codeArray
        self.s = self.code.GetValue()

def OnUndo(self, event):
    if len(self.undoList) > 1:
        undoLen = len(self.undoList)
        undoLen = undoLen-1
        undoItem = self.undoList[undoLen]
        codeVal = self.code.GetValue()
        codeValArray = [codeVal]

        self.redoList = self.redoList + codeValArray
        print self.undoList[1]
        self.code.SetValue(undoItem)
    else:
        cantundo = wx.MessageDialog(None, 'Can\'t undo', 'Can\'t undo', wx.OK | wx.ICON_INFORMATION)
        cantundo.ShowModal()

def OnRedo(self, event):
    if len(self.redoList) > 1:
        redoLen = len(self.redoList)
        redoLen = redoLen-1
        redoItem = self.redoList[undolen]
        codeVal = self.code.GetValue()
        codeValArray = [codeVal]
        self.undoList = self.undoList + codeValArray
        self.code.SetValue

(redoItem)
else:
cantundo = wx.MessageDialog(None, ‘Can’t redo’, ‘Can’t redo’, wx.OK | wx.ICON_INFORMATION)
cantundo.ShowModal()

class MyApp(wx.App
):
def OnInit(self):
MySplash = MySplashScreen()
MySplash.Show()
return True

app = MyApp(redirect=True, filename = “error.log”)
app.MainLoop()


Sorry for the hefty code snippet, but I can’t quite figure out what’s wrong (and I wanted to show the framework of how this works).
I know that the problem is in OnUndo
and OnRedo, but I can’t figure out where it is.

When I click undo, It does nothing except move the cursor to the start of the file (on linux, at least).

Sorry for the huge example, again!

Thanks so much for any help.

Hey all, it's me again.
I need some help debugging some of my code. Here's how it's set up-
______________________________________________________________________________
class MainWin(wx.Frame):
    def __init__(self, parent, id, title):
        self.undoList = [""]
        self.redoList = [""]

        edit = wx.Menu()
        e_undo = wx.MenuItem(edit, wx.ID_UNDO, '&Undo\tCtrl+Z', 'Undo your
changes')
        e_undo.SetBitmap(self.undoImage)
        edit.AppendItem(e_undo)

        e_redo = wx.MenuItem(edit, wx.ID_REDO, '&Redo\tCtrl+Y', 'Redo your
changes')
        e_redo.SetBitmap( self.redoImage)
        edit.AppendItem(e_redo)
        menubar.Append(edit, '&Edit')

        self.code = wx.TextCtrl(self, ID_TEXTBOX, size=(200, 130),
style=wx.TE_MULTILINE)
        self.code.SetFont (wx.Font(11, wx.FONTFAMILY_MODERN, wx.NORMAL,
wx.NORMAL))
        self.Bind(wx.EVT_UPDATE_UI, self.LookAtCode, id=ID_TEXTBOX)

        self.s = self.code.GetValue()

    def LookAtCode(self, event):
        if self.s != self.code.GetValue():
            codeArray = [self.code.GetValue()]
            self.undoList = self.undoList + codeArray
            self.s = self.code.GetValue()

    def OnUndo(self, event):
         if len(self.undoList) > 1:
            undoLen = len(self.undoList)
            undoLen = undoLen-1
            undoItem = self.undoList[undoLen]
            codeVal = self.code.GetValue()
            codeValArray = [codeVal]
            self.redoList = self.redoList + codeValArray
            print self.undoList[1]
            self.code.SetValue(undoItem)
        else:
            cantundo = wx.MessageDialog(None, 'Can\'t undo', 'Can\'t undo',
wx.OK | wx.ICON_INFORMATION)
            cantundo.ShowModal()

    def OnRedo(self, event):
        if len(self.redoList) > 1:
            redoLen = len(self.redoList)
            redoLen = redoLen-1
             redoItem = self.redoList[undolen]
            codeVal = self.code.GetValue()
            codeValArray = [codeVal]
            self.undoList = self.undoList + codeValArray
            self.code.SetValue (redoItem)
        else:
            cantundo = wx.MessageDialog(None, 'Can\'t redo', 'Can\'t redo',
wx.OK | wx.ICON_INFORMATION)
            cantundo.ShowModal()

class MyApp(wx.App ):
    def OnInit(self):
        MySplash = MySplashScreen()
        MySplash.Show()
        return True

app = MyApp(redirect=True, filename = "error.log")
app.MainLoop()
______________________________________________________________________________
Sorry for the hefty code snippet, but I can't quite figure out what's wrong
(and I wanted to show the framework of how this works).
I know that the problem is in OnUndo and OnRedo, but I can't figure out
where it is.

When I click undo, It does nothing except move the cursor to the start of
the file (on linux, at least).

Sorry for the huge example, again!

It's not so big, but it doesn't work. Please make sure that when you
paste a code snippet like this, that it actually runs and demonstrates
your problem.

···

On 10/13/07, Trey K <trey.wxpython@gmail.com> wrote:

Thanks so much for any help.

Trey K wrote:

Hey all, it's me again.
I need some help debugging some of my code. Here's how it's set up-

Sorry for the hefty code snippet, but I can't quite figure out what's wrong (and I wanted to show the framework of how this works).
I know that the problem is in OnUndo and OnRedo, but I can't figure out where it is.

Do you Bind() the EVT_MENU events for the undo/redo items somewhere?

When I click undo, It does nothing except move the cursor to the start of the file (on linux, at least).

That probably happens because you are setting the value to the same one it had before. My guess is that the last item in the undoList is always the current value, so to get the previous value you need to back up one more item.

BTW, using EVT_TEXT might be a better way to get the old values instead of EVT_UPDATE_UI. The EVT_TEXT handler will only be called when the value actually changes instead of every time there are idle events.

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!

Hey all, thanks for the help, but I’ve figured it out.
It just took a while…
my main problem was that when I changed the code using undo, the OnLookAtCode function picked it up, thinking it was user input, and added it back to the undoList.

Sorry!

I got your code to work, but if I "dock" edit menu with menubar it does NOT
work. Any ideas?
RR

import wx
class MainWin(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, -1, "Frame Subclass", size=(600,400))
        self.undoList = [""]
        self.redoList = [""]
        panel=wx.Panel(self, -1)
        menubar = wx.MenuBar()
        #self.SetMenuBar(menubar)
        edit = wx.Menu()
        e_undo = wx.MenuItem(edit, wx.ID_UNDO, '&Undo\tCtrl+Z', 'Undo your
changes')
        edit.AppendItem(e_undo)
        
        e_redo = wx.MenuItem(edit, wx.ID_REDO, '&Redo\tCtrl+Y', 'Redo your
changes')
        edit.AppendItem(e_redo)
        
        menubar.Append(edit, '&Edit')
        self.code = wx.TextCtrl(panel, wx.ID_ANY, size=(600, 400),
style=wx.TE_MULTILINE|wx.TE_RICH2)
        self.code.SetFont (wx.Font(11, wx.FONTFAMILY_MODERN, wx.NORMAL,
wx.NORMAL))
        self.Bind(wx.EVT_UPDATE_UI, self.LookAtCode, self.code)
        self.Bind(wx.EVT_TEXT, self.OnUndo, e_undo)
        self.Bind(wx.EVT_TEXT, self.OnRedo, e_redo)
        self.s = self.code.GetValue()
        #self.Layout()

    def LookAtCode(self, event):
        if self.s != self.code.GetValue():
            codeArray = [self.code.GetValue()]
            self.undoList = self.undoList + codeArray
            self.s = self.code.GetValue()

    def OnUndo(self, event):
        if len(self.undoList) > 1:
            undoLen = len(self.undoList)
            undoLen = undoLen-1
            undoItem = self.undoList[undoLen]
            codeVal = self.code.GetValue()
            codeValArray = [codeVal]
            self.redoList = self.redoList + codeValArray
            print self.undoList[1]
            self.code.SetValue(undoItem)
        else:
            cantundo = wx.MessageDialog(None, 'Can\'t undo', 'Can\'t undo',
wx.OK | wx.ICON_INFORMATION)
            cantundo.ShowModal()

    def OnRedo(self, event):
        if len(self.redoList) > 1:
            redoLen = len(self.redoList)
            redoLen = redoLen-1
            redoItem = self.redoList[undolen]
            codeVal = self.code.GetValue()
            codeValArray = [codeVal]
            self.undoList = self.undoList + codeValArray
            self.code.SetValue (redoItem)
        else:
            cantredo = wx.MessageDialog(None, 'Can\'t redo', 'Can\'t redo',
wx.OK | wx.ICON_INFORMATION)
            cantredo.ShowModal()

class MyApp(wx.App ):
    def OnInit(self):
        wx.InitAllImageHandlers()
        win_id= wx.NewId()
        frame = MainWin()
        self.SetTopWindow(frame)
        frame.Show(True)
        return True
        
app = MyApp(False)
app.MainLoop()

···

--
View this message in context: http://wxpython-users.1045709.n5.nabble.com/Problem-with-custom-undo-redo-in-TextCtrl-tp2356247p5717053.html
Sent from the wxPython-users mailing list archive at Nabble.com.

RobinLRandall@gmail.com wrote:

I got your code to work, but if I "dock" edit menu with menubar it does NOT
work. Any ideas?

You are not binding your event handler methods to the EVT_MENU event.

···

--
Robin Dunn
Software Craftsman