Osadzanie aplikacji Qt wewnątrz aplikacji Qt

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!
Facebooktwittergoogle_plusredditpinterestlinkedinmail
twitterlinkedin