How can I iterate through the pages of a wxNotebook? - c++

void Mainframe::OnClearNotebook( wxCommandEvent& e )
{
int end = m_notebook->GetPageCount();
for ( int i = 0; i < end; i++ )
{
if ( m_notebook->GetPageText( i ) != "Server Log" )
{
m_notebook->DeletePage(i);
}
}
}
This code crashes in this form with the message "m_notebook->GetPageText() index out of range";
How do I correctly iterate through all pages?
edit, the solution:
void Mainframe::OnClearNotebook( wxCommandEvent& e )
{
while ( m_notebook->GetPageCount() > 1 )
{
int end = m_notebook->GetPageCount() - 1;
if ( m_notebook->GetPageText( end ) != "Server Log" )
{
m_notebook->DeletePage(end);
}
else
{
break;
}
}
}

GetPageCount() will be changed if you are deleting pragmatically so end will hold earlier versions value
For Eg.
You have 100 in m_notebook->GetPageCount()
So end = 100
After iterating 10 items you are removing 5 items so now list will have 95 items but you are iterating upto 100 - This might be problem

If you want to delete items from a non-linked list, you will want to iterate the list, and collect the indices of all the list items that you want to delete in another new list. Once you are done iterating and collecting the indices, call delete on your original list with every index that you collected.

Related

How to sort List<File> in Dart with null objects at end

Starting to take in hand Flutter for a study project, I'm wondering about sorting a list of files.
Indeed, my program has a list of 4 files initialized like this :
List<File> imageFiles = List(4);
This initialization actually implies that my list is like this : [null,null,null,null].
When the user performs actions, this list can fill up. However, the user can delete a file at any time, which can give us the following situation: [file A, null, null, file d].
My question is, how to sort the list when a deletion arrives in order to have a list where null objects are always last ([file A, file D, null, null]).
I've looked at a lot of topics already, but they never concern the DART.
Thank you in advance for your help.
You can sort the list with list.sort((a, b) => a == null ? 1 : 0);
Here's a full example, with String instead of File, that you can run on DartPad
void main() {
List<String> list = List(4);
list[0] = "file1";
list[3] = "file4";
print("list before sort: $list");
// list before sort: [file1, null, null, file4]
list.sort((a, b) => a == null ? 1 : 0);
print("list after sort: $list");
// list after sort: [file1, file4, null, null]
}
If it's a business requirement to have a max of 4 files, I would suggest creating a value object that can handle with that.
For example:
class ImageList {
final _images = List<String>();
void add(String image) {
if(_images.length < 4) {
_images.add(image);
}
}
void removeAt(int index) {
_images.removeAt(index);
}
String get(int index) {
return _images[index];
}
List getAll() {
return _images;
}
}
And you could run it like this:
void main() {
ImageList imageList = ImageList();
imageList.add("file1");
imageList.add("file2");
imageList.add("file3");
imageList.add("file4");
imageList.add("file5"); // won't be add
print("imagelist: ${imageList.getAll()}");
// imagelist: [file1, file2, file3, file4]
imageList.removeAt(2); // remove file3
print("imagelist: ${imageList.getAll()}");
// imagelist: [file1, file2, file4]
}
This will make it easier to have control. (This example was again with String instead of File)
You can try this:
This place all null at end.
sortedList.sort((a, b) {
int result;
if (a == null) {
result = 1;
} else if (b == null) {
result = -1;
} else {
// Ascending Order
result = a.compareTo(b);
}
return result;
})

Not able to return out of recursion

I have the following piece of code. It aims at traversing the [attached screenshot] Tree structure in depth first manner.
As you can see, I am interested in the highlighted entry in green -> Has Class( DatasetType ) node of this tree structure. This Tree structure is subjected to additions of new nodes by customers. So, I have to traverse the Tree structure to find my node of interest. I have formulated the below code. But And I can see that it identifies that node of my interest.
However, it is not stopping there. It is proceeding onto the next sibling i.e., Has Class( EPMJob ). I want my processing to stop. I am pretty sure that my way of returning stuff is missing something. but not able to pin point.
Any inputs are most welcome.
tag_t findHasTypeDatasetNodeInAMTree( tag_t amTreeNode )
{
CharPointer nodeName;
Response stat = askRuleName( amTreeNode, &nodeName );
CharPointer nodeArgument;
stat = askRuleArg( amTreeNode, &nodeArgument );
if( tc_strcmp( nodeName.getString(), "Has Class" ) == 0 && tc_strcmp( nodeArgument.getString(), "DatasetType" ) == 0 )
{
return amTreeNode;
}
int numChildNodes = 0;
TagPointer childNodes;
stat = askChildren( amTreeNode, &numChildNodes, &childNodes );
if( numChildNodes == 0 )
{
return NULLTAG;
}
// The following is the piece that needs attention.
// Do not want to NULL check here though
for( int inx = 0; inx < numChildNodes; ++inx )
{
findHasTypeDatasetNodeInAMTree( childNodes[inx] );
}
return NULLTAG;
}
I'm not sure what this is doing:
for( int inx = 0; inx < numChildNodes; ++inx )
{
findHasTypeDatasetNodeInAMTree( childNodes[inx] );
}
But I'm pretty sure it doesn't stop when you find something so the result is ALWAYS NULLTAG. How about something like:
for( int inx = 0; inx < numChildNodes; ++inx )
{
auto result = findHasTypeDatasetNodeInAMTree( childNodes[inx] );
if( result != NULLTAG )
return result;
}

HDF5 :Create a Dataset with string

I am using HDF5 API and I am trying to create a dataset with variable-length string.
The struct is
struct dataX
{
std::string data;
};
I was using char[256] with a static hard coded size.
But I want it to be dynamic so after reading the HDF5 Doc, I found H5T_VARIABLE and used it as follows but it still fails.
H5Dcreate returns a negative value (means error).
hid_t mem_type;
mem_type = H5Tcopy( H5T_C_S1 );
H5Tset_size(mem_type,H5T_VARIABLE);
/* Create the memory data type. */
if ((mem_type_id = H5Tcreate (H5T_COMPOUND, mem_type )) < 0 ) {
return -1;
}
/* Insert fields. */
if ( H5Tinsert(mem_type_id, "field", 0, mem_type_id ) < 0 ) {
return -1;
}
/* Create a simple data space with unlimited size */
// hsize_t dims[1]={0};
// hsize_t maxdimsk[1]={ H5S_UNLIMITED };
if ( (sid = H5Screate_simple( 1, dims, maxdims )) < 0 ){
return -1;
}
/* Modify dataset creation properties, i.e. enable chunking */
plist_id = H5Pcreate (H5P_DATASET_CREATE);
//chunk==1
if ( H5Pset_chunk ( plist_id, 1, chunk ) < 0 ){
return -1;
}
H5Pset_alloc_time( plist_id, H5D_ALLOC_TIME_EARLY )
/* Set the fill value using a struct as the data type. */
// fill_data=0
if ( fill_data )
{
if ( H5Pset_fill_value( plist_id, mem_type_id, fill_data ) < 0 ){
LOG_ERROR << "cannot fill value " << LOG_ENDL;
return -1;
}
}
else {
if ( H5Pset_fill_time( plist_id, H5D_FILL_TIME_NEVER ) < 0 ) {
LOG_ERROR << "error" << LOG_ENDL;
}
}
/* Create the dataset. */
did = H5Dcreate( loc_id, dset_name, mem_type_id, sid, plist_id )
I tried H5D_ALLOC_TIME_LATE, thinking that maybe if it allocated the memory just before writing it would work but ... it didn't.
Now I'm stuck and I don't know what to do.
Did I miss something ?
Your mem_type_id doubly invalid:
the second argument of H5Tcreate should be the size of the compound datatype
in H5Tinsert, the last argument should be the datatype of the inserted field. Here I guess you meant mem_type instead of mem_type_id.
I don't know anything about what you are doing in particular, but to write variable length string, you do not need to create a compound type nor to set any special property lists. Basically your 3 first line are enough to create a valid variable-length string datatype (mem_type). Then you create the simple dataspace, then the dataset.
Have a look at this example, you will see it's pretty simple.

c++: Nested Lists: how to add an item to a list of Lists

I am new on the board. I am using MS VS2008.
I am learning about list of lists.
I am trying to add elements to a list which is part of a list of lists.
I have noted in my program where I am having a problem.
When I debug it, "beth" is being added to the second list (division2), but when the loop is exited, "beth" isn't in the second list even though I have declared all my lists outside of the nested loop.
Any help would be greater appreciated.
Here is the code:
struct item
{
string name;
int age;
};
int main()
{
list<item> division1;
list<item> division2;
list< list<item> >WholeCompany;
item s;
s.name="sandra"; s.age=43; division1.push_back(s);
s.name="Marc"; s.age=19; division2.push_back(s);
s.name="betty"; s.age=34;division2.push_back(s);
WholeCompany.push_back(division1);
WholeCompany.push_back(division2);
list< list<item> >::iterator WholCompIter;
list<item>::iterator itemIter;
for ( WholCompIter = WholeCompany.begin(); WholCompIter != WholeCompany.end(); WholCompIter++ )
{
//incorrect
//list<item> listEntry = *WholCompIter;
//instead use:
list<item> listEntry = *WholCompIter;
for ( itemIter = listEntry.begin(); itemIter != listEntry.end(); itemIter++ )
{
//MY ISSUE IS RIGHT HERE! How can I add the value to the list, but the list forgets it when it exit loop
if(itemIter->name =="betty")
{
item s; s.name="beth"; s.age=65;
listEntry.insert(itemIter,s);//problem is here.
//I have also tried
//listEntry.push_back(s) but the output doesn't show it
}
}
}
//incorrect.
//for(list<item>::iterator i=division2.begin(); i!=division2.end();++i)
// cout<<i->name<<" "<<i->age<<endl;
//instead use:
for ( WholCompIter = WholeCompany.begin(); WholCompIter != WholeCompany.end(); WholCompIter++ )
{
list<item>listEntry = *WholCompIter;
for ( itemIter = listEntry.begin(); itemIter != listEntry.end(); itemIter++ )
{
cout<<itemIter->name<<" "<<itemIter->age<<endl;
}
cout<<endl; cout<<endl;
}
return 0;
}
You're just creating a copy here:
list<item> listEntry = *WholCompIter;
Instead, you need a reference:
list<item>& listEntry = *WholCompIter;
Also, you are printing from division2 in the loop at the bottom. Remember that WholeCompany is only a copy of division2 at the initialization. Since you've modified WholeCompany via the reference above, you need to access WholeCompany in the output loop at the bottom.
Fix.
for ( WholCompIter = WholeCompany.begin(); WholCompIter != WholeCompany.end(); WholCompIter++ )
{
list<item>& listEntry = *WholCompIter;
for ( itemIter = listEntry.begin(); itemIter != listEntry.end(); itemIter++ )
{
//MY ISSUE IS RIGHT HERE! How can I add the value to the list, but the list forgets it when it exit loop
if(itemIter->name =="betty")
{
item s; s.name="beth"; s.age=65;
listEntry.insert(itemIter,s);//problem is here.
//I have also tried
//listEntry.push_back(s) but the output doesn't show it
}
}
}
When you type list<item> listEntry you create local variable and then in your code assigns it to copy of returned value by list<list<item>>::iterator::operator * and when you change it, there is nothing effect on your list WholeCompany.
In strings
WholeCompany.push_back(division1);
WholeCompany.push_back(division2);
you push into wholeCompany copies of division1 and division2, so, when you change contains of WholeCompany, contains of division1 or division2 will not changed.

Flex 3 - how to select an item in the list as default?

how to select an item in the list as default
default selected item say of index 0
I tried stuff like this --
listid.selectedIndex = somevalueinmyprogram - 1; // 0
but when i debug this i get
_selectedIndex = 0
selectedIndex = -1
and default value is not selected why so?
[i have already checked for the obvious that somevaluefrommyprogram is not equal to 0]
Help!
I have found that if you set the selectedItems by defining an array of selected items it works better than the selectedIndex.
function setSelectedCategories():void{
var selectedItems :Array = new Array();
for each (var selectedCategory:Category in entry.categories) {
for each (var category:Category in categories) {
if (selectedCategory.categoryID == category.categoryID){
selectedItems .push(category);
break;
}
}
}
categoriesList.selectedItems = selectedItems ;
}
OR using the selectedIndices works if you want to use an array that contains the indexes that you want to be selected.
for ( var i:int=0; i < userIpods.length; i++ ) {
//j will represent the list item's index value
for ( var j:int = 0; j < iPodAry.length; j++) {
if ( userIpods[i] == iPodAry[j].id ) {
selectedIpodIndices.push( j );
break;
} //end if
} //end for ( var iPodObj:Object in iPodAry) {
} //end for ( var i:int in userIpods )
/*mark as selected those index values in the
selectedIpodIndices array*/
iPodList.selectedIndices = selectedIpodIndices ;