BroadCast
-
hi,
hab zwei komponenten. diese sollen untereinander daten austauschen können, aber auch unabhängig von einander funktionieren sollen. also habe ich einige messages definiert und sende diese über Broadcast an die ParentForm der steuerelemente, damit diese an alle untergeordneten steuerelemente geschickt wird.
// messages #define RSM_MYMESSAGE (WM_USER + 1000) // funktion zum versenden der message void __fastcall TKompo1::BroadcastMessage(UINT Message, WPARAM WParam, LPARAM LParam) { TMessage Msg; Msg.Msg = Message; Msg.WParam = WParam; Msg.LParam = LParam; TCustomForm *Form = GetParentForm(this); if (Form) Form->Broadcast(&Msg); } // beim click in der komponente, message versenden void __fastcall TKompo1::Click(void) { BroadcastMessage(RSM_MYMESSAGE, (WPARAM) &Data, 0); }
abgefangen wird dann per:
void __fastcall TKompo2::WndProc(Messages::TMessage &Message) { // geerbte Fensterprozedur aufrufen inherited::WndProc(Message); if (Message.Msg == RSM_MYMESSAGE) { // was machen } }
BroadCast wird aufgerufen. die ParentForm ist auch vorhanden.
problem ist, dass die message nicht ankommt!
-
Ist TKompo2 evtl. nicht von TWinControl abgeleitet?
-
Ich wuerde
inherited::WndProc(Message);
am Ende von WndProc rufen!
Was liefert GetParentWindow(...)?
Kommt das Handle der Form?
-
die eine komponente ist ein TTreeView (von TCustomTreeView) und die andere eine TListView (von TCustomListView).
das Handle der ParentForm ist vorhanden.
komischerweise funktioniert es nun schon fast. das verschieben von inherited::WndProc hat nix geholfen...
wenn ich die message sende, dann übergebe ich noch eine struktur, die der empfänger auswerten und dann damit weiterarbeiten soll.
// message #define RSM_TV_NODECHANGED (WM_USER + 1000) // struktur typedef struct _TNodeData { LPSHELLFOLDER ShellFolder; LPITEMIDLIST FullID; LPITEMIDLIST ID; LPITEMIDLIST ParentID; // !!! mit diesem parameter kommt die message nicht an ?!? } TNodeData, *P_TNodeData;
bsp. im TreeView
// im OnChanging-Ereignis // Data ist eine weitere struktur die verschiedene daten enthält... TNodeData NodeData; NodeData.ShellFolder = Data->ShellFolder; // LPSHELLFOLDER NodeData.ID = Data->ID; // LPITEMIDLIST NodeData.FullID = Data->FullID; // LPITEMIDLIST NodeData.ParentID = NULL; // message senden // funktion siehe obigen post BroadcastMessage(RSM_TV_NODECHANGED, (WPARAM) &NodeData, 0);
im listview dann
void __fastcall TShellListView::WndProc(Messages::TMessage &Message) { if (Message.Msg == RSM_TV_NODECHANGED) { TNodeData *NodeData = (P_TNodeData) Message.WParam; // daten aus der message lesen LPSHELLFOLDER ParentShellFolder = NodeData->ShellFolder; LPITEMIDLIST ParentID = NodeData->ID; LPITEMIDLIST ParentFullID = NodeData->FullID; // listview neu füllen Reload(ParentShellFolder, ParentID, ParentFullID); } // geerbte Fensterprozedur aufrufen inherited::WndProc(Message); }
wenn ich in der Struktur TNodeData, das Element ParentID entferne, kommt die message bei der ListView an. wenn ich sie dagegen einfüge, komischerweise nicht.
erstelle ich die struktur falsch, bzw. übergebe ich sie falsch?
-
habs jetzt mit RegisterWindowMessage probiert und eine anderen struktur (die 4 int und 1 ansistring enthielt), jedoch komme ich zum selben ergebnis. die message kommt nicht an.
mit 3 elementen in der struktur gehts, mit mehreren nicht... *haarerauf*
-
ha, hatte das selbe Problem.
-> Das ist ein BUG !
Teste folgendes:
1. Mach mal ne Schleife mit Parent->ComponentsCount
du wirst feststellen, dass ComponentCount 0 ist, obwohl da Steuerelemete drauf sind.
2. Jetzt zahl mal mit ControlCount -> Verblüffend....
3. Jetzt geh mal hin und nehm alle anderen Komponeten vom Parent deiner Objekte. Ausser deine Objekte selbst. Mach nun mal ein ComponentCount auf den Parent -> es geht !
Ich sag nur Stichwort TLabel !
Hat mir auch Haare gekostet....
Wenn du eine Lösung ausser COntrolCount (was man ja eigentlich nicht mehr verwenden sollte) so gib bitte Bescheid.
-
naja ControlCount gibt mir 5 zurück und ComponentCount 11.
habe in meiner testform 2 panels, auf denen sich buttons befinden. die werden von controlcount nicht gefunden, lediglich die beiden panels, der treeview, listview und ein splitter. componentcount findet alles.
und das ist auch wieder was, was ich nicht verstehe, der treeview wird gefunden, erhält aber nie die botschaft die ich abschicke...
und broadcast schickt nur an alle elemente die controlcount findet, d.h. wenn der treeview oder listview auf nem panel liegt, kommt die nachricht nie an.
-
AndreasW schrieb:
1. Mach mal ne Schleife mit Parent->ComponentsCount
du wirst feststellen, dass ComponentCount 0 ist, obwohl da Steuerelemete drauf sind.
ComponentCount gibt die Zahl der Elemente zurück, die dem betreffenden Objekt gehören.
Parent <> Owner
Ein Label auf einem Panel gehört standardmässig weiterhin der Form, es sei denn, es wurde explizit mit dem Panel als Owner erzeugt. ControlCount gibt dagegen die Zahl der Elemente zurück, für die das betreffende Objekt Parent ist.
COntrolCount (was man ja eigentlich nicht mehr verwenden sollte)
Wer sagt das?
-
hah... wenn ich in der TMessage-Struktur vor dem Broadcast noch
Msg.Result = 0;
setze, kommen die messages an...
bleibt nur das problem mit dem broadcast und dem fall, dass die komponente auf nem panel liegt, da hilft wahrscheinlich nur, das broadcast selber zu machen und an jede windowproc() aller komponenten der form die message zu schicken...
-
Hi,
@Jansen: das stand irgendwo in der Hilfe oder in der newsgroup...
Erklär mir mal, warum Brodcast auf einmal funktioniert, wenn man Label vom Panel entfernt. Die Objekte empfangen dann die Message. Nimmt man ein Label auf den Parent wieder drauf gehts nicht mehr. Da kann doch was nicht stimmen.
Der Sinn von Brodcast ist, nachrichten an alle Komponenten auf den Objekt zu senden. Das macht er aber nur, wenn kein Label drauf ist. Das kann doch nicht richtig sein.@Sunday: Hast du diese Phänomen auch ?
-
also bei mir machen die labels keine probleme. probiere es mal mit dem Msg.Result = 0;
-
ok, probier ich Montag. Hab gerad Stress...
-
Hi,
bin jetzt erst dazu gekommen, dass zu überprüfen
Brodcast von TWinControl ist so definiert:
procedure TWinControl.Broadcast(var Message); var I: Integer; begin for I := 0 to ControlCount - 1 do begin Controls[I].WindowProc(TMessage(Message)); if TMessage(Message).Result <> 0 then Exit; end; end;
das erklärt einiges.
Wenn man nicht explizit Result auf 0 setzt ist Rsult undefiniert und damit <>0.
-
ja, genau... hab mir daher ne eigene broadcast-funktion geschrieben, bei der auch die komponenten erreicht werden, wenn sie auf einem panel oder in einer groupbox liegen.
//--------------------------------------------------------------------------- // Funktion sendet eine Message an alle, der ParentForm des übergebenen // Steuerelementes, untergeordneten Steuerelemente // -> wenn Message.Result != 0 ist, wird das Versenden abgebrochen //--------------------------------------------------------------------------- void ComponentBroadcast(TControl *Source, TMessage &Message) { TCustomForm *Form = GetParentForm(Source); if (Form && Source) { for (int i = 0; i < Form->ComponentCount; i++) { TControl *Control = dynamic_cast <TControl*> (Form->Components[i]); if (Control) { Control->WindowProc(Message); if (Message.Result != 0) return; } } } }
-
Funktioniert das auch, wenn, wie oben beschrieben, ein Control explizit mit abweichendem Owner erzeugt wird?
TLabel *label = new TLabel(Panel1);
Im ComponentCount von Form1 taucht dieses Label jedenfalls nicht mit auf.
-
hm dafür bräuchte man sicher noch ne zweite schleife über ControlCount der einzelnen Komponenten. hab jeze aber keine zeit zum probieren, denn ich fahre 2 wochen in urlaub...
-
hm, vielleicht besser so, wenn du schon die harte Tour gehst:
void ComponentBroadcast(TWinControl *Source, TMessage &Message) { if (Source) { Source->Broadcast(Message); if (Message.Result != 0) return; for (int i = 0; i < Source->ComponentCount; i++) { TWinControl *WinControl = dynamic_cast <TWinControl*> (Form->Components[i]); if (WinControl) { ComponentBroadcast(WinControl,Message)); if (Message.Result != 0) return; } } } }
Es ist allerding nicht immer erwünscht, die Komponeten auf allen Ebenen (wie Panels GroupBox usw.) anzusprechen .
-
Nachtrag:
...sonst würdest du nur die erste Ebene abdecken, was unter Umständen zu Verwirrung führen kann...