Childwindows im Nachhinein einfügen
-
ok, ich habe jetzt eine Notlösung gefunden die funktioniert, auch wenn es wirklich keine schöne Lösung ist!
wäre toll wenn jemand eine bessere wüsste!

hier mal die Notlösung, das sollte aber nach Möglichkeit nicht so bleiben
:struct Child { HWND parent; int x; int y; int breite; int höhe; HMENU hmenu; HINSTANCE hi; string fensterklasse; string fenstername; DWORD style; }; vector<Child> zu_erstellen; void child_einfügen(HWND parentfenster, int x_oben_links, int y_oben_links, int b, int h, HMENU hmen, HINSTANCE hinstance, string fensterklasse, string fenstername, DWORD windowstyle) { Child c; c.parent=parentfenster; c.x=x_oben_links; c.y=y_oben_links; c.breite=b; c.höhe=h; c.hmenu=hmen; c.hi=hinstance; c.fensterklasse=fensterklasse; c.fenstername=fenstername; c.style=windowstyle; zu_erstellen.push_back(c); } HWND child_erstellen(Child c) { HWND hwnd= CreateWindowA(c.fensterklasse.c_str(), c.fenstername.c_str(), c.style, c.x, c.y, c.breite, c.höhe, c.parent, c.hmenu, c.hi, 0); return hwnd; } vector<HWND> childs; void alle_erstellen() { for(int a=0;a<zu_erstellen.size();a++) { childs.push_back(child_erstellen(zu_erstellen[a])); } zu_erstellen.clear(); } DWORD WINAPI dateifenster(LPVOID IpParameter) { WNDCLASS wc; wc.cbClsExtra=0; wc.cbWndExtra=0; wc.hbrBackground=(HBRUSH) GetStockObject(WHITE_BRUSH); wc.hCursor=LoadCursor(hi3, IDC_ARROW); wc.hIcon=LoadIcon(hi3, IDI_WINLOGO); wc.hInstance=hi3; wc.lpfnWndProc=WndProc3; wc.lpszClassName=TEXT("Dateifenster"); wc.lpszMenuName=0; wc.style=CS_HREDRAW|CS_VREDRAW; RegisterClass(&wc); parent=CreateWindow(TEXT("Dateifenster"), TEXT("Dateimanager"), WS_OVERLAPPEDWINDOW, 100, 100, 600, 600, 0, 0, hi3, 0); UpdateWindow(parent); ShowWindow(parent, SW_NORMAL); MSG msg; while(GetMessage(&msg, 0, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); if(zu_erstellen.size()>0) { alle_erstellen(); } } return msg.wParam; } int main() { DWORD id; HANDLE h=CreateThread(0, 0, dateifenster, 0, 0, &id); //Simulation eines bei Bedarf eingefügten Childs: Sleep(3000); child_einfügen(parent, 200, 200, 100, 40, (HMENU) 5, hi3, "BUTTON", "testbutton2", BS_PUSHBUTTON|WS_CHILD|WS_VISIBLE); WaitForSingleObject(h, INFINITE); }das wird aber hoffentlich nicht die dauerhafte lösung, es kann ja nicht sein dass man sowas in die Nachrichtenschleife packen muss, da gehört es nun wirklich nicht hin...
allerdings sehe ich keine ander Lösung momentan weil ich den thread sobald er in der Nachrichtenschleife ist nicht mehr "verwenden" kann zum Fenstererstellen. trtotzdem hoffe ich dass jemand eine bessere Idee hat.lg,
andi01.
-
IMHO ist das keine Notlösung,..
sondern ist prinzipiell gutes dünken...Denn was wäre die alternative:
n static pointed array in der (Main)WinProc die auf bedarf die fenster erstellt,....Und das ist unübersichtlich (Habe das blöderweise in einem Project so gemacht, mit der folge von xKLOC quasi unübersichtlicher Code,...)
Ich würde den Globalen Vektor aber noch threadsafe machen, sonst könnte der zugriff auf diesem nachher laufzeitfehler verursachen,....
Grüße ..
----------------------------------------------------------------------------
Edit:
Ne kleine alternative evtl.:while(sgn) { if(etwas_zu_erstellen) erstelle(); if(PeekMessage(&msg,..)) { } else { Sleep(12); }; }
-
Wenn man irgendwelche langwierigen Abläufe im Programm hat, dann erstellt man einen Threat der läuft parallel zum Hauptthreat. Der Hauptthreat ist für die Bedienung des Hauptfensters und seiner Elemente verantwortlich. Im Hauptthreat kann doch auch die Progressbar erzeugt werden, der Workingthreat setzt dann nur noch den Balken der Progressbar.
Wo ist das Problem?
-
Vermeide es Child Windows in anderen Threads zu erzeugen.
Ich würde grundsätzlich immer zu folgendem Vorgehen raten:
1. GUI Thread: In dem Du auch on the fly Fenster erzeugen kannst.
2. Workerthread der die Arbeitmacht. Der sendet/postet Nachrichten oder benutzt andere IPC (Events, Queues etc.) für den Datenaustausch.
3. Der UI Thread ist für die Nachrichtenbheandlung zuständig.Mehrere UI Threads sind möglich aber ein nicht ganz ungefährlicher Konstrukt. Alleine was Modale Fenster betrifft etc... Es geht aber man muss ganz genau wissen was man tut.
Deine Methode ist nicht ok weil:
- Sobald Dein Child an das Parent etwas sendet (und das sind nicht wenige Nachrichten), kann dieses locker blockieren, weil Du im Main-Thread ein WaitForSingleObject machst.
- Zudem werden alle anderen Fenster im Main Thread durch den WaitForSngleObject unresponsive. D.h. es werden keine Nachrichten mehr für diese Fenster empfangen.
- Du räumst nicht auf. Du verlässt Dich darauf, dass der terminierende Thread alle Fenster killt.
-
Martin Richter schrieb:
Deine Methode ist nicht ok weil:
- Sobald Dein Child an das Parent etwas sendet (und das sind nicht wenige Nachrichten), kann dieses locker blockieren, weil Du im Main-Thread ein WaitForSingleObject machst.
- Zudem werden alle anderen Fenster im Main Thread durch den WaitForSngleObject unresponsive. D.h. es werden keine Nachrichten mehr für diese Fenster empfangen.
- Du räumst nicht auf. Du verlässt Dich darauf, dass der terminierende Thread alle Fenster killt.Hi Martin,
wenn bekannt ist, das in jedem thread in welches ein fenster erstellt wird, auch ein message handler sein muss, dann sollte dies doch kein problem darstellen...?!Sein Message Handler is innerhalb des seperaten Thread in welchem das Hauptfenster und die Childwindows erstellt werden.
Daher sehe ich nicht die von Dir angesprochenen Probleme.
Grüße
-
Martin Richter schrieb:
Ich würde grundsätzlich immer zu folgendem Vorgehen raten:
1. GUI Thread: In dem Du auch on the fly Fenster erzeugen kannst.
2. Workerthread der die Arbeitmacht. Der sendet/postet Nachrichten oder benutzt andere IPC (Events, Queues etc.) für den Datenaustausch.
3. Der UI Thread ist für die Nachrichtenbheandlung zuständig.2. ist klar, das mache ich sowieso.
aber zu 1. und 3.: das heißt, ich soll einen Thread machen in dem nur die Nachrichtenschleife läuft und einen zweiten der bei Bedarf Fenster erstellt?
ich habe das mal so versucht, um nicht schon wieder die ganzen unveränderten Funktionen zu posten hier nur mal ein Schema:
DWORD WINAPI Nachrichtenthread(LPVOID IpParameter) { //hier Nachrichtenschleife } DWORD WINAPI Workthread(LPVOID IpParameter) { //hier Arbeit } DWORD WINAPI Fensterthread(LPVOID IpParameter) { //hier Parent erstellen //hier fenster bei bedarf erstellen //hier keine Nachrichtenschleife }das Problem dabei ist, dass schon das Parent nicht auf Nachrichten reagiert weil es zu einem anderen thread gehört
.so ein Schema wäre bereits völlig ausreichend um den Ansatz zu verstehen, den Code für Nachrichtenschleifen und Fenster erstellen kann ich ja selbst einfügen, es geht nur darum wohin damit

wäre schön wenn jemand mal so ein Schmea postet damit ich verstehe was wohin muss, den Code füge ich dann selbst schon ein

lg,
andi01.
-
Hi,
Der Messagequeue ist threadspezifisch.
Du bekommst nur Nachrichten aus diesen Queue für ein Window das Du auch innerhalb des Threads erstellt hast!Anstatt IPC würde ich lieber ITC's nehmen, ein zwo signale und ein locked speicherbereich reichen da völlig, um dies ThreadSafe zu machen.
Das mit den WorkerThreads ist dann halt so eine sache,..
Du musst aufpassen dass am ende auch das Handle zu diesem geschlossen wird, damit diese resourcen dann auch wieder frei gegeben werden.Sollteste also aus der WndProc oder ähnlich heraus den thread erzeugen, solltest Du darauf achten das:
a) wirklich nur genau einer, oder halt ganeu die geforderte anzahl, an workerthreads erzeugt werden.
b) das Du nach dem ende des threads auch ordentlich aufräumst...Bei mir sieht dies ähnlich deinem ansatz von weiter oben:
DWORD WINAPI namespace::class_or_struct_or_extern::threadproc(LPVOID lpParam) { this->tssSignal._set_sgn(true); //signal das der thread gestartet ist while(!this->tssSignal._get_done()) { //some windows to create? if(this->__serialize()) { if(this->_winVec.size()>0) { winVec::iterator itCount = this->_winVec.begin(); winVec::iterator itEnd = this->_winVec.end(); for(;itCount<itEnd;itCount++) { (*itCount)->_CreateWindow(); }; this->_winVec.clear(); }; this->__unserialize(); } //und nun das message handling MSG msg={0}; if(PeekMessage(&msg,0,0,0,PM_REMOVE)) { if(msg.message==WM_QUIT) { this->tssSignal._set_done(true); } else { TranslateMessage(&msg); DispatchMessage(&msg); } } else { Sleep(12); }; }; return 0; };greetz
-
gut, so funktionert es

danke an alle!
lg,
andi01.
-
Ich verstehe immer noch nicht warum und wieso ihr Fenster in einem anderen Thread erzeugen wollt und müsst!

-
ich kann das Erstellen der Fenster ja in den Primärthread verlegen

es ging mir nur darum wie ich es mit einem Thread hinbekomme on the fly Fenster zu erstellen, aber das hat sich ja geklärt.
und der Code ändert sich nicht wirklich, er steht eben in main() statt in einem anderen Thread, aber jetzt weiß ich endlich wie man on the fly Fenster erzeugt

nochmal danke an alle!
lg,
andi01.