5

I'm using winxp and wxpython ( wxpython 3.1, python 2.6 ) to make a GUI program which will copy the text from a TextCtrl, into a ScrollablePanel that contains a StaticText. This all works fine, however, the Scrolled part doesn't work quite right. It seems like it won't update in real time. When I ummaximize the window and maximize it again, the scroll bar updates. However, if I start typing in the TextCtrl again ( Thereby adding text to the StaticText inside the ScrollablePanel using an event ) the scrollbar on the panel doesn't update unless I minimize again and so on.

So the question is, how can I update the ScrolledPanel in real time? I have an event setup waiting for the text to change in the TextCtrl, which is where I think the update would need to go. I've tried Update, Refresh, and Layout but they didn't seem to do much. The bigger question is, what does minimizing the window and maximixing it again do that Update, Refresh and Layout do not? Thanks for you help in this. Sorry I can't post code, confidential. I would appreciate any help you could give me. I can normally find problems out on my own by searching but I just haven't found any documentation about this kind of thing. This is the first time for me, but I get a lot of help from your answers. Thanks again! :)

Added:

import wx
import wx.lib.inspection
from wx.lib.scrolledpanel import ScrolledPanel

class MyFrame( wx.Frame ):

    # TODO: add all class variables here for convention
    tin         = None

    hsizer      = None

    def __init__( self, parent, ID, title ):
        wx.Frame.__init__( self, parent, ID, title,
                     wx.DefaultPosition, wx.Size( 200, 150 ) )

        self.InitWidgets()
        self.InitBindings()
        self.InitFinish()


    def InitWidgets( self ):
        self.hsizer = wx.BoxSizer( wx.HORIZONTAL )

        # Add the TextCtrl
        vsizer = wx.BoxSizer( wx.VERTICAL )
        self.tin = wx.TextCtrl( self, style=wx.TE_MULTILINE )
        vsizer.Add( self.tin, 1, wx.EXPAND  )
        self.hsizer.Add( vsizer, 3, wx.TOP|wx.LEFT|wx.BOTTOM|wx.EXPAND, border=20 )

        # Add ScrolledPanel widget
        self.hsizer.Add( wx.Size( 200, -1 ), 1 )
        vsizer2 = wx.BoxSizer( wx.VERTICAL )
        self.test_panel = ScrolledPanel( self )
        self.test_panel.SetupScrolling()

        # Setup static text ( label ) tvs is the 
        # vertical sizer inside the panel
        self.tvs = wx.BoxSizer( wx.VERTICAL )
        self.tin2 = wx.StaticText( self.test_panel )
        self.tvs.Add( self.tin2, 0, wx.EXPAND )
        vsizer2.Add( self.test_panel, 1, wx.EXPAND  )
        self.hsizer.Add( vsizer2, 3, wx.TOP|wx.LEFT|wx.BOTTOM|wx.EXPAND, border=20 )

        # Add Spacer
        self.hsizer.Add( wx.Size( 500, -1 ), 1 ) 

    def InitBindings( self ):
        self.tin.Bind( wx.EVT_TEXT, self.TextChange ) 

    def InitFinish( self ):

        # Setup sizers and frame
        self.SetAutoLayout( True )
        self.test_panel.SetAutoLayout( True )
        self.test_panel.SetSizer( self.tvs )
        self.SetSizer( self.hsizer )
        self.Layout()
        self.Update()
        self.Maximize()

    def TextChange( self, event ):

        #self.CopyValues()
        self.tin2.Label = self.tin.GetValue()
        self.Layout()
        self.Update()
        self.test_panel.Refresh()
        self.test_panel.Update()
        print self.tin.GetValue().split( "\n" )


class MyApp( wx.App ):

    fr = None

    def OnInit( self ):
        self.fr = MyFrame( None, -1, "TitleX" )
        self.fr.Show( True )
        self.SetTopWindow( self.fr )
        return True

app = MyApp( 0 )
app.MainLoop()

def main():

    win = 1
if ( __name__ == "__main__" ):
    main()    

Generally, This is what is going on without giving too much of the purpose of the program. I setup the virtual size thinking that would make the size of the panel bigger than the area it was filling, hoping it would have permanent scroll bars but its not the case.

Isaac
  • 53
  • 1
  • 4
  • 1
    I think the relevant parts of your code might be in place here. It will help you get a better answer. I don't have much knowledge in this area but I'm guessing this is a very specific problem and probably a bug in **your** program, so, it is hard to guess the problem without seeing what you are doing. – Trufa May 06 '11 at 14:53
  • Thanks for your reply, Added what I could above – Isaac May 06 '11 at 15:16
  • Also forgot to mention I'm using windows XP os – Isaac May 06 '11 at 15:25
  • 1
    No problem! wish you luck with this problem! One more thing, whenever you are using the comment system, I recommend you to do use @Isaac or in this case @Trufa so that the user get's notified. – Trufa May 06 '11 at 16:00
  • Glag you could solve you problem! welcome to StackOverflow. – Trufa May 07 '11 at 02:45

1 Answers1

9

It would be better if you'll post something that could be running right after copy and paste.

Anyway it appears that you missed the following things that are mandatory to make scrolled panel works:

  1. Scrolled panel must have a sizer. This could be done via self.test_panel.SetSizer(self.a_sizer) method. All other controls inside the panel must be attached to this sizer.

  2. You must call SetupScrolling() method on your panel, e.g. self.test_panel.SetupScrolling()

  3. You must enable auto layout for the panel, e.g. self.test_panel.SetAutoLayout(1)

P.S. Have you ever seen an examples of the wxPython code? I'm asking since almost all of them have wonderful method like __do_layout or something like that. This approach will help to make your code much more readable.

EDIT:

You need to add self.test_panel.FitInside() to TextChange method in order to force the panel to recalculate sizes of child controls and update its own virtual size.

Here is complete solution:

import wx
from wx.lib.scrolledpanel import ScrolledPanel

class MyFrame( wx.Frame ):
    def __init__( self, parent, ID, title ):
        wx.Frame.__init__( self, parent, ID, title,
                         wx.DefaultPosition, wx.Size( 600, 400 ) )
        #Controls
        self.tin = wx.TextCtrl( self, 
                                size = wx.Size( 600, 400 ),
                                style=wx.TE_MULTILINE )        
        self.test_panel = ScrolledPanel( self, 
                                         size = wx.Size( 600, 400 ) )
        self.test_panel.SetupScrolling()
        self.tin2 = wx.StaticText( self.test_panel )

        #Layout
        #-- Scrolled Window
        self.panel_sizer = wx.BoxSizer( wx.HORIZONTAL )
        self.panel_sizer.Add( self.tin2, 0, wx.EXPAND )
        self.test_panel.SetSizer( self.panel_sizer )
        self.panel_sizer.Fit(self.test_panel)
        #-- Main Frame
        self.inner_sizer = wx.BoxSizer( wx.HORIZONTAL )        
        self.inner_sizer.Add( self.tin, 1, wx.LEFT | wx.RIGHT | wx.EXPAND, 50  )
        self.inner_sizer.Add( self.test_panel, 1, wx.LEFT | wx.RIGHT | wx.EXPAND, 50  )

        self.sizer = wx.BoxSizer( wx.VERTICAL )
        self.sizer.Add(self.inner_sizer, 1, wx.ALL | wx.EXPAND, 20)        
        self.SetSizer(self.sizer)
        self.sizer.Fit(self)
        self.sizer.Layout()

        self.test_panel.SetAutoLayout(1)

        #Bind Events
        self.tin.Bind( wx.EVT_TEXT, self.TextChange )

    def TextChange( self, event ):
        self.tin2.SetLabel(self.tin.GetValue())
        self.test_panel.FitInside()


class MyApp( wx.App ):
    def OnInit( self ):
        self.fr = MyFrame( None, -1, "TitleX" )
        self.fr.Show( True )
        self.SetTopWindow( self.fr )
        return True

app = MyApp( 0 )
app.MainLoop()

def main():

    win = 1

if ( __name__ == "__main__" ):
    main()    
Vader
  • 3,675
  • 23
  • 40
  • 1. I did have set the sizer for the frame, I just didn't list the code. I assumed it was given. I see that is not. I've added it to the code above. 2. I tried calling SetupScrolling but it didn't do much. I also operated under the assumption that setting the scroll rate and such would enable scrolling. Is this not the case? Either way I've changed it to use SetupScrolling and the problem exists still 3. I do have this see new code P.S. Obviously I have looked at wxpython examples or I would have no knowledge about how it works, I find your remark to lack insight. – Isaac May 06 '11 at 16:46
  • 3
    @Isaac The problem of your code is that you don't "notify" the panel that the size of its child controls has changed, however sizes of all controls are recalculated automatically on resizing, thats why everything is working when you resize the window. To get you code works just add self.test_panel.FitInside() to the TextChanged method. Also I've made some clean up of your code. See updated answer. – Vader May 06 '11 at 20:18
  • Thanks, this works. This Fit functionality was the inner workings that I didn't know. Thanks for teaching me something new. – Isaac May 06 '11 at 21:05
  • To anyone that was also looking for an answer - see Vader's comment, rather than the lengthy answer. All I needed was the FitInside() command. I didn't need two sizers. – Vaidøtas I. Oct 06 '21 at 19:47