Argus - GUI extension 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.
<?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.
#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) }; |
#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 application can draw histograms in tasks defined in the own program.
It can also obtain histograms from other ROME application over network.
For details, please see files in "netfolder" example.
Relevant files are readme, netfolder.xml, include/tabs/NFTHistos.h, src/tabs/NFTHistos.cpp, include/tasks/NFTFillHistoAndFolder.h, src/tasks/NFTFillHistoAndFolder.cpp, separateProcessConfigAnalyzer.xml, separateProcessConfigMonitor.xml and singleProcessConfig.xml.
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.
#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) }; |
#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.
<?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> |
#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) }; |
#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.
#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.
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.
<?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> |
#include <include/generated/XTX_Base.h> class XTX : public XTX_Base { protected: public: XTX():XTX_Base(){ } ~XTX(){ } void Init(); void Z(); ClassDef(XTX,1) }; |
#include "include/tabs/XTX.h" ClassImp(XTX) void XTX::Init() { StartZ(10000,3); // StopZ(); } void XTX::Z() { cout<<"Thread function Z is running."<<endl; } |
#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) }; |
#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; } |
R.Sawada | |