1

I am making a simple text editor in wxpython. I would like it to be able to edit code such as python, and as such I would like to have it highlight the text in a similar manner to IDLE or Notepad++. I know how I would highlight it, but I would like the best way of running it. I don't know if it is possible but what I would really like is to run whenever a key is pressed, and not on a loop checking if it is pressed, so as to save on processing.

import wx
class MainWindow(wx.Frame):
    def __init__(self, parent, title):
        wx.Frame.__init__(self, parent, title=title, size=(500,600))
        style = wx.TE_MULTILINE|wx.BORDER_SUNKEN|wx.TE_RICH2
        self.status_area = wx.TextCtrl(self, -1,
                                   pos=(10, 270),style=style,
                                   size=(380,150))
        self.status_area.AppendText("Type in your wonderfull code here.")
        fg = wx.Colour(200,80,100)
        at = wx.TextAttr(fg)
        self.status_area.SetStyle(3, 5, at)
        self.CreateStatusBar() # A Statusbar in the bottom of the window

        # Setting up the menu.
        filemenu= wx.Menu()

        filemenu.Append(wx.ID_ABOUT, "&About","Use to edit python code")
        filemenu.AppendSeparator()
        filemenu.Append(wx.ID_EXIT,"&Exit"," Terminate the program")

        # Creating the menubar.
        menuBar = wx.MenuBar()
        menuBar.Append(filemenu,"&File") # Adding the "filemenu" to the MenuBar
        self.SetMenuBar(menuBar)  # Adding the MenuBar to the Frame content.
        self.Show(True)


app = wx.App(False)
frame = MainWindow(None, "Python Coder")
app.MainLoop()

If a loop is needed what would be the best way to make it loop, with a while loop, or a

def Loop():
    <code>
    Loop()

My new code with the added bind:

import wx

class MainWindow(wx.Frame):
    def __init__(self, parent, title):
        wx.Frame.__init__(self, parent, title=title, size=(500,600))
        style = wx.TE_MULTILINE|wx.BORDER_SUNKEN|wx.TE_RICH2
        self.status_area = wx.TextCtrl(self, -1,
                                   pos=(10, 270),style=style,
                                   size=(380,150))
        #settup the syntax highlighting to run on a key press
        self.Bind(wx.EVT_CHAR, self.onKeyPress, self.status_area)
        self.status_area.AppendText("Type in your wonderfull code here.")
        fg = wx.Colour(200,80,100)
        at = wx.TextAttr(fg)
        self.status_area.SetStyle(3, 5, at)
        self.CreateStatusBar() # A Statusbar in the bottom of the window

        # Setting up the menu.
        filemenu= wx.Menu()

        filemenu.Append(wx.ID_ABOUT, "&About","Use to edit python code")
        filemenu.AppendSeparator()
        filemenu.Append(wx.ID_EXIT,"&Exit"," Terminate the program")

        # Creating the menubar.
        menuBar = wx.MenuBar()
        menuBar.Append(filemenu,"&File") # Adding the "filemenu" to the MenuBar
        self.SetMenuBar(menuBar)  # Adding the MenuBar to the Frame content.
        self.Show(True)


    def onKeyPress (self, event):
        print "KEY PRESSED"
        kc = event.GetKeyCode()
        if kc == WXK_SPACE or kc == WXK_RETURN:
            Line = self.status_area.GetValue()
            print Line
app = wx.App(False)
frame = MainWindow(None, "Python Coder")
app.MainLoop()
6
  • What would you like to run when a key is pressed? The highlighting? Commented Aug 16, 2011 at 20:31
  • I want it to highlight key words in the string so that it highlights python code. So "if" would be in purple text and different functions would also be colored. I know how to make my code highlight the text if a word is typed in. I want it to run through a block of code if the text in the textctrl is changed. So if I had typed in the text box of my window, "I like apple" and I changed it it "I like apple pie" it would run a block of code 4 times because of each key press in " pie". Commented Aug 16, 2011 at 21:10
  • Well one way to reduce that is probably to run your highlighting code only when the spacebar or enter keys are pressed. Since that would indicate that a word or line is complete. Commented Aug 16, 2011 at 21:27
  • Well that sounds good, but how do I tell if the space bar or enter key are pressed when typing into the textctrl. Commented Aug 16, 2011 at 21:29
  • Don't you currently have your highlight code running when the key is pressed in the text control? Just check the key code for the event. If it is the key code corresponding to space or enter, then run your highlighing, else pass. Commented Aug 16, 2011 at 21:34

2 Answers 2

1

In your MainWindow __init__ function add this

self.Bind(wx.EVT_CHAR, self.onKeyPress, self.status_area)

then define onKeyPress in MainWindow

def onKeyPress (self, event):
    kc = event.GetKeyCode()
    if kc == WXK_SPACE or kc == WXK_RETURN:
        #Run your highlighting code here

Come to think of it, this might not be the most efficient way of doing code highlighting. Let me look this up. But in the meantime you can try this.

Edit: Take a look at this - StyledTextCtrl . I think its more along the lines of what you need.

Sign up to request clarification or add additional context in comments.

8 Comments

I tried what you gave me but when I was debugging it, I couldn't get it to do anything.
I know how to color text, I just need it to run when a key on the keyboard is pressed, that is what your code looks like it does, but I put "print "test"" where you have #Run your highlighting code here and it never printed when I was typing. The styledTextCtrl looks too complex to me for what I am doing.
put debugging in the onKeyPress. print "at the start" then print "value of keycode %d" % kc after you get keycode
I did that it also doesn't print anything or give me any indication it runs.
Paste the new code to your question. And paste all of it. With the key press and everything.
|
0

I solved this when I faced the same issue by creating a custom event.

First, I created a subclass of the TextCtrl, so I had a place in code to raise/post the custom event from:

import  wx.lib.newevent
(OnChangeEvent, EVT_VALUE_CHANGED) = wx.lib.newevent.NewEvent()

class TextBox(wx.TextCtrl):
    old_value = u''

    def __init__(self,*args,**kwargs):
        wx.TextCtrl.__init__(self,*args,**kwargs)
        self.Bind(wx.EVT_SET_FOCUS, self.gotFocus) # used to set old value
        self.Bind(wx.EVT_KILL_FOCUS, self.lostFocus) # used to get new value

    def gotFocus(self, evt):
        evt.Skip()
        self.old_value = self.GetValue()

def lostFocus(self, evt):
    evt.Skip()
    if self.GetValue() != self.old_value:
        evt = OnChangeEvent(oldValue=self.old_value, newValue=self.GetValue())
        wx.PostEvent(self, evt)

Now, in my frame's code, here is a snippet of me Binding the event, and using it.

summ_text_ctrl = TextBox(self, -1, size=(400, -1))
summ_text_ctrl.Bind(EVT_VALUE_CHANGED, self.onTextChanged)

def OnTextChanged(self, evt):
    evt.Skip()
    print('old Value: %s' % evt.oldValue )
    print('new Value: %s' % evt.newValue )

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.