Wxpython 为什么在用户调整窗口大小之前我的UI元素不可见?

Wxpython 为什么在用户调整窗口大小之前我的UI元素不可见?,wxpython,wxwidgets,Wxpython,Wxwidgets,我有一个自定义的进度条视图,它基本上由两个并排的尺寸标注器组成:左侧的一个为红色背景,右侧的一个为浅灰色背景。通过调整施胶器的相对大小,我可以指示不同的百分比。无论出于何种原因,可能是因为此窗口仅由大小写组成,没有“实质性”元素,所以当其包含的框架首次出现时,进度条不可见。当框架在任何方向上调整任意大小时,进度条会突然弹出,显示正确的大小、位置和所有内容 下面是一个最小的代码示例。它并没有完全说明我所描述的问题:当按原样运行时,进度条将正确显示 但是,如果我从TestWindow的Add()调用

我有一个自定义的进度条视图,它基本上由两个并排的尺寸标注器组成:左侧的一个为红色背景,右侧的一个为浅灰色背景。通过调整施胶器的相对大小,我可以指示不同的百分比。无论出于何种原因,可能是因为此窗口仅由大小写组成,没有“实质性”元素,所以当其包含的框架首次出现时,进度条不可见。当框架在任何方向上调整任意大小时,进度条会突然弹出,显示正确的大小、位置和所有内容

下面是一个最小的代码示例。它并没有完全说明我所描述的问题:当按原样运行时,进度条将正确显示

但是,如果我从TestWindow的Add()调用中删除wx.EXPAND标志。init,那么当窗口第一次出现时,进度条要么大小错误,要么完全不可见。(调整窗口的大小会导致该条变为可见和/或采用正确的大小。)但是,如果未应用“运行在主线程上”线程装饰器来更新线程大小,则无论是否包含wx.EXPAND标志,该条始终会立即正确显示

我不确定为什么我在线程安全方面的努力导致了这个绘图问题。有谁能建议一种方法,使进度条从一开始就正确显示,同时确保
update\u size
仅在主线程上运行?例如,我是否可以在窗口上触发
EVT\u SIZE
,以便它在没有任何用户交互的情况下刷新自身

我在OSX10.9.2上使用Python2.7.5和Wxpython2.9.5.0

代码
您的示例在wxPython 3.0中的效果与我预期的一样,但您的症状很常见。通常这意味着初始大小事件发生在设置大小器之前,因此默认的
EVT_size
处理程序还没有用于布局的大小器。一旦调整了窗口的大小,就使用大小调整器来进行布局,一切都如您之前所期望的那样


要解决此问题,只需在创建框架及其内容后触发内置布局功能。(通常在
\uuuu init\uuuu
的末尾)由于自动布局与大小事件相关联,因此可以使用帧的
SendSizeEvent
方法使其具有一个。或者你可以自己明确地调用
Layout
方法。

你能提供一个小的可运行示例以及你使用的是什么操作系统吗?此外,您使用的是Python和WxPython的版本?我已经添加了一些代码。当我在Windows 7、WX2.2.12和Python 2.6上运行代码时,在帧的中间看到了一个黑条。如果您使用的是线程,请确保对wx元素的任何调用都是通过wx的线程安全方法完成的:wx.CallAfter和wx。PostEvent@MikeDriscoll我用的是CallAfter。如果你不介意再读一遍我的问题,我已经对它进行了相当多的编辑。不幸的是,这也不起作用。在框架和PercentageBar的包含窗口上调用
SendSizeEvent
,无法使其可见。我最终使用了一个“非阻塞锁”装饰器而不是“在主线程上运行”装饰器,它似乎工作正常。
from functools import wraps
from math import floor
import wx

def run_on_main_thread(fn):
    """Decorator. Forces the function to run on the main thread.

    Any calls to a function that is wrapped in this decorator will return
    immediately; the return value of such a function is not available.

    """
    @wraps(fn)
    def deferred_caller(*args, **kwargs):
        wx.CallAfter(fn, *args, **kwargs)

    return deferred_caller


class PercentageBar(wx.Window):
    def __init__(self, parent, percentage=0.0):
        wx.Window.__init__(self, parent)

        border_color = '#000000'
        active_color = '#cc0000'
        inactive_color = '#d3d7cf'
        height = 24

        self.percentage = percentage

        self.SetBackgroundColour(border_color)

        self.active_rectangle = wx.Panel(self, size=(-1, height))
        self.active_rectangle.SetBackgroundColour(active_color)

        self.inactive_rectangle = wx.Panel(self, size=(-1, height))
        self.inactive_rectangle.SetBackgroundColour(inactive_color)

        self.sizer = wx.BoxSizer(wx.HORIZONTAL)
        self.SetSizer(self.sizer)
        self.update_sizes()

    @run_on_main_thread
    def update_sizes(self):
        self.sizer.Clear(False)

        if self.percentage != 0.0 and self.percentage != 1.0:
            active_flags = wx.EXPAND | (wx.ALL & ~wx.RIGHT)
        else:
            active_flags = wx.EXPAND | wx.ALL

        self.sizer.Add(self.active_rectangle, floor(1000 * self.percentage),
                active_flags, 1)

        self.sizer.Add(self.inactive_rectangle, floor(1000 * (1.0 - self.percentage)),
                wx.EXPAND | wx.ALL, 1)

        if self.percentage == 0.0:
            self.active_rectangle.Hide()
            self.inactive_rectangle.Show()
        elif self.percentage == 1.0:
            self.active_rectangle.Show()
            self.inactive_rectangle.Hide()
        else:
            self.active_rectangle.Show()
            self.inactive_rectangle.Show()

        self.sizer.Layout()
        self.Refresh()


class TestWindow(wx.Frame):
    def __init__(self, parent):
        wx.Frame.__init__(self, parent, title='Test')

        vertical_sizer = wx.BoxSizer(wx.VERTICAL)
        vertical_sizer.Add((1, 1), 1)
        vertical_sizer.Add(PercentageBar(self, percentage=0.33), 2, wx.EXPAND)
        vertical_sizer.Add((1, 1), 1)

        horizontal_sizer = wx.BoxSizer(wx.HORIZONTAL)
        horizontal_sizer.Add((1, 1), 1)
        horizontal_sizer.Add(vertical_sizer, 10, wx.EXPAND)
        horizontal_sizer.Add((1, 1), 1)

        self.SetSizer(horizontal_sizer)


if __name__ == '__main__':
    app = wx.App()
    window = TestWindow(None)
    window.Show()
    app.MainLoop()