我有一个自定义进度条状视图,基本上由两个并排的sizer组成:左边的一个有红色背景,右边有一个有浅灰色背景。通过调整大小调整器的相对大小,我可以指示不同的百分比。无论出于何种原因 - 可能因为此窗口仅由大小调整器组成,没有“实质”元素 - 当首次出现包含Frame时,进度条不可见。当框架在任何方向上调整任何数量的大小时,进度条突然弹出视图,具有正确的大小和位置以及所有内容。
以下是最小代码示例。它并没有完全证明我所描述的问题:当按原样运行时,进度条将正确显示。
但是,如果我从TestWindow中的Add()调用中移除了wx.EXPAND标志。 init ,那么当窗口首次出现时,进度条将是错误的大小或完全不可见。 (调整窗口大小会导致栏变得可见和/或采用正确的大小。)但是,当run_on_main_thread装饰器未应用于update_sizes时,无论wx.EXPAND标志是否正确,该栏始终正确显示。被包括在内!
我不确定为什么我对线程安全的努力导致了这个绘图问题。任何人都可以建议一种方法,从一开始就正确显示进度条,同时仍然确保update_sizes
只能在主线程上运行?例如,我可以在窗口上触发EVT_SIZE
,以便在没有任何用户交互的情况下刷新自己吗?
我在OS X 10.9.2上使用Python 2.7.5和wxPython 2.9.5.0。
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()
答案 0 :(得分:2)
您的示例正如我所期望的那样使用wxPython 3.0,但您的症状很常见。通常,这意味着初始大小事件发生在sizer设置之前,因此默认的EVT_SIZE
处理程序还没有用于布局的sizer。一旦窗口调整大小,然后使用sizer进行布局,所有内容都按照您的预期进行。
要解决此问题,您只需在创建框架及其内容后触发内置布局功能。 (通常在__init__
的末尾)由于自动布局与大小事件相关联,因此您可以使用框架的SendSizeEvent
方法让它拥有一个。或者你可以自己明确地调用Layout
方法。