[Qt] Ręczne zagnieżdżanie QWidget'ów i błąd po wyłaczeniu aplikacji.

0

Mam takie klasy w hierarchii dziedziczenia:
mainframe.h (klasa odpowiedzialna za "ramkę" aplikacji):

class MainFrame: public QMainWindow {
    Q_OBJECT
public:
    explicit MainFrame(QWidget* canvas, QWidget* parent = nullptr);
    // ... pozostałe metody ...
};

canvas.h:

class Canvas: public QWidget {
    Q_OBJECT
    // ... pozostałe metody ...
};

konstruktor MainFrame w mainframe.cpp:

MainFrame::MainFrame(QWidget* canvas, QWidget* parent): QMainWindow(parent) {
    QWidget* central = new QWidget;
    QLayout* layout = new QHBoxLayout;
    
    layout->addWidget(canvas);
    central->setLayout(layout);
    setCentralWidget(central);
}

Problem jest taki, że chociaż program działa i wszystko wyświetla się jak należy. To po zakończeniu aplikacji pojawia się znane okienko (z Windows), że: "Program xxx.exe przestał działać. System Windows może wyszukać rozwiązanie tego problemu w trybie online."
Dodam, że w konsoli nie pojawiają się żadne komunikaty, że coś poszło nie tak. Może problem jest w zagnieżdżaniu widgetów? Nie mam jakiegoś super doświadczenia z biblioteką Qt ale wiem, że w klasie QMainWindow trzeba odwołać się do widgetu centralnego i w nim dopiero zdefiniować(przypisać) układ, a w nim już te widgety jakie chcemy. No i tak robię jak widać. Ale może coś źle robię? A może po prostu Windows tak już ma.

PS. Oczywiście sam konstruktor MainFrame jest dobrze wywoływany, przekazuję do niego adres obiektu mojej klasy Canvas:
guiservice.h:

class GuiService {
public:
    GuiService(): mainFrame(&canvas) {}

public:
    Canvas canvas;
    
    MainFrame mainFrame;
};
0

Co mówi debugger? Dokumentacja nie potwierdza tego jednoznacznie, ale zobacz czy nie wywołujesz 2x destruktora Canvas - możliwe, że layout przejmuje własność obiektu canvas.

1

Uruchom w Qt Creator trybie debug i odtwórz bug-a.
Program się zatrzyma w miejscu błędu.
Odszukaj okienku "Call stack" i przeanalizuj jakie fragmenty kody wskazują pozycje w tym okienku.
Jak nadal nie wiesz o co chodzi to copy paster tego "call stack" na forum i najlepiej powiązanego z nim kodu.

Jeśli twój canvas jest tworzymy na stosie lub jako zmienna globalna to wtedy central widget będzie próbował go usunąć co doprowadzi do crash

No czyli problemem jest mainFrame(&canvas)

0

@MarekR22: Dzięki za pomoc, działa.
Nie wiem o co chodzi z Call stackiem w QtCreatorem. Uruchomiłem projekt w trybie Debug ale nic sensownego się nie pojawiło. Ale zrobiłem jak się domyśliłem od Ciebie co chodzi. Miałem na początku obiekt Canvas canvas jako pełną instancję w klasie GuiService (jak pokazałem w pierwszym poście).
Problem zniknął gdy zamieniłem instancję na zmienną dynamiczną:

class GuiService {
public:
    GuiService::GuiService(): canvas(new Canvas), mainFrame(canvas) {}

public:
    Canvas* canvas;
    
    MainFrame mainFrame;
};

Dzięki za pomoc. Na zakończenie tylko napiszę, że w dokumentacji Qt do QWidget do konstruktora https://doc.qt.io/qt-5/qwidget.html#QWidget czytamy:

Constructs a widget which is a child of parent, with widget flags set to f.

If parent is 0, the new widget becomes a window. If parent is another widget, this widget becomes a child window inside parent. The new widget is deleted when its parent is deleted.

Wcześniej rozumiałem to tak, że nowy widget (u mnie canvas) jest usuwany, gdy usuwany jest jego rodzic ale rozumiałem to tak, że zadziała ten mechanizm gdy jawnie ustawi się rodzica w nowym widgecie.
Czyli gdy będę miał tak (gdy dodam linijkę 5):

MainFrame::MainFrame(QWidget* canvas, QWidget* parent): QMainWindow(parent) {
    QWidget* central = new QWidget;
    QLayout* layout = new QHBoxLayout;
    
    canvas->setParent(this);
    layout->addWidget(canvas);
    central->setLayout(layout);
    setCentralWidget(central);
}

Myślałem, że gdy nie będę ustawiał jawnie rodzica to mogę mieć Canvas canvas; jako pełną instancję. No widać działa to troszkę inaczej niż myślałem :)
Dzięki za pomoc.

1 użytkowników online, w tym zalogowanych: 0, gości: 1