Wxpython 为什么在用户调整窗口大小之前我的UI元素不可见?
我有一个自定义的进度条视图,它基本上由两个并排的尺寸标注器组成:左侧的一个为红色背景,右侧的一个为浅灰色背景。通过调整施胶器的相对大小,我可以指示不同的百分比。无论出于何种原因,可能是因为此窗口仅由大小写组成,没有“实质性”元素,所以当其包含的框架首次出现时,进度条不可见。当框架在任何方向上调整任意大小时,进度条会突然弹出,显示正确的大小、位置和所有内容 下面是一个最小的代码示例。它并没有完全说明我所描述的问题:当按原样运行时,进度条将正确显示 但是,如果我从TestWindow的Add()调用中删除wx.EXPAND标志。init,那么当窗口第一次出现时,进度条要么大小错误,要么完全不可见。(调整窗口的大小会导致该条变为可见和/或采用正确的大小。)但是,如果未应用“运行在主线程上”线程装饰器来更新线程大小,则无论是否包含wx.EXPAND标志,该条始终会立即正确显示 我不确定为什么我在线程安全方面的努力导致了这个绘图问题。有谁能建议一种方法,使进度条从一开始就正确显示,同时确保Wxpython 为什么在用户调整窗口大小之前我的UI元素不可见?,wxpython,wxwidgets,Wxpython,Wxwidgets,我有一个自定义的进度条视图,它基本上由两个并排的尺寸标注器组成:左侧的一个为红色背景,右侧的一个为浅灰色背景。通过调整施胶器的相对大小,我可以指示不同的百分比。无论出于何种原因,可能是因为此窗口仅由大小写组成,没有“实质性”元素,所以当其包含的框架首次出现时,进度条不可见。当框架在任何方向上调整任意大小时,进度条会突然弹出,显示正确的大小、位置和所有内容 下面是一个最小的代码示例。它并没有完全说明我所描述的问题:当按原样运行时,进度条将正确显示 但是,如果我从TestWindow的Add()调用
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()