pythonuser-interfaceevent-handlingwxpythontextctrl

wxPython - Process input from one TextCtrl and send output to another TextCtrl?


I am sure this is a terribly stupid question. But I've used python for a year, i went through "Learn Python the hard way", I went through the Zetcode WxPython Tutorial, I looked through the WXPython TextCtrl Demo, and I've spent 2 days google searching for the answer to this seemingly simple question and I'm not figuring it out.

All I am trying to do is make a very simple test game where I have an input box, where the user types something like "get pineapple", then presses [ENTER], and send this phrase to a function I will make that processes the request, then sends the output to an output box that says something like "you cannot get the pineapple." Since I have coded lots of things at the office in python, and have coded full-featured financial models and games with VBA, I was sure this would be easy but it seems impossible. And WXPython is the obstacle.

If i put a string variable under "frame" or "panel" or under the class objects for TC1 or TC2, then they're treated as utterly alien and empty in the MainLoop, no matter where i put the variable it's not recognized. It seems impossible to use the same variable when making a function under the TextCtrl1 and TextCtrl2, or vice versa. I think I have to do something wwith "event.skip", or maybe make layers of passing things deep into the layers of WXPython and then pulling them all the way back out again, but I am not sure where to put it or how to do this.

Above all please tell me how I can figure out the answers to questions like this myself! I feel humiliated just asking it since it seems like it must be so easy, because if it were hard it would exist and be answered on this Q&A website.

I have all the GUI skeleton looking good, I have the "Enter" keypress event working, i have my multimedia set up and working fine, I know how i will be setting up my objects, I just need to be pointed in the right direction here. Even if you could just show me how to take input from one textctrl, and pass it unchanged to the output read-only textctrl, that would be perfect and i could figure out the rest. I could post the rest of my code here but I read somewhere that was bad manners.

EDIT: I am pasting the code here at the request of a would-be answerer.

Thank you in advance.

import wx
from random import randint
from pygame import mixer # Load the required library


mixer.init()
mixer.music.load('sog.ogg')
mixer.music.set_volume(1.0)
mixer.music.play()

RandomSound1 = mixer.Sound('CritHit.wav')
RandomSound2 = mixer.Sound('swallow2.wav')
RandomSound3 = mixer.Sound('thunder2.wav')

#instantiate class

class MusTogButt(wx.Button):

    def __init__(self, *args, **kw):
        super(MusTogButt, self).__init__(*args, **kw)

        self.Bind(wx.EVT_BUTTON, self.MusicToggleFunction)

    def MusicToggleFunction(self, mtf):
        if mixer.music.get_busy() == True:
            print "test, is playing"
            mixer.music.stop()
        else:
            mixer.music.play()

class SoundTestButt(wx.Button):

    def __init__(self, *args, **kw):
        super(SoundTestButt, self).__init__(*args, **kw)

        self.Bind(wx.EVT_BUTTON, self.PlayRandSound)

    def PlayRandSound(self, mtf):
        randsoundnum = randint (0,100)
        if randsoundnum < 34:
            RandomSound1.play()
        elif randsoundnum  < 68:
            RandomSound2.play()
        else:
            RandomSound3.play()


class CPFInputter(wx.TextCtrl):

    def __init__(self, *args, **kw):
        super(CPFInputter, self).__init__(*args, **kw)

        self.Bind(wx.EVT_COMMAND_ENTER, self.TextEntryFunction)

    def TextEntryFunction(self, mtf):
        print "you pressed enter"


class Example(wx.Frame):

    def __init__(self, parent, title):
        super(Example, self).__init__(parent, title=title,
            size=(800, 600))


        self.InitUI()
        self.Centre()
        self.Show()


    def InitUI(self):

        panel = wx.Panel(self)

        #--------------------------------------------------------------
        #This is an event handler. It handles the pressing of Enter, only.
        def UserInputtedCommand(self):
            keycode = self.GetKeyCode()
            if keycode == wx.WXK_RETURN or keycode == wx.WXK_NUMPAD_ENTER:
                print self.GetValue()

        hbox = wx.BoxSizer(wx.HORIZONTAL)

        fgs = wx.FlexGridSizer(3, 2, 9, 25)
        #  3 rows
        #  2 columns
        #  9 vert gap
        # 25 horizonatl gap

        OutBoxLabel = wx.StaticText(panel, label="Outbox") #notice that these do NOT have wx.expand and they do NOT expand when the window is sized.
        InBoxLabel = wx.StaticText(panel, label="Input:") #notice that these do NOT have wx.expand and they do NOT expand when the window is sized.

        #make a bunch of input text controls, under the main panel.
        InTC = wx.TextCtrl(panel)
        InTC.Bind(wx.EVT_KEY_DOWN, UserInputtedCommand)
        OutTC = wx.TextCtrl(panel, style=wx.TE_MULTILINE)
        MusicToggle = MusTogButt(panel, label="Toggle Music Playback")
        SoundTester = SoundTestButt(panel, label="Play Random Sound")

        #Use AddMany AFTER you've built all your widgets with their specifications and put them in objects.
        fgs.AddMany([(OutBoxLabel), (OutTC, 1, wx.EXPAND),
            (InBoxLabel), (InTC, 1, wx.EXPAND), (MusicToggle), (SoundTester)])

        fgs.AddGrowableRow(0, 1)
        fgs.AddGrowableCol(1, 1)
        # So, in other words, the 1st and second textboxes can grow horizontally, and the 3rd and final textbox can grow horizontally and vertically.

        #lastly, add the FGS to the main hbox.
        hbox.Add(fgs, proportion=1, flag=wx.ALL|wx.EXPAND, border=15)
        #...and set sizer.
        panel.SetSizer(hbox)


if __name__ == '__main__':

    app = wx.App()
    Example(None, title='CPF_FunGame2_MediaTest')
    print "cpf_Fungame2_mediatest_running"
    app.MainLoop()

Solution

  • Below creates two text controls, when you type something in the first and press enter it shows up in the second control.

    In your code you are missing the style=wx.TE_PROCESS_ENTER.

    # -*- coding: utf-8 -*-
    #!/usr/bin/env python
    import wx
    import wx.lib.sized_controls as sc
    
    class AFrame(sc.SizedFrame):
        def __init__(self, *args, **kwds):
            super(AFrame, self).__init__(*args, **kwds)
    
            pane = self.GetContentsPane()
    
            self.tc1 = wx.TextCtrl(pane, style=wx.TE_PROCESS_ENTER)
            self.tc2 = wx.TextCtrl(pane)
    
            self.tc1.Bind(wx.EVT_TEXT_ENTER, self.onTc1Enter)
    
        def onTc1Enter(self, Evt):
            self.tc2.ChangeValue(self.tc1.GetValue())
    
    
    
    if __name__ == "__main__":
        import wx.lib.mixins.inspection as WIT
    
        app = WIT.InspectableApp()
        f = AFrame(None)
        f.Show()
        app.MainLoop()