Use a MSHFlexGrid with non-database data and still define the shape - c++

I am trying to use the Microsoft Hierarchical FlexGrid (MSHFlexGrid) in a Visual C++ (VS 2005). I have the grid shown, and I can manually add data to the individual cells. However, according to online documentation I've read, I should be able to show the hierarchical nature of the data (hence MSHFlexGrid instead of MSFlexGrid) by defining the SHAPE as the RecordSource. I can do that fine (by using the put_RecordSource method of the grid object), however I'm at a loss as to how to add the actual data.
I've read that the best way to do this is to use an ADO Data Control (ie ADODC) component and bind it as the DataSource for the Grid. You can then specify "provider=msdatashape;data provider=none;" as the provider of the DataControl and fill it with data. If I were doing SQL, I'd specify my SELECT query as the RecordSource, then call Refresh() and let the control load the data.
However, my data is in custom objects. I know what needs to be displayed, I'm just at a loss as to the best way to insert the data into the FlexGrid and still use the built in features of the control. I'm open to any suggestions, but I need to keep the data local (ie no JET, Access, etc).
Here's some code:
In header:
....
// Variable to control the Flex Grid component
CMshflexgrid1 m_grid; //generated by wizard from the MSHFlexGrid component
// to control the data source hierarchical information
CAdodc1 m_adodc1;
....
In cpp:
....
BOOL MyDialogClass::OnInitDialog()
{
CDialog::OnInitDialog();
m_grid.Clear();
CString strCn = "provider=msdatashape;data provider=none;";
m_adodc1.put_ConnectionString(strCn);
CString BackupOfRecordSource = "";
BackupOfRecordSource = m_adodc1.get_RecordSource();
//CString strShape = "SHAPE APPEND new adInteger As PID, New adVarChar(10) As StudentName, ((SHAPE APPEND new adInteger As ChID, New adVarChar(10) As Course, ((SHAPE APPEND new adInteger As GrndChID, New adBSTR As Description) RELATE ChID TO GrndChID) As GrandChild) RELATE PID TO ChID) AS Child";
CString strShape = "SHAPE APPEND new adInteger As PID, New adVarChar(10) As StudentName";
m_adodc1.put_RecordSource(strShape);
m_adodc1.Refresh();
m_grid.Refresh();
BackupOfRecordSource = m_adodc1.get_RecordSource(); //returns the strShape that I just put in
//ADD RECORDS HERE! HOW?
return TRUE;
}

The sample talked about building an ADODB.Recordset and use it as the data source of ADODC. The code you give is building a SQL and use it as the data source of ADODC. I don't think you can replace an ADODB.Recordset with a string.

Related

Visualization of dynamically created modules

I am building a dynamic multi agent simulation in OMNeT and for this I have to create new modules at runtime. The module creation is working, however, the modules created at runtime are not appearing in the 3D visualization.
module "node" is created sucessfully
Does anyone know how to make the module appear in the visualization? Do I have to update the visualization module?
omnet.ini:
[General]
network = AgentNetwork
*.visualizer.osgVisualizer.typename = "IntegratedOsgVisualizer"
*.visualizer.*.mobilityVisualizer.animationSpeed = 1
*.visualizer.osgVisualizer.sceneVisualizer.typename = "SceneOsgEarthVisualizer"
*.visualizer.osgVisualizer.sceneVisualizer.mapFile = "hamburg.earth"
AgentSpawner:
void AgentSpawner::initialize()
{
cMessage *timer = new cMessage("timer");
scheduleAt(1.0, timer);
}
void AgentSpawner::handleMessage(cMessage *msg)
{
cModuleType *moduleType = cModuleType::get("simulations.Agent");
cModule *module = moduleType->create("node", getParentModule());
// set up parameters and gate sizes before we set up its submodules
module->par("osgModel") = "3d/glider.osgb.(20).scale.0,0,180.rot";
module->getDisplayString().parse("p=200,100;i=misc/aircraft");
module->finalizeParameters();
// create internals, and schedule it
module->buildInside();
module->callInitialize();
module->scheduleStart(simTime()+5.0);
}
The OSG visualization info is maintained totally separately from the actual simulation model module object (that's because the visualization must be ALWAYS optional in the simulation, so make sure your simulation builds fine with OSG totally turned off). This means that an entirely different data structure is built during initialization time from the existing network nodes. As this is done only once during the initialization, dynamically created modules will not have their visualization counterpart data structure.
The code which created the corresponding objects is here.
The solution would be to look up the NetworkNodeOsgVisualizer module in your AgentSpawner code then create and add the corresponding data structures (NetworkNodeOsgVisualization objects). The needed methods (create and add) are there, but sadly they are protected, so you many need to modify the INET code and make them public to be able to call them.

Error - Cannot access display string yet for new node creation in Omnet

I am trying to create a node at run time in my module in Omnet. I am able to create it with this code and its working fine.
cModule* parentmod = getParentModule();
cModule* grantParentMod = parentmod->getParentModule();
cModule* grantParentMod1 = grantParentMod->getParentModule();
// To check if the module is already created
for (cSubModIterator iter(*grantParentMod1); !iter.end(); iter++)
{
EV << iter()->getFullName()<<endl;
if (iter()->getFullName() == "host_send4")
return;
}
cModuleType *meshnode1 = cModuleType::get("inet.networklayer.manetrouting.PASER.meshnode");
cModule *mod = meshnode1->create("host_send4", grantParentMod1);
cDisplayString& dispstr = getDisplayString();
dispstr.parse("p=1000,535;r=200,green");
mod->finalizeParameters();
mod->buildInside();
mod->scheduleStart(simTime()+2*beaconInterval);
However this module is not generated at desired place in simulation output (the coordinates and the display). I believe the display string created here is not attached to the module and hence I tried to do it by this :-
cDisplayString& dispstr = getDisplayString();
dispstr.parse("p=1000,535;r=200,green");
mod->getDisplayString().set(dispstr);
But with this I encounter following error at run time :- Cannot access display string yet: Parameters not yet set up . I know the problem is in mod->getDisplayString().set(dispstr);
So is there any other way to assign the parameter or am I doing some minor error.
Thanks for this help.
Make sure you are following the module creation procedure as given in the OMNeT++ manual.
If you navigate to the The Detailed Procedure sub-section you will notice a comprehensive list which tells what step should be performed where:
Find the factory object;
Create the module;
Set up its parameters and gate sizes as needed;
Tell the (possibly compound) module to recursively create its internal submodules and connections;
Schedule activation message(s) for the new simple module(s).
Step 3 I believe is the one you are looking for. Little below is given a detailed explanation of what should be done for step 3:
If you want to set up parameter values or gate vector sizes (Step
3.), the code goes between the create() and buildInside() calls:
// create
cModuleType *moduleType = cModuleType::get("foo.nodes.WirelessNode");
cModule *module = moduleType->create("node", this);
// set up parameters and gate sizes before we set up its submodules
module->par("address") = ++lastAddress;
module->finalizeParameters();
module->setGateSize("in", 3);
module->setGateSize("out", 3);
// create internals, and schedule it
module->buildInside();
module->scheduleStart(simTime());
Be aware of the usage of the module->par("<parameter_name>") function.
PS: I was writing my answer, and in meanwhile you answered your own question. This answer can be left there for future reference, if useful.
Well I modified the code as :-
cModuleType *meshnode1 = cModuleType::get("inet.networklayer.manetrouting.PASER.meshnode");
cModule *mod = meshnode1->create("host_send4", grantParentMod1);
mod->finalizeParameters();
std::string displayString = "p=1000,535;r=200,green;i=device/smallrouter";
mod->getDisplayString().parse(displayString.c_str());
mod->buildInside();
mod->scheduleStart(simTime()+2*beaconInterval);
and then its working perfect. According to my understanding, I should add mod->finalizeParameters(); before changing the display setting and display string should be a simple string but not the cDisplayString object.

Adding to a list from another class

I am trying to add the instance of an object that I click on to a list on my control object. However when I do so it says that the reference is not set to an instance of an object. The code I have to instantiate the list on the control object is:
public List<Transform> selected = new List<Transform>();
And I tried to add to it to that list using this code attached to the unit:
if (!selected)
{
// Set selected state
selected = true;
// Add to Selected List
control.GetComponent<ForwardCommandScript>().selected.Add(this.transform);
// Set material colour brighter
oldColour = gameObject.renderer.material.color;
newColour = oldColour + new Color(0.2f, 0.2f, 0.2f);
gameObject.renderer.material.color = newColour;
}
I have tried with transform as well. Later I will try to remove it by finding a reference id that was set when the unit is instantiated so should I try to add the script instead of the object if I need to find its variables and then delete the game object attached to the script. I have tried with the GameObject, transform and the class. I wanted to use the class so I can easily access the variables. I have posted this on unity answers and forums but no one replied in the week it was up and I don't like reposting the same stuff on the same site.
Cheers, Scobbo
Your error NullReferenceException: Object reference not set to an instance of an object states that something in the associated line is null. Since the error message doesn't state which part is null, you have to split your code up and check which part is failing.
I'm not sure how you split it up, but try it this way:
var script = control.GetComponent<ForwardCommandScript>();
if (script == null) Debug.Log("script not found");
if (script.selected == null) Debug.Log("selected is null");
script.selected.Add(this.transform);
Now you should get one of the two messages in your debug log before the exception raises. Either the script was not found and you have to check if it is correctly assigned to the game object and if control is the correct game object, or selected is null which should not happen if you initialized it like you posted...
Thanks for adding the complete Error Message :)
you need to replace
control.GetComponent<ForwardCommandScript>().selected.Add(this.transform);
with
control.GetComponent<ForwardCommandScript>().selected.Add(transform);
because
this
is a reference to the script and not the GameObject. you could also use gameObject.transform which transform is just an abbreviation for

design pattern for "save"

I'm currently working on a "save" mechanism, which allows a user to save the project his working on on hard disc. The output will be a XML file containing all kinds of data.
Now our project structure is about to change and we need to write a new xml file (create a new save method).
So now here comes the challenge: When saving I want the user to be able to choose which file format he will be creating (version1 (old) or version2 (new)).
Does anyone now how to achieve that? Is there a suitable design pattern around?
Remarks:
- The data we are saving can be seen as unrelated blocks, so it would actually be easy to exchange an old block with a new one.
- The whole goal of the thing is, it should be readable again when loading an old project. (I assume this can be done by tags, and just react on tags when loading?)
This sounds like a good application for the Strategy pattern.
You would create an abstract base class FileFormat (the Strategy interface) with two virtual functions, projectToXml and xmlToProject, which are supposed to turn your internal project representation into XML or vice versa.
Then you create two implementing subclasses FileFormatNew and FileFormatLegacy (these are the concrete strategies).
Your save functions would then additionally require an instance of FileFormat, and call the corresponding method of that object to do the data conversion. Your load function could choose the strategy to use by examining the XML tree for something which tells it which version it is.
And when you ever need to support another file format, you just have to create a new class which is a subclass of FileFormat.
Addendum after the exchange in the comments
When you are going to have a lot of versions with very small differences and you still want to use the Strategy pattern, you could make the FileFormat a composite of multiple strategies: A CircleStragegy, a RectangleStrategy, a LineStrategy etc.. In that case I wouldn't use different classes for different versions of the FileFormat. I would create a static factory function for each version which returns a FileFormat with the Strategy objects used in that version.
FileFormat FileFormat::createVersion1_0() {
return new FileFormat(
new LineStrategyOld(),
new CircleStrategyOld(),
new RectangleStragegyOld()
);
}
FileFormat FileFormat::createVersion1_1() {
// the 1.1 version introduced the new way to save lines
return new FileFormat(
new LineStrategyNew(),
new CircleStrategyOld(),
new RectangleStragegyOld()
);
}
FileFormat FileFormat::createVersion1_2() {
// 1.2 uses the new format to save circles
return new FileFormat(
new LineStrategyNew(),
new CircleStrategyNew(),
new RectangleStragegyOld()
);
}
FileFormat FileFormat::createVersion1_3() {
// 1.3 uses a new format to save rectangles, but we realized that
// the new way to save lines wasn't that good after all, so we
// returned to the old way.
return new FileFormat(
new LineStrategyOld(),
new CircleStrategyNew(),
new RectangleStragegyNew()
);
}
Note: In real code you would of course use more descriptive suffixes than "Old" and "New" for your strategy class names.

Accessing values in Flex Object result from Zend AMF originated as PHP associative array

I cannot access values in Flex Object (ArrayCollection) after I receive it from Zend AMF. The original type sent is PHP associative array which is simply returned like
return $this->sections['initial_setup'];
PHP Variable view:
The required result sent looks like this in Charles AMF RPC tab:
But when I receive the data in Flex as Object (or String[] - it doesn't matter), I cannot access the property values in such code
var result:Object = event.result;
if (result['database'] == 'yes' && result['admin'] == 'yes')
// continue branch ...
and I get exception on the if-line:
Error: Unknown Property: 'database'.
at mx.collections::ListCollectionView ...
Finally, I can see in Eclipse variables view that ResultEvent instance carries a result of type ArrayCollection with 0 length and the values received are visible with D icon (I couldn't find what D adornment means):
But why I still can't access them at all and what should I do to use them?
I have tried to change types of Array or ArrayCollection instead of Object. Also there is a thread discussing similar problem, but after trying that out, it doesn't help too.
Any help will be much appreciated :o)
EDIT 1:
Here is the code of FB generated super class constructor for the ConfigurationService:
// Constructor
public function _Super_ConfigurationService()
{
// initialize service control
_serviceControl = new mx.rpc.remoting.RemoteObject();
// initialize RemoteClass alias for all entities returned by functions of this service
var operations:Object = new Object();
var operation:mx.rpc.remoting.Operation;
operation = new mx.rpc.remoting.Operation(null, "readSettings");
operation.resultType = Object;
operations["readSettings"] = operation;
operation = new mx.rpc.remoting.Operation(null, "writeSettings");
operations["writeSettings"] = operation;
operation = new mx.rpc.remoting.Operation(null, "readDBSettings");
operation.resultType = valueObjects.ConnectionParams;
operations["readDBSettings"] = operation;
operation = new mx.rpc.remoting.Operation(null, "writeDBSettings");
operations["writeDBSettings"] = operation;
operation = new mx.rpc.remoting.Operation(null, "readInitSetupCompletion");
operation.resultType = Object;
operations["readInitSetupCompletion"] = operation;
operation = new mx.rpc.remoting.Operation(null, "writeInitSetupCompletion");
operations["writeInitSetupCompletion"] = operation;
_serviceControl.operations = operations;
_serviceControl.convertResultHandler = com.adobe.serializers.utility.TypeUtility.convertResultHandler;
_serviceControl.source = "ConfigurationService";
_serviceControl.endpoint = "gateway.php";
preInitializeService();
model_internal::initialize();
}
So what's happened here is that the Array that's serving as the source for your ArrayCollection is acting as a generic Object with those same two properties. Probably the generated code is assuming you'll always get back more than one object and is having problems when your data doesn't fulfill the assumptions Adobe's engineers made about it. One of the reasons I don't like generated code :-).
Check out these resources on how to "roll your own."
Thoughts on Remoting
AMFPHP to Flex Object Relational Mapping
Implementing PHP Services
I think this last (3) is closest to what you probably have in PHP. If you do decide to go with a VO, you can probably just add an $explicitType to your row return and not need to change too much else on the PHP side. You'll probably need to regenerate your services if you go that route, because I suspect the generated code will be different. The good news is the Adobe engineers probably did think of the case where you have an explicit type, but only one record.
Another fix is to just check your AC for having a source of zero length that is not null and looking for your properties on the edges of that.