Hallo zusammen,
Ich habe ein TreeCtrl Element als "Custom Ctrl" Element eingebunden welches, wenn man auf eine Node klickt, die entsprechenden Daten in einem Notebook Tab laden soll. Wie stelle ich das am besten an? Ich habe die verschiedenen Events in der TreeCtrl Klasse definiert (z.b OnSelChanged) dort frage ich auch ab, welche Node gerade angeklickt wurde. In der Hauptklasse, wo ich die ganzen Ctrls einbinde, liegt auch mein Notebook somit auch mein Tab Handle. Muss ich nun das Tab Handle/Notebook an das TreeCtrl übergeben oder muss ich die Events für das TreeCtrl alle in der Hauptklasse definieren? Stehe auf dem Schlauch.
Gruss,
Vannid Burdon
Strukturproblem beim einbinden von TreeCtrl
Hi und willkommen im Python Forum.
Hab folgendes kurz geschrieben. Ich hoffe das Hilft dir weiter
Der kern ist halt das du die Daten, zu jeder Node im Tree, halt der Node hinzufügst. Bei abfragen holst du die Daten der Entsprechenden Node und gibst die dann wo immer du willst aus.
lg
Hab folgendes kurz geschrieben. Ich hoffe das Hilft dir weiter

Der kern ist halt das du die Daten, zu jeder Node im Tree, halt der Node hinzufügst. Bei abfragen holst du die Daten der Entsprechenden Node und gibst die dann wo immer du willst aus.
Code: Alles auswählen
#!/usr/bin/python
# -*- coding: utf-8 -*-
import os
import sys
from itertools import izip, count
import wx
wx.SetDefaultPyEncoding("utf-8")
class MainFrame(wx.Frame):
def __init__(self, parent=None, id=-1, title = "MyApp"):
wx.Frame.__init__(self, parent, id, title)
self.Centre()
self.panel = wx.Panel(self)
# TreeCtrl
self.tree = wx.TreeCtrl(
parent = self.panel,
id = -1,
style = wx.TR_DEFAULT_STYLE | wx.TR_HAS_VARIABLE_ROW_HEIGHT
)
# Rechtsklick event an `self.tree binden`
self.Bind(wx.EVT_TREE_ITEM_RIGHT_CLICK, self.TreeRightClick)
# Notebook
self.notebook = wx.Notebook(
parent = self.panel,
id = -1,
)
self.text_ctrl = wx.TextCtrl(self.notebook, style = wx.TE_READONLY |
wx.TE_MULTILINE)
self.notebook.AddPage(
page = self.text_ctrl,
text = "test",
select = True,
imageId = -1
)
# Sizer
sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer.Add(self.tree, 1, wx.EXPAND)
sizer.Add(self.notebook, 1, wx.EXPAND)
self.panel.SetSizerAndFit(sizer)
#
# Tree mit werten Füllen!
#
# Datentype definieren.
my_data = list()
for i in xrange(100):
my_data.append({
'text': 'foo %d' % i,
'value': i * i
# usw...
})
# Nun denn Tree erzeugen.
self.root = self.tree.AddRoot("Tree-Trunk")
for data, cntr in izip(my_data, count(1)):
# Neue Node zur root hinzufügen.
child = self.tree.AppendItem(self.root, "node %d" % cntr)
# So, nun fügen wir dieser Node daten hinzu :)
self.tree.GetItemData(child).SetData(data)
# Tree aufklappen...
self.tree.Expand(self.root)
def TreeRightClick(self, event):
# So nun erstmal die Child-Node holen.
child = event.GetItem()
# Wenn diese node nicht die root ist...
if child != self.root:
# so nun die Daten holen :)
data = self.tree.GetItemData(child).GetData()
print data
# Daten von dieser Node ins `self.text_ctrl` vom `self.notebook`
# anhängen.
self.text_ctrl.AppendText(
"text = %s; value = %d\n" % (data['text'], data['value'])
)
def main():
app = wx.PySimpleApp()
mf = MainFrame()
mf.Show()
app.MainLoop()
if __name__ == "__main__":
main()
Ach soVannid Burdon hat geschrieben:[...]Muss ich nun das Tab Handle/Notebook an das TreeCtrl übergeben oder muss ich die Events für das TreeCtrl alle in der Hauptklasse definieren? Stehe auf dem Schlauch.

Also so...Mit der Methode `self.notebook.GetPage(nummer_der_page)` kommst du dann an das Objekt der page (z.B. das TextCtrl in meinen Beispiel). Dann kannst du halt die Daten dort eintragen/Aktualisieren.
Code: Alles auswählen
def TreeRightClick(self, event):
# So nun erstmal die Child-Node holen.
child = event.GetItem()
# Wenn diese node nicht die root ist...
if child != self.root:
# so nun die Daten holen :)
data = self.tree.GetItemData(child).GetData()
print data
# Page (`self.text_ctrl`) vom `self.notebook` holen und
# daten anhängen.
text = self.notebook.GetPage(0) #<-- Page holen (`self.text_ctrl`)
text.AppendText(
"text = %s; value = %d\n" % (data['text'], data['value'])
)
-
- User
- Beiträge: 12
- Registriert: Freitag 22. Dezember 2006, 14:51
Hallo sape, erstmal Danke für die Antwort aber das trifft mein Problem noch nicht ganz.
Das ist meine "Custom TreeCtrl" Klasse, welche ich in die "Hauptklasse", wo unteranderem das Notebook definiert ist, aufgerufen wird.
Ist es nun eine gute Idee das Handle des Notebooks in die PluginTreeCtrl Klasse zu übergeben um somit in der OnSelChanged() den jeweiligen Inhalt der aktuellen Node in dem Notebook-Tab auszugeben?
Oder muss ich mit dem Handle der definierten PluginTreeCtrl Klasse in der Hauptklasse weiterarbeiten?
In deinen Beispielen verwendest du das TreeCtrl nur in einer einzigen Klasse und definierst dort alle Events der TreeCtrl Klasse. Wie gesagt dort stehe ich immer noch auf dem Schlauch.
Das ist, was ich mich frage, ob es eine gute Lösung wäre.Ach so Confused Du übergibst als Parameter den Notebook an die Klasse die das TreeCtrl hat. Mit der Methode `self.notebook.GetPage(nummer_der_page)` kommst du dann an das Objekt der page (z.B. das TextCtrl in meinen Beispiel). Dann kannst du halt die Daten dort eintragen/Aktualisieren.
Code: Alles auswählen
class PluginTreeCtrl(wx.TreeCtrl):
def __init__(self, *args, **kwds):
self.tree = wx.TreeCtrl.__init__(self, *args, **kwds)
#self.parent = parent
# {path:name}
self.module_container = {}
# (obj,name)
self.module_objects = []
root = self.AddRoot("Plugins")
self.parent = root
self.backup = self.parent
self._search("Plugins", [".py"])
self._load()
self.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnSelChanged)
def _search(self, dir, types):
for entry in os.listdir(dir):# jedes objekt im verzeichnis
path = os.path.join(dir, entry)
if os.path.isdir(path): #objekt ist ein verzeichnis
old_dir = self.parent
self.parent = self.AppendItem(self.parent,entry)
self._search(path, types)
# rekursiver auslauf
self.parent = old_dir
for type in types: # objekt ist eine datei
if path.endswith(type):
entry = os.path.splitext(entry)[0]
self.AppendItem(self.parent,entry)
self.module_container[os.path.split(path)[0]] = entry
def _load(self):
for path, name in self.module_container.items():
print path, name
try:
(file, path, desc) = imp.find_module(name, [path])
except ImportError:
continue
if file is None:
continue
try:
self.module_objects.append((imp.load_module(name, file, path, desc), name))
finally:
file.close()
def OnSelChanged(self, event):
selectedItem = self.GetItemText(event.GetItem())
for j,i in self.module_objects:
if selectedItem == i:
pass# später
Code: Alles auswählen
class Hauptklasse:
....
self.ControlPanel = wx.Notebook(self.SplitterPanelRight, -1, style=0)
self.window_1 = PluginTreeCtrl(self.SplitterPanelLeft, -1, style=wx.TR_HAS_BUTTONS|wx.TR_LINES_AT_ROOT|wx.TR_DEFAULT_STYLE|wx.SUNKEN_BORDER)
...
Ist es nun eine gute Idee das Handle des Notebooks in die PluginTreeCtrl Klasse zu übergeben um somit in der OnSelChanged() den jeweiligen Inhalt der aktuellen Node in dem Notebook-Tab auszugeben?
Oder muss ich mit dem Handle der definierten PluginTreeCtrl Klasse in der Hauptklasse weiterarbeiten?
In deinen Beispielen verwendest du das TreeCtrl nur in einer einzigen Klasse und definierst dort alle Events der TreeCtrl Klasse. Wie gesagt dort stehe ich immer noch auf dem Schlauch.
Oh, OK.
So wie ich deine Klasse verstehe (Korrigiere mich wenn ich falsch liege), listet es Plugins ein und stellt in jeder Node diverse Daten bereit, die man sich anzeigen lassen kann. Das Ziel wo die Daten angezeigt werden, sollte Flexibel sein und nicht nur auf eine Page von nem `wx.Notebook` beschränkt sein. Der Nutzer deine Klasse sollte also selber entscheiden wo er die Daten ausgeben will. Daher...
Mein Gefühl sagt mir das ich lieber mit dem Handle der `PluginTreeCtrl` arbeiten würde die mir alle benötigten Daten liefert. Also konkret gesagt, nicht das `self.ControlPanel`-Handle an `self.window_1` weiterreichen.
Das `wx.EVT_TREE_SEL_CHANGED` event würde ich Zusätzlich in `Hauptklasse` noch mal Binden um dann an die Benötigten Daten zu kommen die dann an der betreffenden Page vom `self.ControlPanel` "gesendet" werden.
Dadurch ist `PluginTreeCtrl` unabhängig und kann als eigenständiges Widget in verschiedene wx-Programmen genutzt werden. So kann der Empfänger der Daten einer Node alles beliebige sein und nicht nur eine Page von `wx.Notebook`. Wenn du jetzt in der `PluginTreeCtrl` Klasse es zum Bestandteil machst (Durch rüberreichen des Handles...), das der Empfänger immer eine Page von `wx.Notebook` ist, verliert dein Widget an Flexibilität.
Es ist halt, wie du schon erkennst, eine frage wie wiederverwendbar und flexibel dein Widget sein soll.
lg
So wie ich deine Klasse verstehe (Korrigiere mich wenn ich falsch liege), listet es Plugins ein und stellt in jeder Node diverse Daten bereit, die man sich anzeigen lassen kann. Das Ziel wo die Daten angezeigt werden, sollte Flexibel sein und nicht nur auf eine Page von nem `wx.Notebook` beschränkt sein. Der Nutzer deine Klasse sollte also selber entscheiden wo er die Daten ausgeben will. Daher...
Mein Gefühl sagt mir das ich lieber mit dem Handle der `PluginTreeCtrl` arbeiten würde die mir alle benötigten Daten liefert. Also konkret gesagt, nicht das `self.ControlPanel`-Handle an `self.window_1` weiterreichen.
Das `wx.EVT_TREE_SEL_CHANGED` event würde ich Zusätzlich in `Hauptklasse` noch mal Binden um dann an die Benötigten Daten zu kommen die dann an der betreffenden Page vom `self.ControlPanel` "gesendet" werden.
Code: Alles auswählen
class Hauptklasse:
def __init__(...):
...
self.ControlPanel = wx.Notebook(self.SplitterPanelRight, -1, style=0)
self.window_1 = PluginTreeCtrl(
self.SplitterPanelLeft,
id = -1,
style=wx.TR_HAS_BUTTONS |
wx.TR_LINES_AT_ROOT |
wx.TR_DEFAULT_STYLE |
wx.SUNKEN_BORDER
)
self.window_1.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnSelChanged)
def OnSelChanged(self, event):
# Hier dann alles holen und die Daten dan an den gewünschten
# Empfänger (z.B. Page von...) im Abschluss senden.
selectedItem = self.GetItemText(event.GetItem())
for j,i in self.window_1.module_objects:
if selectedItem == i:
pass# später
Es ist halt, wie du schon erkennst, eine frage wie wiederverwendbar und flexibel dein Widget sein soll.
lg