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