1

ユーザーの操作に基づいて、wxPythonノートブックのパネルにコントロールを動的に追加および削除したいと思います。私が最も徹底的に試したアプローチは.Clear()、パネルのサイザーを呼び出して、すべての新しいコントロールを追加することです。ただし、Windows 7デスクトップとLinuxデスクトップの両方で、レンダリングアーティファクトと古いコントロールは新しいコンテンツの下に表示されたままになります。古いコントロールを完全に削除し、これらのアーティファクトなしで新しいコントロールを追加するにはどうすればよいですか?

以下は、Windows 7で問題を再現するサンプルプログラムです。との2つの異なる.update()方法にStaticPanel注意してくださいDynamicPanel

#!/usr/bin/python
import wx
import sys


class StaticPane(wx.Panel):
    """A panel that contains simple text that is updated
    when the .update() method is called. The text is updated
    using .SetText(), and the text control sticks around 
    between calls to .update()."""
    def __init__(self, *args, **kwargs):
        super(StaticPane, self).__init__(*args, **kwargs)
        self._sizer = wx.BoxSizer(wx.VERTICAL)
        self.SetSizer(self._sizer)
        self._counter = 0
        self._base_text = "Some Text"
        self._text = wx.TextCtrl(self, -1,
                                 self._base_text + "!" * self._counter,
                                 style=wx.TE_READONLY)
        self._sizer.Add(self._text, -1, wx.EXPAND)

    def update(self):
        self._counter += 1
        self._text.SetValue(self._base_text + "!" * self._counter)


class DynamicPane(wx.Panel):
    """A panel that contains simple text that is updated
    when the .update() method is called. The text is updated
    by removing the existing text control, and adding a new one
    with the updated text string."""
    def __init__(self, *args, **kwargs):
        super(DynamicPane, self).__init__(*args, **kwargs)
        self._sizer = wx.BoxSizer(wx.VERTICAL)
        self.SetSizer(self._sizer)
        self._counter = 0
        self._base_text = "Some Text"
        self._text = wx.TextCtrl(self, -1,
                                 self._base_text + "!" * self._counter,
                                 style=wx.TE_READONLY)
        self._sizer.Add(self._text, -1, wx.EXPAND)

    def update(self):
        self._counter += 1
        self._sizer.Clear()
        self._text = wx.TextCtrl(self, -1,
                                 self._base_text + "!" * self._counter,
                                 style=wx.TE_READONLY)
        self._sizer.Add(self._text, -1, wx.EXPAND)
        self.Layout()


class TestViewer(wx.Frame):
    """A Frame with a button and a notebook. When the button is pressed, 
    each of the two pages in the notebook recieve a call to .update().
    """
    def __init__(self, parent):
        super(TestViewer, self).__init__(parent, -1, "Test Viewer")
        self.Bind(wx.EVT_CLOSE, self.OnClose)

        self._panel = wx.Panel(self)
        vbox = wx.BoxSizer(wx.VERTICAL)
        self._panel.SetSizer(vbox)

        update_button = wx.Button(self._panel, wx.ID_CLOSE, "Update")
        update_button.Bind(wx.EVT_BUTTON, self.update)
        vbox.Add(update_button, 0, wx.EXPAND)

        self._nb = wx.Notebook(self._panel)
        self._view_one = StaticPane(self._nb, -1)
        self._view_two = DynamicPane(self._nb, -1)
        self._nb.AddPage(self._view_one, "One")
        self._nb.AddPage(self._view_two, "Two")
        vbox.Add(self._nb, 1, wx.EXPAND | wx.ALL)

        self.Layout()

    def update(self, e):
        self._view_one.update()
        self._view_two.update()

    def OnClose(self, event):
        sys.exit(0)

if __name__ == "__main__":
    app = wx.App(False)
    frame = TestViewer(None)
    frame.Show()
    app.MainLoop()

[更新]ボタンをクリックして、2つのパネルのテキストを更新します。最初のパネルは、を使用してテキストコントロールを更新し、2番目のパネルはを新しいものに.SetText()置き換えます。TextCtrlボタンを数回クリックした後、ウィンドウのサイズを変更するか、2番目のパネルの上にマウスを置くと、重複するコントロールやその他のアーティファクトがあることに注意してください。

これは、スタックされたコントロールを示すスクリーンショットです。両方の画像は、同じボタンクリック数の後に撮影されたもので、同じ状態の2つの異なるパネルを示しています。私はテキストがまったく同じであることを期待していました。

パネル1(<code> .SetText()</ code>) パネル2(<code> TextCtrl </ code>が置き換えられました)

4

1 に答える 1

2

単純にサイザーをクリアすると、ウィジェットではなく、そのコンテンツへの参照のみが削除されます。ウィジェットを作成すると、指定した親ウィンドウに登録されます。次のコードを検討してください。

class Frame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self,None)
        self.textCtrl = wx.TextCtrl(self) # create with Frame as parent
        self.textCtrl = None # has no effect on the TextCtrl

親ウィンドウ (この例では Frame) は TextCtrl の所有権を取得し、None に設定しても、Frame は破棄されるまで存続します。TextCtrl を削除するには、明示的に破棄する必要があります。

self.textCtrl.Destroy()

すべての子ウィジェットを一度に削除する場合は、次を使用できます。

self.DestroyChildren()
于 2012-11-01T22:50:18.520 に答える