|
Argus - GUI extension of ROME
|
Introduction.
How to design own projects.
AGRUS is a GUI generator based on ROOT.
It helps you write any sort of graphical user interface.
Although it is used in the ROME environment as the GUI extension of ROME it is not limited to ROME.
It can be used as a completely separated (stand alone) GUI application.
The way how ROME and ARGUS are executed can be steered with the configuration file.
Three modes are supported.
First, the framework can run as a stand alone ROME application.
This will be a pure analyzer with no GUI extension.
This is the default mode of ROME.
Second is a mixed mode.
Therefore ARGUS acts as the GUI extension of ROME.
The framework will run as an analyzer with a GUI displaying the ROME objects.
The third mode is a stand alone ARGUS application.
In this mode you will have no analyzer running.
Therefore no tasks will be executed.
The GUI may accesses objects of a ROME application running in a separate process.
But it can also run completely independent of ROME.
Each tab in ROME is a class, and
Tabs can have several graphical objects in it. A Tab can be created
with adding an entry in a project definition xml file.
Xmonitor.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<ROMEFrameworkDefinition>
<Experiment>
<ExperimentName>X</ExperimentName>
<ExperimentShortCut>X</ExperimentShortCut>
<ProgramName>monitor</ProgramName>
</Experiment>
<Tabs>
<Tab>
<TabName>X</TabName>
<TabTitle>XXX</TabTitle>
</Tab>
</Tabs>
</ROMEFrameworkDefinition>
|
From this definition file, romebuilder will generates header files and a
source file under include/tabs and src/tabs. You will
see this window when you run the created executable.
You can put any ROOT graphical objects such as TGTextButton,
TRootEmbeddedCanvas, TGListBox and so on with editing these header and
source file. Your change in XTX.h and XTX.cpp will be preserved even
if you run romebuilder again, while XTX_Base.h will be over
written.
For example, following change of XTX.h and XTX.cpp will add a
canvas in the tab.
XTX.h
#include <include/generated/XTX_Base.h>
#include <TCanvas.h>
#include <TRootEmbeddedCanvas.h>
class XTX : public XTX_Base
{
protected:
TRootEmbeddedCanvas *fCanvas;
public:
XTX():XTX_Base(){
fCanvas = 0;
}
~XTX(){
if(fCanvas)
delete fCanvas;
}
void Init();
ClassDef(XTX,1)
};
|
XTX.cpp
#include "include/tabs/XTX.h"
ClassImp(XTX)
void XTX::Init()
{
fCanvas = new TRootEmbeddedCanvas("XCanvas", this
, ((UInt_t)200*gAnalyzer->GetWindowScale())
, ((UInt_t)200*gAnalyzer->GetWindowScale()));
AddFrame(fCanvas, new TGLayoutHints( kLHintsExpandX |
kLHintsExpandY, 10, 10, 4, 4));
}
|
ROME applications can obtain histograms from other
ROME application over network. For this purpose, NetFolder can be used, Following
example shows how to obtain a histogram and draw. Framework is in
charge of connection to server, so what you need to do is just to call
FindObjectAny function in your code.
Xmonitor.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<ROMEFrameworkDefinition>
<Experiment>
<ExperimentName>X</ExperimentName>
<ExperimentShortCut>X</ExperimentShortCut>
<ProgramName>monitor</ProgramName>
</Experiment>
<Tabs>
<Tab>
<TabName>X</TabName>
<TabTitle>XXX</TabTitle>
</Tab>
</Tabs>
<NetFolders>
<NetFolder>
<NetFolderName>mynetfolder</NetFolderName>
</NetFolder>
</NetFolders>
</ROMEFrameworkDefinition>
|
XTX.h
#include <include/generated/XTX_Base.h>
#include <TCanvas.h>
#include <TRootEmbeddedCanvas.h>
#include <TH1.h>
class XTX : public XTX_Base
{
protected:
TRootEmbeddedCanvas *fCanvas;
TH1F *fHisto;
public:
XTX():XTX_Base(){
fCanvas = 0;
fHisto = 0;
}
~XTX(){
if(fCanvas)
delete fCanvas;
if(fHisto)
delete fHisto;
}
void Init();
void DrawHisto();
ClassDef(XTX,1)
};
|
XTX.cpp
#include "include/tabs/XTX.h"
ClassImp(XTX)
void XTX::Init()
{
fCanvas = new TRootEmbeddedCanvas("XCanvas", this
, ((UInt_t)200*gAnalyzer->GetWindowScale())
, ((UInt_t)200*gAnalyzer->GetWindowScale()));
AddFrame(fCanvas, new TGLayoutHints( kLHintsExpandX |
kLHintsExpandY, 10, 10, 4, 4));
DrawHisto();
}
void XTX::DrawHisto(){
if(!gAnalyzer->GetNetFolder("mynetfoler")){
return;
}
fCanvas->GetCanvas()->cd();
if(fHisto)
delete fHisto;
fHisto =
(TH1F*)gAnalyzer->GetNetFolder("mynetfoler")->FindObjectAny("hAdc0_001");
if (!fHisto)
cout<<"Histo hAdc0_001 not available."<<endl;
else
fHisto->Draw();
fCanvas->GetCanvas()->Modified();
fCanvas->GetCanvas()->Update();
return;
}
|
In this example, when the button is pressed. the message (kC_COMMAND,
kCM_BUTTON and ButtonID) will be sent to the function
ProcessMessage. You can call any function from ProcessMessage.
In addition to ProcessMessage, ROME provide a special function
ProcessMessageThread. If you rename ProcessMessage to
ProcessMessageThread in XTX.h and XTX.cpp, All functions called
from ProcessMessageThread will be executed in new thread. It
means you can do other operation even if the called function is not
finished.
It is possible to use both ProcessMessage and
ProcessMessageThread. In this case ProcessMessageThread
needs to be called from ProcessMessage.
There is an example project in
rome/argus/examples/processMessage. Please note that multi thread
application might not safe (especially on multi processor
computer). For instance, usually Xlib is not thread safe.
XTX.h
#include <include/generated/XTX_Base.h>
#include <TGButton.h>
class XTX : public XTX_Base
{
protected:
TGTextButton *fButton;
enum CommandIdentifiers {
ButtonID
};
public:
XTX():XTX_Base(){
fButton = 0;
}
~XTX(){
delete fButton;
}
void Init();
Bool_t ProcessMessage(Long_t msg, Long_t param1, Long_t param2);
ClassDef(XTX,1)
};
|
XTX.cpp
#include "include/tabs/XTX.h"
ClassImp(XTX)
void XTX::Init()
{
fButton = new TGTextButton(this, "Button", ButtonID);
fButton->Associate(this);
AddFrame(fButton, new TGLayoutHints( kLHintsCenterX |
kLHintsCenterY, 10, 10, 4, 4));
}
Bool_t XTX::ProcessMessage(Long_t msg, Long_t param1, Long_t param2)
{
switch (GET_MSG(msg)) {
case kC_COMMAND:
switch (GET_SUBMSG(msg)) {
case kCM_BUTTON:
switch (param1){
case ButtonID:
cout<<"Button is clicked."<<endl;
break;
}
break;
}
break;
}
return true;
}
|
Menus can be added with adding entries in a project definition XML
file. Menus belong to a tab, and they appear when the tab is front.
Every menu item has MenuItemID. This number will be sent to a
special function MenuClicked. You can implement any function in
MenuClicked. Please note that MenuItemID needs to be
between 0 and
maxNumberOfTabMenuItems. maxNumberOfTabMenuItems is
defined in rome/builder/include/ROMEBuilder.h, and the
default value is 20.
Xmonitor.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<ROMEFrameworkDefinition>
<Experiment>
<ExperimentName>X</ExperimentName>
<ExperimentShortCut>X</ExperimentShortCut>
<ProgramName>monitor</ProgramName>
</Experiment>
<Tabs>
<Tab>
<TabName>X</TabName>
<TabTitle>XXX</TabTitle>
<Menus>
<Menu>
<MenuTitle>Y</MenuTitle>
<MenuItems>
<MenuItem>
<MenuItemTitle>YYY</MenuItemTitle>
<MenuItemID>1</MenuItemID>
</MenuItem>
</MenuItems>
</Menu>
</Menus>
</Tab>
</Tabs>
</ROMEFrameworkDefinition>
|
XTX.h
#include <include/generated/XTX_Base.h>
class XTX : public XTX_Base
{
protected:
public:
XTX():XTX_Base(){
}
~XTX(){
}
void Init();
void MenuClicked(Long_t param);
ClassDef(XTX,1)
};
|
XTX.cpp
#include "include/tabs/XTX.h"
ClassImp(XTX)
void XTX::Init()
{
}
void XTX::MenuClicked(Long_t param){
cout<<"Menu is clicked.("<<param<<")"<<endl;
}
|
gWindow->GetStatusBar() returns a pointer of
TGStatusBar. You can split status bar and set text. Please note
that the first part may be used by framework.
XTX.cpp
#include "include/monitor/XWindow.h"
ClassImp(XTX)
void XTX::Init()
{
gWindow->GetStatusBar()->SetText("status bar");
}
|
There are two ways to execute functions in background. One is
executing functions in a new thread, and the other is using TTimer.
With creating thread, you can execute functions in parallel with the
main thread. It uses effectively (maybe less) CPU power than
TTimer. On the other hand, you have to carefully write code, because
two threads can access the same memory space really at the same
time. It is known that Xlib is not thread safe.
If the calculation time of the functions is rather short or you want
to use safer way. You may use TTimer. It executes functions
periodically within the main thread.
- Using thread.
Thread functions can be added with adding entries in an project
definition XML file. Thread functions shares the same memory space and
run in parallel. Such functions may be used for updating histograms
periodically or checking HV, pressure, gas flow and so on.
Once an entry of ThreadFunction is added in a definition
file, romebuilder generates StartZ(Int_t interval = 1000, Int_t nloop
= 0) and StopZ(). StartZ executes function Z
nloop times every interval mili seconds. If nloop
is 0, Z will be executed until StopZ() is called. Function
Z need to be implemented in XTX.h and XTX.cpp
like following example.
Please note that multi thread application might not safe (especially
on multi processor computer). For instance, usually Xlib is
not thread safe.
Xmonitor.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<ROMEFrameworkDefinition>
<Experiment>
<ExperimentName>X</ExperimentName>
<ExperimentShortCut>X</ExperimentShortCut>
<ProgramName>monitor</ProgramName>
</Experiment>
<Tabs>
<Tab>
<TabName>X</TabName>
<TabTitle>XXX</TabTitle>
<ThreadFunctions>
<ThreadFunction>
<FunctionName>Z</FunctionName>
</ThreadFunction>
</ThreadFunctions>
</Tab>
</Tabs>
</ROMEFrameworkDefinition>
|
XTX.h
#include <include/generated/XTX_Base.h>
class XTX : public XTX_Base
{
protected:
public:
XTX():XTX_Base(){
}
~XTX(){
}
void Init();
void Z();
ClassDef(XTX,1)
};
|
XTX.cpp
#include "include/tabs/XTX.h"
ClassImp(XTX)
void XTX::Init()
{
StartZ(10000,3);
// StopZ();
}
void XTX::Z()
{
cout<<"Thread function Z is running."<<endl;
}
|
- Using TTimer.
XTX.h
#include <include/generated/XTX_Base.h>
#include <TTimer.h>
class XTX : public XTX_Base
{
protected:
TTimer* fTimer;
public:
XTX():XTX_Base(){
fTimer = new TTimer(10000);
fTimer->Connect("Timeout()","XTX",this,"Z()");
}
~XTX(){
}
void Init();
void Z();
ClassDef(XTX,1)
};
|
XTX.cpp
#include "include/tabs/XTX.h"
ClassImp(XTX)
void XTX::Init()
{
fTimer->TurnOn();
// fTimer->TurnOff();
}
void XTX::Z()
{
cout<<"function Z is executed by TTimer."<<endl;
}
|