1. I have an OGLCanvas with shapes on it
2. Double clicking a shape will open up a wx.MiniFrame where the user can do certain things
3. After OK is clicked or the frame is destroyed I would like the "focus" to shift back to the canvas so that without actually having to do a mouse click I can immediately start using the keyboard keys to perform actions on the canvas
4. Except where do I call the SetFocus() so that the focus successfully passes back to the parent of the miniframe?

I have tried several variations of SetFocus, SetFocusIgnoringChildren and SetFocusFromKbd both after the self.Destroy() and just before it but nothing works which leads me to conclude that there is some piece of logic that I am missing. Is there no way I can pass the focus back to the parent after the mini frame is closed??

Any advice is appreciated...

You can use Hide() and Show() as explained here:

# create two frames with wxFrame, only one is showing

import wx

class Frame1(wx.Frame):
    def __init__(self, parent, mytitle):
        wx.Frame.__init__(self, parent, wx.ID_ANY, mytitle)
        self.SetBackgroundColour("green")
        # pass frame1 to frame2 as instance self
        self.frame2 = Frame2(None, 'Frame1', self)

        # create input widgets
        self.button1 = wx.Button(self, wx.ID_ANY, label='Frame2')
        self.button2 = wx.Button(self, wx.ID_ANY, label='Button2')
        self.button3 = wx.Button(self, wx.ID_ANY, label='Button3')
        # bind mouse event to an action
        self.button1.Bind(wx.EVT_BUTTON, self.button1Click)

        # use a box sizer to lay out widgets
        sizer_v = wx.BoxSizer(wx.VERTICAL)
        # Add(widget, proportion, flag, border)
        sizer_v.Add(self.button1, 0, flag=wx.ALL, border=10)
        sizer_v.Add(self.button2, 0, flag=wx.ALL, border=10)
        sizer_v.Add(self.button3, 0, flag=wx.ALL, border=10)
        self.SetSizer(sizer_v)

        # size the frame so all the widgets fit
        self.Fit()

    def button1Click(self, event):
        """button1 has been left clicked"""
        # self is instance frame1
        self.Hide()
        self.frame2.Show()


class Frame2(wx.Frame):
    def __init__(self, parent, mytitle, frame1):
        wx.Frame.__init__(self, parent, wx.ID_ANY, mytitle)
        self.SetBackgroundColour("brown")
        self.frame1 = frame1

        # create input widgets
        self.button1 = wx.Button(self, wx.ID_ANY, label='Frame1')
        self.button2 = wx.Button(self, wx.ID_ANY, label='Button2')
        self.button3 = wx.Button(self, wx.ID_ANY, label='Button3')
        # bind mouse event to an action
        self.button1.Bind(wx.EVT_BUTTON, self.button1Click)
        # responds to exit symbol x on frame2 title bar
        self.Bind(wx.EVT_CLOSE, self.button1Click)

        # use a box sizer to lay out widgets
        sizer_v = wx.BoxSizer(wx.VERTICAL)
        # Add(widget, proportion, flag, border)
        sizer_v.Add(self.button1, 0, flag=wx.ALL, border=10)
        sizer_v.Add(self.button2, 0, flag=wx.ALL, border=10)
        sizer_v.Add(self.button3, 0, flag=wx.ALL, border=10)
        self.SetSizer(sizer_v)

        # size the frame so all the widgets fit
        self.Fit()

    def button1Click(self, event):
        """button1 has been left clicked"""
        # self is instance frame2
        self.Hide()
        self.frame1.Show()


app = wx.App(0)
# create a MyFrame instance and show the frame
frame1 = Frame1(None, 'Frame1')
frame1.Show()
app.MainLoop()

Thanks for your reply sneekula - that functionality is pretty cool! I wasn't aware I could show and hide frames but in this particular instance I have a different issue. I figured it would be easier to just show rather than tell so here is a little example I put together.

import wx
import wx.lib.ogl as ogl
        
class NodeNameDialog(wx.MiniFrame):
    
    """Frame prompts user to input a name for the node."""
    
    def __init__(self, parent, id, title, position):
        
        """Background & text box arranged appropriately and focus set on frame."""
        
        wx.MiniFrame.__init__(self, parent, id, title, position, size=(300, 300), style=wx.DEFAULT_FRAME_STYLE)
        
        self.parent = parent
        self.SetBackgroundColour('#D3D3D3')
       
        box = wx.BoxSizer(wx.HORIZONTAL)  # a horizontal layout will be used            
        self.textBox = wx.TextCtrl(self, -1, "child", size=(80,-1)) 
        self.textBox.Bind(wx.EVT_KEY_DOWN, self.on_name_key_down)  # the text box expects key strokes
        self.textBox.SetFocus()
        box.Add(self.textBox, 1, wx.ALIGN_CENTRE|wx.ALL, 5)  
        self.SetSizer(box)
        box.Fit(self)
        
    def on_name_key_down(self, event):
        """Define what to do when certain keystrokes are used on name dialog."""
        keycode = event.GetKeyCode()
        if keycode == wx.WXK_RETURN:  # set node name to be the text user entered
            self.set_shape_text(self.textBox.GetValue())
            self.parent.Refresh(False)
            self.Destroy()               
             #  TODO: check this???? focus should be set to canvas here???  
        if keycode == wx.WXK_ESCAPE:  # do nothing if user pressed Escape
            self.Destroy()  
        event.Skip()    
      
    def set_shape_text(self, text):
        """Set the name of the node only if the text user entered is not empty."""
        if not (text == ""):
            region = self.parent.currentShape.GetRegions()[0]
            region.SetText(text) 
            self.parent.reformat_regions(self.parent.currentShape)  
        self.Refresh(False)    
            
            
class MyEvtHandler(ogl.ShapeEvtHandler):
        """
        Overwrite the default event handler to implement some custom features. 
        """
        def __init__(self):
                ogl.ShapeEvtHandler.__init__(self)        


        def OnLeftDoubleClick(self, x, y, keys=0, attachment=0):
             toShape = self.GetShape()
             toShape.GetCanvas().currentShape = toShape
             posnFrame = (toShape.GetX()+200, toShape.GetY()) 
             nameNode = NodeNameDialog(toShape.GetCanvas(), -1, 'Node name:', posnFrame)
             nameNode.Show(True)        

        def OnLeftClick(self, x, y, keys=0, attachment=0):
            shape = self.GetShape()
            canvas = shape.GetCanvas()
            dc = wx.ClientDC(canvas)
            canvas.PrepareDC(dc)    
            if shape.Selected():
                shape.Select(False, dc)
                #canvas.Redraw(dc)
                canvas.Refresh(False)
            else:
                redraw = False
                shapeList = canvas.GetDiagram().GetShapeList()
                toUnselect = []    
                for s in shapeList:
                    if s.Selected():
                        toUnselect.append(s)
                shape.Select(True, dc)   
                if toUnselect:
                    for s in toUnselect:
                        s.Select(False, dc)
                    canvas.Refresh(False)                  
                                               
    
class OGLCanvas(ogl.ShapeCanvas):
        def __init__(self, parent, frame):
                ogl.ShapeCanvas.__init__(self, parent)
                
                maxWidth  = 100
                maxHeight = 100
                self.SetScrollbars(20, 20, maxWidth/20, maxHeight/20)

                self.SetBackgroundColour("LIGHT BLUE")
                self.diagram = ogl.Diagram()
                self.SetDiagram(self.diagram)
                self.diagram.SetCanvas(self)
                self.currentShape = None
                self.shapes = []
                self.save_gdi = []

                one = self.MyAddShape(
                    ogl.CircleShape(80), 
                    75, 110, wx.Pen(wx.BLUE, 3), wx.GREEN_BRUSH, "Root")           
                two = self.MyAddShape(
                    ogl.TextShape(120, 45), 
                    160, 35, wx.GREEN_PEN, wx.LIGHT_GREY_BRUSH, "node 1")            
                self.MyAddShape(
                    ogl.TextShape(120, 45), 
                    270, 35, wx.GREEN_PEN, wx.LIGHT_GREY_BRUSH, "node 2")

                self.shapes.append(one)
                self.shapes.append(two)
                
                self.MyAddLink()
         
                self.Bind(wx.EVT_KEY_DOWN, self.on_key_down)   
         
        def on_key_down(self, event):
            """Define what to do when certain keystrokes are used."""
            keycode = event.GetKeyCode() 
    
            if keycode == wx.WXK_DELETE:  # delete shape selected
                print "delete"
            if keycode == wx.WXK_INSERT:  # create a child node for shape selected
                print "insert"
            event.Skip()     
                  
        def MyAddLink(self):      
                for x in range(len(self.shapes)):
                    fromShape = self.shapes[x]
                    if x+1 == len(self.shapes):
                        toShape = self.shapes[0]
                    else:
                        toShape = self.shapes[x+1]
        
                    line = ogl.LineShape()
                    line.SetCanvas(self)
                    line.SetPen(wx.BLACK_PEN)
                    line.SetBrush(wx.BLACK_BRUSH)
                    line.AddArrow(ogl.ARROW_ARROW)
                    line.MakeLineControlPoints(2)
                    fromShape.AddLine(line, toShape)
                    self.diagram.AddShape(line)
                    line.Show(True)       
        
        def MyAddShape(self, shape, x, y, pen, brush, text):
            # Composites have to be moved for all children to get in place
            if isinstance(shape, ogl.CompositeShape):
                dc = wx.ClientDC(self)
                self.PrepareDC(dc)
                shape.Move(dc, x, y)
            else:
                shape.SetDraggable(True, True)
            shape.SetCanvas(self)
            shape.SetX(x)
            shape.SetY(y)
            if pen:    shape.SetPen(pen)
            if brush:  shape.SetBrush(brush)
            if text:
                for line in text.split('\n'):
                    shape.AddText(line)
            #shape.SetShadowMode(ogl.SHADOW_RIGHT)
            self.diagram.AddShape(shape)
            shape.Show(True)
    
            evthandler = MyEvtHandler()
            evthandler.SetShape(shape)
            evthandler.SetPreviousHandler(shape.GetEventHandler())
            shape.SetEventHandler(evthandler)
        
            return shape

        def reformat_regions(self, shape):
            """Ensures the text displays correctly for a shape region."""
            rnum = 0
            canvas = shape.GetCanvas()
            dc = wx.ClientDC(canvas)  # used for measuring
            for region in shape.GetRegions():
                text = region.GetText()
                region.SetFormatMode(ogl.FORMAT_SIZE_TO_CONTENTS)
                shape.FormatText(dc, text, rnum)
                rnum += 1        

        
class OGLFrame(wx.Frame):
        def __init__(self, *args, **kwds):
                wx.Frame.__init__(self, *args, **kwds)

                self.SetTitle("Testing right click")
                self.SetBackgroundColour(wx.Colour(8, 197, 248))
                self.canvas = OGLCanvas(self, self)

if __name__ == "__main__":
        app = wx.PySimpleApp(False)
        wx.InitAllImageHandlers()
        ogl.OGLInitialize()
        frame = OGLFrame(None, -1, "")
        app.SetTopWindow(frame)
        frame.Show(True)
        app.MainLoop()

In the code above when we start up the app pressing insert and delete means that we will see stuff print out as expected. Then after we double click on a shape and the frame shows up and we write something in it then press enter the frame is destroyed. Now I want to know what can I do that without a mouse click the focus can be set back to the canvas so that pressing insert and delete will once again print stuff...where can I put the SetFocus() method so this works?

Thanks

This article has been dead for over six months. Start a new discussion instead.