It is fatal error and ROOT just able to recover.
Most probably - gPad
value is not correct.
Try to restore this value at the end of EventDisplay::HighlightGraph()
method
What exactly do you mean “restore”? Sorry I’m very bad at coding
At the begin:
auto store = gPad;
and at the end:
gPad = store;
Thank you again and it solved the problem…Just try to understand what was wrong, I attach my slot function here, can you please have a look and tell me what caused that seg fault?
//at first time c_waveform will be a nullptr that because I want it appear after highlight is called
void EventDisplay::HighlightGraph(TVirtualPad* pad, TObject* obj, Int_t ihp, Int_t y){
auto store = gPad;
c_waveform = (TCanvas*)gROOT->GetListOfCanvases()->FindObject("c_waveform");
std::cout<<"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"<<std::endl;
if(!c_waveform){
std::cout<<"Make new Canvas for ADC waveform"<<std::endl;
c_waveform = new TCanvas("c_waveform", "ADC waveform", 505, 0, 600, 400);
}
if(ihp == -1){
delete c_waveform;
return;
}
if(waveforms.size() != 0 && waveforms.find(ihp) != waveforms.end()){
c_waveform->cd();
waveforms.at(ihp)->Draw("APL");
std::cout<<"Drawn graph"<<std::endl;
gPad->Update();
}
gPad = store;
}
After you create new canvas - moving cursor over old canvas may not work. While gPad
is set to new canvas.
Ah, assume I have a TCanvas* c
which generate the signal, you mean after the gPad->Update()
, gPad is setting to the c_waveform
but the Canvas that generate signal is a different Canvas which is c
, so in order to set the gPad
back to the c
I need to store gPad at the beginning and set back at the end? Is my understanding correct?
Generally you are correct.
But be careful - working with many canvas at a time is complicated.
And sometimes makes such problems.
Thank you!
Let me summarize this in case of someone else also face the same problem.
I made a simple example to show how to use user class member function as the slot function to receive the signal.
EventDisplay.cxx:
#include "EventDisplay.hxx"
EventDisplay::EventDisplay(){
c1 = new TCanvas();
c1->Connect("Highlighted(TVirtualPad*, TObject*, Int_t, Int_t)", "EventDisplay", this, "HighlightGraph(TVirtualPad*, TObject*, Int_t, Int_t)");
x = {1,2,3,4,5};
y = {1,2,3,4,5};
g = new TGraph(x.size(), x.data(), y.data());
c1->cd();
g->SetMarkerStyle(58);
g->SetMarkerColor(kRed);
g->Draw("AP");
g->SetHighlight();
c1->Update();
gSystem->ProcessEvents();
}
void EventDisplay::HighlightGraph(TVirtualPad* pad, TObject* obj, Int_t ihp, Int_t y){
auto store = gPad; //store the current gPad pointer
c_show = (TCanvas*)gROOT->GetListOfCanvases()->FindObject("c_show");
if(!c_show){
std::cout<<"showed new canvas"<<std::endl;
c_show = new TCanvas("c_show", "Canvas that shows later", 505, 0, 600, 400);
g_show = new TGraph();
}
if(ihp == -1){
delete c_show;
return;
}
c_show->cd();
for(int i=0; i<50; i++){
double t = (double)ihp + 1;
if(i == 0) g_show->SetPoint(0, 0, 1);
else g_show->SetPoint(i, i, sin(i/t) / (i/t));
}
g_show->SetMarkerStyle(20);
g_show->SetMarkerColor(kBlue);
g_show->Draw("APL");
gPad->Update();
gPad = store;
}
EventDisplay.hxx:
#ifndef _EVENTDISPLAY_HXX_
#define _EVENTDISPLAY_HXX_
#include <iostream>
#include <vector>
#include <TROOT.h>
#include <TSystem.h>
#include <TCanvas.h>
#include <TGraph.h>
class EventDisplay{
public:
EventDisplay();
void HighlightGraph(TVirtualPad* pad, TObject* obj, Int_t ihp, Int_t y); //this needs to be public!
private:
TCanvas* c1;
TCanvas* c_show;
TGraph* g;
TGraph* g_show;
std::vector<double> x;
std::vector<double> y;
};
#endif
main.cxx:
#include <TApplication.h>
#include "EventDisplay.hxx"
int main(int argc, char** argv){
TApplication app("app", &argc, argv);
EventDisplay eventDisplay;
app.Run();
return 0;
}
LinkDef.h:
#ifdef __CLING__
#pragma link C++ class EventDisplay;
#endif
Procedure how to make it run:
If one uses command line to compile:
rootcling -f Dict.cxx EventDisplay.hxx LinkDef.h
to generate the dictionary fileDict.cxx
`root-config --cxx --cflags --libs` -lgui main.cxx Dict.cxx EventDisplay.cxx -o main
- ./main
If one uses CMakeLists.txt
, you should add this line:
ROOT_GENERATE_DICTIONARY(Dict EventDisplay.hxx LINKDEF LinkDef.h)
Here CMakeLists.txt file which compiles your project:
cmake_minimum_required(VERSION 3.10 FATAL_ERROR)
project(EventDisplay)
find_package(ROOT REQUIRED)
include(${ROOT_USE_FILE})
set(sources EventDisplay.cxx)
set(headers EventDisplay.hxx)
ROOT_GENERATE_DICTIONARY(G__EventDisplay ${headers} LINKDEF LinkDef.h)
#---Create a shared library with geneated dictionary
add_library(EventDisplay SHARED ${sources} G__EventDisplay.cxx)
target_include_directories(EventDisplay PRIVATE ${CMAKE_SOURCE_DIR})
#---Create a main program using the library
add_executable(testgui main.cxx)
target_link_libraries(testgui EventDisplay ROOT::Gui)
But for me everything looks fine.
And code also works with new web-based graphics.
You can try it running:
./testgui --web