【问题标题】:wxpython - Using treectrl to load local html files into a panelwxpython - 使用 treectrl 将本地 html 文件加载到面板中
【发布时间】:2021-12-16 05:19:29
【问题描述】:

我正在尝试在 wxPython 中创建一个帮助菜单,左侧有一个树控件,右侧有一个 html 查看器;树控件充当一种导航菜单,单击树控件中的项目时,应在左侧面板中加载相应的本地 .html 文件。

但是,当我尝试实现这一点时,我无法将任何事件绑定到树控件中的不同节点。这就是我目前所拥有的——有人可以告诉我哪里出错了吗?

代码:

import wx
import wx.html


class HelpMenu(wx.Frame):
    def __init__(self, parent):
        tstr = "Need help?"
        super(HelpMenu, self).__init__(
            parent, -1, title=tstr, size=wx.Size(800, 500), style=wx.CAPTION |
            wx.CLOSE_BOX | wx.SYSTEM_MENU | wx.RESIZE_BORDER)

        splitter = wx.SplitterWindow(self)
        window1 = NavBar(splitter)
        window2 = htmlPanel(splitter)
        splitter.SplitVertically(window1, window2)
        splitter.SetSashGravity(0.5)
        # splitter.SetMinimumPaneSize(20)

        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(splitter, 1, wx.EXPAND)
        self.SetSizer(sizer)


class htmlPanel(wx.Panel):
    def __init__(self, parent):
        super(htmlPanel, self).__init__(parent)

        html = wx.html.HtmlWindow(self)
        if 'gtk2' in wx.PlatformInfo:
            html.SetStandardFonts()

        # htmlszr = wx.BoxSizer(wx.VERTICAL)
        # htmlszr.Add(html, 0, wx.EXPAND)
        html.LoadPage('.\\index.html')
        # self.SetSizer(htmlszr)


class NavTree(wx.TreeCtrl):
    def __init__(self, parent, id, pos, size, style):
        super(NavTree, self).__init__(parent, id, pos, size, style)


class NavBar(wx.Panel):
    def __init__(self, parent):
        super(NavBar, self).__init__(parent)

        self.tree = NavTree(
            self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TR_HAS_BUTTONS)
        self.root = self.tree.AddRoot('Help Contents')
        self.welcome = self.tree.AppendItem(self.root, 'Start Page')
        self.background = self.tree.AppendItem(self.root, 'Background')
        self.method = self.tree.AppendItem(self.root, 'Calculation Method')
        self.using = self.tree.AppendItem(self.root, 'Using the Calculator')
        self.start = self.tree.AppendItem(self.using, 'Selecting Data Type')
        self.params = self.tree.AppendItem(self.using, 'Setting Parameters')
        self.results = self.tree.AppendItem(self.using, 'Viewing Results')
        self.interp = self.tree.AppendItem(self.root, 'Interpreting Results')
        # insert more children of interp here for various issues concerning
        # interpretation
        self.welcome.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self._welcome)
        self.background.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self._background)
        self.method.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self._method)
        self.using.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self._using)
        self.start.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self._start)
        self.params.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self._params)
        self.results.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self._results)
        self.interp.Bind(wx.EVT_TREE_ITEM_ACTIVATE, self._interp)

        self.treeszr = wx.BoxSizer(wx.VERTICAL)
        self.treeszr.Add(self.tree, 0, wx.EXPAND)
        self.SetSizer(self.treeszr)

        def _welcome(self, event):
            htmlPanel.html.LoadPage('.\\Help\\index.html')

        def _background(self, event):
            htmlPanel.html.LoadPage('.\\Help\\background.html')

        def _method(self, event):
            htmlPanel.html.LoadPage('.\\Help\\method.html')

        def _using(self, event):
            htmlPanel.html.LoadPage('.\\Help\\use.html')

        def _start(self, event):
            htmlPanel.html.LoadPage('.\\Help\\start.html')

        def _params(self, event):
            htmlPanel.html.LoadPage('\\Help\\params.html')

        def _results(self, event):
            htmlPanel.html.LoadPage('\\Help\\results.html')

        def _interp(self, event):
            htmlPanel.html.LoadPage('\\Help\\interpretation.html')


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

输出:

>>> Traceback (most recent call last):
  File "c:\Python\testing\splitterwindow.py", line 100, in <module>
    frame = HelpMenu(None)
  File "c:\Python\testing\splitterwindow.py", line 13, in
__init__
    window1 = NavBar(splitter)
  File "c:\Python\testing\splitterwindow.py", line 60, in __init__
    self.welcome.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self._welcome)
AttributeError: 'TreeItemId' object has no attribute 'Bind'
>>> C:\Python\testing>

我怀疑self.welcome 不是指节点本身,而是指其他东西,这就是错误的根源。我只是不太确定如何引用树控件中的实际节点/文本才能将事件处理程序绑定到它。

编辑 Rolf 让我完成了 99% 的工作,除了这种奇怪的行为,只有根填充 - 没有孩子。请看下面的截图。

【问题讨论】:

  • Bindself.tree 然后解释该事件,但该代码存在不止 1 个问题。
  • 事件处理程序如何知道选择/激活了哪个节点?我看到有人提到有人监视光标并检查左键单击时的 x,y 位置,检查光标下的哪个(如果有)节点,如果是,则调用适当的事件处理程序......但这似乎对于应该很简单的事情来说真的很老套和复杂,不是吗?
  • 查看我发布的答案。它也可能被认为有点 hacky,但它确实有效。

标签: html python-3.x user-interface wxpython treecontrol


【解决方案1】:

这是您的代码模型,我已经对其进行了调整,以使用 treectrl 中的标签来决定要显示的内容。

import wx
import wx.html


class HelpMenu(wx.Frame):
    def __init__(self, parent):
        tstr = "Need help?"
        super(HelpMenu, self).__init__(
            parent, -1, title=tstr, size=wx.Size(800, 500), style=wx.CAPTION |
            wx.CLOSE_BOX | wx.SYSTEM_MENU | wx.RESIZE_BORDER)

        splitter = wx.SplitterWindow(self)
        window1 = NavBar(splitter)
        window2 = htmlPanel(splitter)
        splitter.SplitVertically(window1, window2)
        splitter.SetSashGravity(0.5)
        # splitter.SetMinimumPaneSize(20)

        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(splitter, 1, wx.EXPAND)
        self.SetSizer(sizer)
        self.Show()

class htmlPanel(wx.Panel):
    def __init__(self, parent):
        super(htmlPanel, self).__init__(parent)

        self.html = wx.html.HtmlWindow(self)
        if 'gtk2' in wx.PlatformInfo:
            self.html.SetStandardFonts()

        htmlszr = wx.BoxSizer(wx.VERTICAL)
        htmlszr.Add(self.html, 1, wx.EXPAND)
        self.html.LoadPage('index.html')
        self.SetSizer(htmlszr)


class NavTree(wx.TreeCtrl):
    def __init__(self, parent, id, pos, size, style):
        super(NavTree, self).__init__(parent, id, pos, size, style)


class NavBar(wx.Panel):
    def __init__(self, parent):
        super(NavBar, self).__init__(parent)
        self.tree = NavTree(
            self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TR_HAS_BUTTONS)
        self.parent = parent
        self.root = self.tree.AddRoot('Help Contents')
        self.welcome = self.tree.AppendItem(self.root, 'Start Page')
        self.background = self.tree.AppendItem(self.root, 'Background')
        self.method = self.tree.AppendItem(self.root, 'Calculation Method')
        self.using = self.tree.AppendItem(self.root, 'Using the Calculator')
        self.start = self.tree.AppendItem(self.using, 'Selecting Data Type')
        self.params = self.tree.AppendItem(self.using, 'Setting Parameters')
        self.results = self.tree.AppendItem(self.using, 'Viewing Results')
        self.interp = self.tree.AppendItem(self.root, 'Interpreting Results')
        # insert more children of interp here for various issues concerning
        # interpretation
        self.tree.ExpandAll()
        self.tree.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self._click)

        self.treeszr = wx.BoxSizer(wx.VERTICAL)
        self.treeszr.Add(self.tree, 1, wx.EXPAND)
        self.SetSizer(self.treeszr)

    def _click(self, event):
        item = event.GetItem()
        label = self.tree.GetItemText(item)
        print(label)
        if label == 'Help Contents':
            self._welcome()
        elif label == 'Background':
            self._background()
        elif label == 'Calculation Method':
            self._method()
        elif label == 'Start Page':
            self._start()
        elif label == 'Selecting Data Type':
            self._using()
        elif label == 'Setting Parameters':
            self._params()                                            
        elif label == 'Viewing Results':
            self._results()        
        elif label == 'Interpreting Results':
            self._interp()

    def _welcome(self):
        self.parent.GetWindow2().html.LoadPage('index.html')

    def _background(self):
        self.parent.GetWindow2().html.LoadPage('background.html')

    def _method(self):
        self.parent.GetWindow2().html.LoadPage('method.html')

    def _using(self):
        self.parent.GetWindow2().html.LoadPage('use.html')

    def _start(self):
        self.parent.GetWindow2().html.LoadPage('index.html')

    def _params(self):
        self.parent.GetWindow2().html.LoadPage('params.html')

    def _results(self):
        self.parent.GetWindow2().html.LoadPage('results.html')

    def _interp(self):
        self.parent.GetWindow2().html.LoadPage('interp.html')

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

这是 NavBar 类的一个变体,使用 lists 处理文本和相关 html 文件,只需使用索引位置进行链接。

class NavBar(wx.Panel):
    def __init__(self, parent):
        super(NavBar, self).__init__(parent)
        self.labs = ['Help Contents', 'Start Page', 'Background', 'Calculation Method', 'Using the Calculator',\
                     'Selecting Data Type', 'Setting Parameters', 'Viewing Results', 'Interpreting Results']
        self.pages = ['index.html','index.html','background.html','method.html',None,'use.html',\
                      'params.html','results.html','interp.html']
        self.tree = NavTree(
            self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TR_HAS_BUTTONS)
        self.parent = parent
        self.root = self.tree.AddRoot(self.labs[0])
        self.tree.AppendItem(self.root, self.labs[1])
        self.tree.AppendItem(self.root, self.labs[2])
        self.tree.AppendItem(self.root, self.labs[3])
        self.using = self.tree.AppendItem(self.root, self.labs[4])
        self.tree.AppendItem(self.using, self.labs[5])
        self.tree.AppendItem(self.using, self.labs[6])
        self.tree.AppendItem(self.using, self.labs[7])
        self.tree.AppendItem(self.root, self.labs[8])
        # insert more children of interp here for various issues concerning
        # interpretation
        self.tree.ExpandAll()
        self.tree.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self._click)

        self.treeszr = wx.BoxSizer(wx.VERTICAL)
        self.treeszr.Add(self.tree, 1, wx.EXPAND)
        self.SetSizer(self.treeszr)

    def _click(self, event):
        item = event.GetItem()
        label = self.tree.GetItemText(item)
        if label:
            pass
        else:
            return
        index = self.labs.index(label)
        if self.pages[index]:
            self.parent.GetWindow2().html.LoadPage(self.pages[index])

【讨论】:

  • 啊,是的,我的代码中确实发现了一些愚蠢的错误。你总是在拯救我的皮肤,罗尔夫!虽然,运行代码,treectrl 并没有为我填充。我让根节点显示,index.html 正确加载,并且没有抛出任何错误,但没有一个子节点填充在树中。我在原始帖子中添加了一个屏幕截图以显示我得到的内容。注意:我稍微调整了您的代码,然后得到了错误,但即使直接从您的帖子复制/粘贴(并将 .html 文件移动到正确的目录),行为也是相同的。
  • 查看编辑后的答案。我只是添加了self.tree.ExpandAll()。您可以展开项目、节点或所有内容。
  • 啊,我认为默认行为是让孩子们展开。罗尔夫再次拯救了这一天!干杯!
猜你喜欢
  • 2020-12-28
  • 2012-02-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-25
  • 1970-01-01
  • 2011-06-06
  • 2011-10-27
相关资源
最近更新 更多