Get seg fault when trying to call TGMainFrame::Cleanup() then reuse the frame

Dear experts

I want to make a GUI which after I click a button it process something and then clean up everything on the main frame, then add new things on it.
Here is part of code:

EventDisplay::EventDisplay() {
        // Create main frame
        mainFrame = new TGMainFrame(gClient->GetRoot(), 800, 600);

        // Add label
        TGLabel* label = new TGLabel(mainFrame, "Please select number of entries that you want to preprocess for T0 and ADC pedestal value");
        mainFrame->AddFrame(label, new TGLayoutHints(kLHintsCenterX, 5, 5, 10, 10));

        // Add number entry
        preNumEventEntry = new TGNumberEntry(mainFrame, 0, 9, -1, TGNumberFormat::kNESInteger);
        mainFrame->AddFrame(preNumEventEntry, new TGLayoutHints(kLHintsCenterX, 5, 5, 10, 10));

        // Add process button
        processButton = new TGTextButton(mainFrame, "&Process");
        processButton->Connect("Clicked()", "EventDisplay", this, "Preprocess()");
        mainFrame->AddFrame(processButton, new TGLayoutHints(kLHintsCenterX, 5, 5, 10, 10));

        mainFrame->SetWindowName("Preprocess Entries");
        mainFrame->MapSubwindows();
        mainFrame->Resize(mainFrame->GetDefaultSize());
        mainFrame->MapWindow();
}

void EventDisplay::Preprocess() {
        int number = preNumEventEntry->GetIntNumber();
        std::cout << "Processing " << number << " entries..." << std::endl;
        
        mainFrame->Cleanup();

        // Call SetupDisplay to create new elements
        SetupDisplay();
}

void EventDisplay::SetupDisplay() {
        // Create embedded canvas
        embeddedCanvas = new TRootEmbeddedCanvas("embeddedCanvas", mainFrame, 800, 400);
        mainFrame->AddFrame(embeddedCanvas, new TGLayoutHints(kLHintsExpandX | kLHintsExpandY));
        canvas = embeddedCanvas->GetCanvas();

        // Set new canvas size
        canvas->SetCanvasSize(800, 600);

 // Set window name and map subwindows, main window
        mainFrame->SetWindowName("Event Display");
        mainFrame->MapSubwindows();
        mainFrame->Resize(mainFrame->GetDefaultSize());
        mainFrame->MapWindow();
}

I found that when I add the line mainFrame->Cleanup(); it give the seg fault when I click the button:

 *** Break *** segmentation violation
[/usr/lib/system/libsystem_platform.dylib] _sigtramp (no debug info)
[/Users/siyuan/Physics/root/install/lib/libGui.so] TGButton::EmitSignals(bool) (no debug info)
[/Users/siyuan/Physics/root/install/lib/libGui.so] TGButton::HandleButton(Event_t*) (no debug info)
[/Users/siyuan/Physics/root/install/lib/libGui.so] TGFrame::HandleEvent(Event_t*) (no debug info)
[/Users/siyuan/Physics/root/install/lib/libGui.so] TGClient::HandleEvent(Event_t*) (no debug info)
[/Users/siyuan/Physics/root/install/lib/libGui.so] TGClient::ProcessOneEvent() (no debug info)
[/Users/siyuan/Physics/root/install/lib/libGui.so] TGInputHandler::Notify() (no debug info)
[/Users/siyuan/Physics/root/install/lib/libCore.so] TMacOSXSystem::DispatchOneEvent(bool) (no debug info)
[/Users/siyuan/Physics/root/install/lib/libCore.so] TSystem::InnerLoop() (no debug info)
[/Users/siyuan/Physics/root/install/lib/libCore.so] TSystem::Run() (no debug info)
[/Users/siyuan/Physics/root/install/lib/libCore.so] TApplication::Run(bool) (no debug info)
[/Users/siyuan/Physics/comet/crt/ana/EventDisplay/build/EventDisplay] main (no debug info)
[/usr/lib/dyld] start (no debug info)

What did I do wrong?

Here is a little update:
I add one line:

preNumEventEntry->GetNumberEntry()->Connect("ReturnPressed()", "TGTextButton", processButton, "Clicked()");

And I found that when I use Enter key to trigger Preprocess() there is no seg fault, only if I press the button there will be seg fault.

But this makes no sense because when I press the enter key it should be the same as I click the “process” button…

Hi,

Adding in the loop @linev and @couet .

Best,
D

The problem you’re encountering is related to the GUI. @bellenot is the expert in this area.

Thank you, @bellenot could you please give some suggestions?

@bellenot is on holidays right now. He will reply when he will be back.

You cannot call mainFrame->Cleanup(); in the slot method (EventDisplay::Preprocess()), it will delete the widget being currently in use (the signal emitter). Here is a possible solution:

void EventDisplay::Preprocess()
{
   TTimer::SingleShot(300, "EventDisplay", this, "Process()");
}

void EventDisplay::Process()
{
   int number = preNumEventEntry->GetIntNumber();
   std::cout << "Processing " << number << " entries..." << std::endl;
   mainFrame->Cleanup();
   // Call SetupDisplay to create new elements
   SetupDisplay();
}

Thank you, can I move the mainFrame->Cleanup() to the function SetupDisplay() if I don’t want a new function?

Not if EventDisplay::SetupDisplay() is called by EventDisplay::Preprocess()

Ah, I see, that means I need to wait until EventDisplay::Preprocess() return then I can call mainFrame->Cleanup()

Sorry but why return key does not trigger seg fault? (refer to my 2nd post)

I don’t know, I’ll check whenever I have some time

So I don’t know why it works with the number entry… But anyway, now you know how to fix the issue, right?

If you don’t want to create a new method, just do the following:

void EventDisplay::Preprocess()
{
   int number = preNumEventEntry->GetIntNumber();
   std::cout << "Processing " << number << " entries..." << std::endl;
   TTimer::SingleShot(300, "EventDisplay", this, "SetupDisplay()");
}

void EventDisplay::SetupDisplay()
{
   mainFrame->Cleanup();
   // Create embedded canvas
   embeddedCanvas = new TRootEmbeddedCanvas("embeddedCanvas", mainFrame, 800, 400);
   mainFrame->AddFrame(embeddedCanvas, new TGLayoutHints(kLHintsExpandX | kLHintsExpandY));
   canvas = embeddedCanvas->GetCanvas();
   ...