wxPython滚动面板不更新滚动条

5
我正在使用winxp和wxpython(wxpython 3.1,python 2.6)制作一个GUI程序,该程序将从TextCtrl中复制文本到包含StaticText的ScrollablePanel中。这一切都很顺利,但是滚动部分的工作不太对。它似乎无法实时更新。当我最小化窗口然后再次最大化时,滚动条会更新。但是,如果我再次在TextCtrl中开始输入(因此使用事件向ScrollablePanel内部的StaticText添加文本),则面板上的滚动条不会更新,除非我再次最小化等。
所以问题是,如何实时更新ScrolledPanel?我已经设置了一个事件等待TextCtrl中的文本更改,这就是我认为需要进行更新的地方。我尝试过Update、Refresh和Layout,但它们似乎没有什么用。更大的问题是,最小化窗口并再次最大化会做什么,而Update、Refresh和Layout却不能做到呢?谢谢你的帮助。抱歉我不能发布代码,因为它是保密的。我会感激您能给我的任何帮助。通常情况下,我可以通过搜索自己找出问题,但我还没有找到关于这种事情的任何文档。这是我第一次遇到这种情况,但我从您的答案中得到了很多帮助。再次感谢! :)
补充:
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()    

通常情况下,这就是程序的目的,不需要过多的解释。我设置了虚拟大小,希望这会使面板的大小大于它填充的区域,以期获得永久滚动条,但事实并非如此。


1
我认为你的代码中相关部分可能已经就位了。这将有助于您获得更好的答案。我在这个领域没有太多的知识,但我猜这是一个非常具体的问题,很可能是你的程序中的一个错误,因此,如果不看到您正在做什么,很难猜出问题所在。 - Trufa
谢谢您的回复,我已经添加了我能够添加的内容。 - Isaac
还忘了提一下,我正在使用Windows XP操作系统。 - Isaac
1
没问题!祝你解决问题顺利!还有一件事,每当你使用注释系统时,我建议你使用@Isaac或在这种情况下使用@Trufa,以便用户得到通知。 - Trufa
很高兴你解决了你的问题!欢迎来到StackOverflow。 - Trufa
1个回答

9

如果您发布的内容可以复制并粘贴后立即运行,将会更好。

无论如何,似乎您忽略了以下必需的事项,以使滚动面板正常工作:

  1. 滚动面板必须有一个sizer。这可以通过self.test_panel.SetSizer(self.a_sizer)方法完成。面板内的所有其他控件都必须附加到此sizer上。

  2. 您必须在面板上调用SetupScrolling()方法,例如:self.test_panel.SetupScrolling()

  3. 您必须为面板启用自动布局,例如:self.test_panel.SetAutoLayout(1)

P.S. 您是否见过wxPython代码的示例?我之所以问是因为几乎所有示例都具有像__do_layout或类似的精美方法。这种方法可以帮助使您的代码更加易读。

编辑:

您需要在TextChange方法中添加self.test_panel.FitInside(),以便强制面板重新计算子控件的大小并更新其自身的虚拟大小。

下面是完整的解决方案:

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()    

  1. 我确实设置了框架的大小器,只是没有列出代码。我以为这是默认的。现在我明白了,我已经将它添加到上面的代码中。
  2. 我尝试调用了SetupScrolling,但效果不大。我还以为设置滚动速率等参数就可以实现滚动。难道不是这样吗?无论如何,我已经改成使用SetupScrolling,问题仍然存在。
  3. 我确实有这个新代码,请看一下。
附注:显然,我已经查看了wxpython的示例,否则我对它的工作原理一无所知。我认为你的评论缺乏洞察力。
- Isaac
3
你的代码问题在于没有"通知"面板其子控件大小已更改,但是所有控件的大小会在调整大小时自动重新计算,这就是为什么当你调整窗口大小时一切都能正常工作的原因。要使你的代码正常工作,只需在TextChanged方法中添加self.test_panel.FitInside()。此外,我已经对你的代码进行了清理。请参见更新后的答案。 - Vader
谢谢,这个可行。这个Fit功能是我不知道的内部工作原理。感谢您教给我新东西。 - Isaac
对于任何也在寻找答案的人 - 请查看Vader的评论,而不是冗长的回答。我只需要FitInside()命令。我不需要两个sizer。 - Vaidøtas I.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接