Jedenfalls würde ich die struct gerne in einem treeview anzeigen...
Seit Monaten höre ich in dem Zusammenhang man solle uitree nutzen...
Aber wie? Für Verzeichnisse oder Models ist das kein Problem, aber struct werden -denke ich- nicht standardmäßig unterstützt...
Man muss denke ich in der uitree.m in der processNode Funktion eine weitere Fall abfrage mit isstruct durchführen...aber wie wird dann der node gebildet?
schön, dass mit diesen Beiträgen endlich eine Lösung für ein Thema vorgeschlagen wird, dass in diesem Forum schon in mehreren Beiträgen andiskutiert, aber nie richtig gelöst wurde.
Begeistert habe ich mit dem Vorschlag der obigen Funktionen herumgespielt und auch versucht, den Quellcode nachzuvollziehen.
Leider führt bei meinem struct, der in verschiedenen Ebenen Arrays enthält (MeinStrukt(1:x).Unterstrukt ...) die Funktion fieldnames(MeinStrukt) zu einem Error. Mir fehlen allerdings die informatischen Fertigkeiten, dieses Problem in die Unterfunktion einzubauen. Daher meine Frage an Zenon oder andere pfiffige Programmierer:
Wie muss ich die Unterfunktion umschreiben, damit die Funktion fieldnames() ein oder alle Elemente einer Liste beachtet und zu keinem Fehler führt?
Anmerkung: Meine unterschiedlichen Unterelemente haben die gleiche Struktur. Daher würde zur Veranschaulichung der Struktur eine Lösung mit nur einem Element erst mal reichen:
Code:
MeinStrukt(1).Unterstrukt.UUstrukt = struct();
MeinStrukt(2).Unterstrukt.UUstrukt = struct();
% Diese Abfrage führt zu einem Fehler: fieldnames(MeinStrukt.Unterstrukt)
merci für den Hinweis mit den eckigen Klammern. Bei mehrfacher Verzweigung funktioniert die Funktion fieldnames() allerdings auch mit eckigen Klammern nicht. Es erscheint der Fehler:
"??? Dot name reference on non-scalar structure.".
inzwischen habe ich den Code von Denny noch erweitert, um einen vorhandenen Fehler zu entfernen. Bei mehreren Instanzen eines Unterobjekts ist die Auflistung in die Unter-Unter-Gruppe gerutscht. Zur Veranschaulichung nehme man z.B. eine Struktur mit mehreren Ebenen. In der Zweiten Ebene gibt es mehrere "Objekte" (A,B,C) und von diesen mehrere "Instanzen" (B(1), B(2), ...., B(5))
Im Vorschlag von Denny muss folgende Funktion ersetzt werden.
Code:
function nodes = struct_tree_expfcn(tree, value, S) ifeval(sprintf('isstruct([%s])',value))% Wenn die Variable ein Struct ist
nodeIdcs = eval(sprintf('length([%s])',value));
if nodeIdcs==1% Wenn direkt die nächst-niedrieger Ebene folgen soll
nodeNames = eval(sprintf('fieldnames(%s)',value)); % cellarray mit feldernamen for nodeIdx = 1:length(nodeNames)% Unterstruktur % Erstellen des jeweiligen Unterknotens:
nodes(nodeIdx) = uitreenode(...
'v0',... sprintf('%s.%s',value,nodeNames{nodeIdx}), ... sprintf('%s',nodeNames{nodeIdx}),... [],... eval(sprintf('~isstruct(%s.%s)',value,nodeNames{nodeIdx})));
end elseif nodeIdcs > 1% Wenn die Instanzen in einem Sammler gebündelt werden sollen for nodeIdx = 1:eval(sprintf('length([%s])',value))
nodes(nodeIdx) = uitreenode(...
'v0',... sprintf('%s(%d)',value,nodeIdx), ... sprintf('%s(%d)',name_substruct_extr(value),nodeIdx),... [],... eval(sprintf('~isstruct(%s(%d))',value,nodeIdx)));
end end else
nodes = [];
end
In der obigen Funktion werden aus Übersichtlichkeitsgründen mehrere "Instanzen" eines Objekts in dessen "Objektsammler" gebündelt. D.h. der Baum zeigt dann "T-- +A -- +A(1) -- Wert" statt "T -- +A(1) -- Wert".
Für Neulinge noch ein paar Informationen zum Verständnis bzw. zum Ausprobieren, wenn man selbst den Code verändern möchte:
(A)
"struct_tree_expfcn" ist eine Callback-Funktion. Callbackfunktionen gibt es bei GUI's. In ihnen wird definiert, welche Reaktion auf ein Ereignis passieren soll. Das Ereignis ist der Mausklick auf einen Knoten im Fenster des Baumes. Wurde der Knoten bisher noch nicht angeklickt, so wird in der Callback-Funktion ein Unterknoten erstellt. Anders gesagt erstellt die Funktion also keinen vollständigen Baum im Voraus, durchsucht also nicht die gesamte Struktur, sondern reagiert nur auf Interaktion und wird dann tätig.
(B)
Will man nun den Code durch debuggen verstehen, so muss man die berühmten Käfer (Haltepunkte) setzen UND dann ein Ereignis auslösen, damit die Callback-Fcn aufgerufen wird - ALSO einen Knotenpunkt expandieren (aufs plus-Zeichen klicken).
(C)
Noch eine Anmerkung zur uitreenode-Fkt. Die Argumente lauten: 1.) Fehlerunterdrückung, 2.) Pfad des Knotens, 3.) Anzeigenahme des Knotens im Fenster, 4.) Pfad zu einem Symbol des Knotens, 5.) ???.
Folgende offene Fragen habe ich selbst noch:
(1)
In der Konsole erscheint beim Anklicken des Astendes eine Ausgabe, sie beginnt mit "S." und nicht mit dem Namen des Structs
(2)
Bei der Ausgabe der Variablen, die am niedrigsten Punkt eines Baumes hängt, kommt es zu Problemen. Im obigen Beispiel ist das T. ... . ... .Wert. Ist es ein einzelner Wert, so ist alles O.K.. Ist "Wert" ein Vektor, so wird in der Matlab-Konsole Müll angezeigt, geschweigedenn bei Cells etc.
Es freut mich sehr, dass du den Code weiter ausbaust.
zu Frage (1):
Es liegt daran, dass in Callbacks (wie ExpandFcn und SelectionChangeFcn) der Strukturname fest ist. Da muss der Strukturname in Callbacks den Rootnamen annehmen. (siehe dazu den beigefügten Code):
zu Frage(2)
Da muss man die Ausgaben in SelectionChangeFcn erweitern. Dazu hab ich den Code einwenig verändert
(siehe dazu auch den den beigefügten Code)
%----------------------------- struct_tree_expfcn --------------------------
%
% input : % output:
%-------------------------------------------------------------------------------
function nodes = struct_tree_expfcn(tree, value, S,rootname) eval(sprintf('%s=S;',rootname));
ifeval(sprintf('isstruct([%s])',value))% Wenn die Variable ein Struct ist
nodeIdcs = eval(sprintf('length([%s])',value));
if nodeIdcs==1% Wenn direkt die nächst-niedrieger Ebene folgen soll
nodeNames = eval(sprintf('fieldnames(%s)',value)); % cellarray mit feldernamen for nodeIdx = 1:length(nodeNames)% Unterstruktur % Erstellen des jeweiligen Unterknotens:
nodes(nodeIdx) = uitreenode(...
'v0',... sprintf('%s.%s',value,nodeNames{nodeIdx}), ... sprintf('%s',nodeNames{nodeIdx}),... [],... eval(sprintf('~isstruct(%s.%s)',value,nodeNames{nodeIdx})));
end elseif nodeIdcs > 1% Wenn die Instanzen in einem Sammler gebündelt werden sollen for nodeIdx = 1:eval(sprintf('length([%s])',value))
nodes(nodeIdx) = uitreenode(...
'v0',... sprintf('%s(%d)',value,nodeIdx), ... sprintf('%s(%d)',name_substruct_extr(value),nodeIdx),... [],... eval(sprintf('~isstruct(%s(%d))',value,nodeIdx)));
end end else
nodes = [];
end
%---------------------------- name_substruct_extr --------------------------
%
% input : % output:
%-------------------------------------------------------------------------------
function sname = name_substruct_extr(name)
pos = strfind(name,'.');
sname = name(pos(end)+1:end);
%----------------------------- struct_tree_selfcn --------------------------
%
% input : % output:
%-------------------------------------------------------------------------------
function struct_tree_selfcn(tree, event, S,rootname) eval(sprintf('%s=S;',rootname));
value = event.getCurrentNode.getValue;
ifeval(sprintf('~isstruct([%s])',value))
Res = eval(sprintf('{%s}',value));
for k=1:length(Res) switchclass(Res{k}) case 'cell'
if iscellstr(Res{k})
num_res = Res{k};
num_res = sprintf('%s\t',num_res{:});
fprintf('%s = {%s}\n', value,num_res);
else
num_res = Res{k};
num_res = sprintf('%d\t',num_res{:});
fprintf('%s = {%s}\n', value,num_res);
end case 'double'
num_res = sprintf('%d\t',Res{k});
fprintf('%s = [%s]\n', value,num_res) case 'char'
num_res = sprintf('%c',Res{k});
fprintf('%s = [%s]\n', value,num_res) end end fprintf('\n');
end
Du kannst Beiträge in dieses Forum schreiben. Du kannst auf Beiträge in diesem Forum antworten. Du kannst deine Beiträge in diesem Forum nicht bearbeiten. Du kannst deine Beiträge in diesem Forum nicht löschen. Du kannst an Umfragen in diesem Forum nicht mitmachen. Du kannst Dateien in diesem Forum posten Du kannst Dateien in diesem Forum herunterladen
MATLAB, Simulink, Stateflow, Handle Graphics, Real-Time Workshop, SimBiology, SimHydraulics, SimEvents, and xPC TargetBox are registered trademarks and The MathWorks, the L-shaped membrane logo, and Embedded MATLAB are trademarks of The MathWorks, Inc.