Qt4 jest fajne. Ale… nie zawsze, jak to zwykle w życiu bywa. Piszę aplikację, która składa się z kilku mniejszych aplikacji i jednego GUI nadrzędnego, hosta, w którym osadzone są te mniejsze. Całe szczęście, że składniki również ja piszę, inaczej byłby niezły problem.
W czym problem? Ano w tym, że zawsze do tej pory do osadzania okna w oknie pod kontrolą Windows, używałem funkcji tego typu:
void CWinSystemTools::reparentWindow(HWND hWindow, QWidget *widget) { if (hWindow == 0) return; DWORD style = GetWindowLong(hWindow, GWL_STYLE); style = style & ~(WS_POPUP); style = style & ~(WS_OVERLAPPEDWINDOW); style = style | WS_CHILD; SetWindowLong(hWindow, GWL_STYLE, style); SetParent(hWindow, widget->winId()); }
i wszystko pięknie działa, dopóki oknem osadzanym nie jest aplikacja, która również jest napisana w Qt. Dlaczego? Ano dlatego, że w przeciwieństwie do każdej innej aplikacji, która po takim powyżsyzm zabiegu pięknie działa osadzona w okienku wewnętrznym, aplikacja Qt przestaje działać – w sensie, przestaje działać obsługa eventów. Wszelkie buttony, menu itp. mówią: “jak tak, to ja strajkuję!”. Ok, powiedziałem, i przekompilowałem aplikację-dziecko na bibliotekę, w aplikacji-rodzicu tworząc ręcznie obiekt typu QMainWindow tego nieposłusznego dziecka.
aplikacja_dziecko = new CChildApp(ui.widget_rodzica_dla_dziecka, Qt::Widget); aplikacja_dziecko->show();
Efekt? Kicha… Okno pokazuje się wcale nie przywiązane do widgetu – a na dodatek diabelskie eventy nadal nie działają! Użycie funkcji przeparentowania okna pomaga na osadzenie, ale eventów brak. Rozwiązanie? Ano, konstruktor klasy QMainWindow ignoruje parametr windowFlags, wstawiając tam na sztywno Qt::Window, dlatego trzeba:
aplikacja_dziecko = new CChildApp(ui.widget_rodzica_dla_dziecka); aplikacja_dziecko->setWindowFlags(Qt::Widget); aplikacja_dziecko->show();
i… nagle wszystko działa! Zarówno osadzenie okna w widgecie, jak i eventy 🙂 Pozostaje tylko przenieść resource’y z aplikacji dziecka. Oczywiście, dla porządku, jeśli ktoś się nie domyśla, takiemu osadzonemu oknu trzeba mówić, kiedy i jak ma zmieniać swój rozmiar: w aplikacji nadrzędnej definiujemy:
void CParentApp::resizeEvent(QResizeEvent *event) { if (aplikacja_dziecko) aplikacja_dziecko->resize(ui.widget_rodzica_dla_dziecka->size()); }
i wszystko śmiga, jak należy 🙂 Oczywiście, nadal pozostaje otwarte pytanie, co zrobić, gdy do dyspozycji mamy tylko exeka, którego chcemy osadzić – tu nadal problemu nie rozgryzłem. Trzeba się wystrzegać osadzania w ten sposób aplikacji qtowych 😉 Powodzenia!