Home > other >  wxpython - Using treectrl to load local html files into a panel
wxpython - Using treectrl to load local html files into a panel

Time:11-03

I'm trying to make a help menu in wxPython that has a tree control on the left and an html viewer on the right; the treecontrol acts as a sort of navigation menu, and on clicking an item in the treecontrol, the appropriate local .html file should load in the left panel.

However, when I try to implement this, I'm unable to bind any events to the different nodes in the tree control. This is what I have so far -- could someone show me where I'm going wrong?

Code:

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()

Output:

>>> 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>

I have a sneaking suspicion that self.welcome isn't referring to the node itself, but rather to something else, and this is the source of the error. I'm just not quite sure how to refer to the actual node/text in the treecontrol to be able to bind an event handler to it.

EDIT Rolf has me 99% of the way there, except for this weird behavior where only the root populates -- none of the children. See screenshot below.navbar fail

CodePudding user response:

Here's a mock-up of your code, which I've adapted to use the labels in the treectrl to decide what to display.

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()

enter image description here

Here's a variant of the NavBar class using lists for the text and related html files, linked simply using the index position.

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])
  • Related