TCanvas goes blank after clicking on different window

Hi there,
I have a standalone application (compiled in Visual C++ 2008) that acquires data from an FPGA board and displays real time histograms while the program is running. The histograms are displayed on pads in a single canvas. When running ROOT 5.16 I can click on different windows and when I click back to the TCanvas window, the histograms continue to update. When running ROOT 5.22, after clicking on a different window the canvas goes blank and never redraws, even after clicking back on the canvas.

Here is an example of how the program works:

int main( ) {

	Controller *controller = new Controller();
	
	if( controller->Connect() ) {
		controller->Run();
	}
	
	delete controller;
	
}

class Controller {

private:
	TFile *r_file;
	TTree *r_tree;
	TRint *r_App;
	TCanvas *r_c1;
	TPad *r_pad1, *r_pad2;
	TH1F *r_h1, *r_h2;
	
public:
	Controller();
	~Controller();
	int InitializeRoot();
	int Connect();
	void Run();
	
	void ParseData();
	void ParseStats();

}

Controller::Controller() {
	r_file = NULL;
}

Controller::~Controller() {
	r_App->Run();
	r_tree->Write();
	if( r_file != NULL ) {
		r_file->Write();
		r_file->Close();
	}
}

int Controller::Connect() {
	if( !InitializeRoot() ) {
		return 0;
	}
	// connect to the FPGA...
	return 1;
}

int Controller::InitializeRoot() {
	r_file = new TFile("out.root", "RECREATE");
	
	r_tree = new TTree("OutTree", "Events");
	r_tree->Branch("timestamp", &timestamp, "timestamp/i");
	// create other branches...
	r_tree->AutoSave();
	
	r_App = new TRint("ROOTapp", NULL, NULL, NULL, NULL, true);
	
	r_c1 = new TCanvas("c1", "canvas", 610, 0, 800, 800);
	r_pad1 = new TPad("pad1", "pad1", 0.005, 0.505, 0.995, 0.995);
	r_pad2 = new TPad("pad2", "pad2", 0.005, 0.005, 0.995, 0.495);
	r_pad1->Draw();
	r_pad2->Draw();
	
	r_pad1->cd();
	r_h1 = new TH1F("h1", "h1", 100, 1, 100);
	r_h1->Draw();
	
	r_pad2->cd();
	r_h2 = new TH1F("h2", "h2", 100, 1, 100);
	r_h2->Draw();
	
	r_c1->cd();
	
	return 1;
}

void Controller::Run() {
	while( [current_time < stop_time] ) { // loop until the time is up (psuedo code)
		if( [received data from FPGA] ) {
			ParseData();
		}
		if( [received stats from FPGA] ) {
			ParseStats(); // occasionally (every couple seconds) we will receive some stats from the FPGA
		}
	}
}

void Controller::ParseData() {
	this->timestamp = new_timestamp; // put new data into the branch
	... // handle other data
	
	r_tree->Fill();
	
	r_h1->Fill(new_timestamp);
	r_pad1->Modified();
	
	... // same for other histograms
}

void Controller::ParseStats() {
	// because stats come back only occasionally, we will use this time to update the canvas
	
	... // parse the stats
	
	r_c1->Update();
}

I tried to strip out everything unnecessary, but its still quite long… sorry about that.

Thanks in advance for any suggestions regarding this strange problem!

Cheers,
Ford

Hello,

I thought of some more information I left out of the previous post. I am running Windows XP and experienced this on two different computers. Also, the problem does not happen only when I click on a different window, it is any time the TCanvas window loses focus, such as the screen saver coming on or anything like that. With version 5.16, I can click on a different window and, if the canvas window is not minimized or blocked by another wnidow, I can see that the canvas continues to update in the background.

Also, the r_c1->Update() command is called approximately once per second.

I read today a little about TRootEmbeddedCanvas and TGMainFrame. Should I try to use something like that for my program? I don’t exactly understand the difference if I am not using an “widgets.”

Thanks again,
Ford

Hi,

I’m not sure this code would work:

  • You call TRint::Run() in you class destructor? Is it right?
  • Where is the code handling ROOT events? (e.g. gSystem->ProcessEvents() )…
    I can start from this, but in order to save a bit of our time, and to be sure to fix the real problem, it would be better if you could post a small working piece of code…

Cheers,
Bertrand.

One possible solution (taking your example as real code…)
Just add e.g.:

in your loop:

To let the system handle (GUI) events.

Cheers, Bertrand.

Hi Bertrand,

Adding gSystem->ProcessEvents(); solved my problems. I actually added it to the ParseStats function so that it would only be called every few seconds. The only problem is that this slowed down my data acquisition by almost a factor of two. I think it’s worth the loss in speed, though.

Anyways, thanks for your help!

Ford

Hi Ford,

You’re welcome. :slight_smile:
Note that I still don’t understand why you call TRint::Run() in your class destructor… :confused:
Anyway, you can also consider using threads. See $ROOTSYS/test/threads.exe application as an example.

Cheers, Bertrand.