CStringList in MFC - mfc

I was coding with 2 CStringList objects. Each has its own data, for eg one has name and other the phoneno, and both are in sync, i.e, if there is a phoneno there is a name and viceversa.
Now, i have 2 combobox in which i show the names and the respective phonenos. The name combobox is sorted, hence the sync between the two goes for a toss. hence for sorting i did the following:
int aComboElementNo = myNameComboBox.GetCount();
if( aComboElementNo >= 1 )
{
for( int aIndex = 0; aIndex < aComboElementNo; aIndex++ )
{
CString aTempStr;
// Getting the string in the combobox
myNameComboBox.GetLBText( aIndex, aTempStr );
// Getting the position where the name is present in the list
POSITION aPos = aNameList.Find( aTempStr );
// setting the appropriate phoneno in the 2nd combobox
myPhoneComboBox.AddString( aPhoneList.GetAt( aPos ) );
}
}
When i executed this i got the names in the myPhoneComboBox rather than the phonenos.
Now i have 2 qns:
how come i get the name present in namelist when i am accessing the phonelist? isn't it a breach, as i am able to access some other variables data using some other variable.
how to sort the 2nd list.

I Hope U are using CStringArray and not CStringList.
You need to use FindIndex rather than Find since Find will return OBJECT Pos rather than the Index count....
and to get the element with array use simply [] the operator.
If You still want to use CStringList then through Iterator Find the Index Count of the first match of string in one List and Use FindIndex of that IndexCount to get the postition object for the secondlist to use GetAt to the second list.

Why do you have 2 separate lists? Why not one CTypedPtrArray of structures holding both the name and the phone nb?

That is a crazzy, forgive me, stupid way to find names. It assumes the names are unique. God help me, I've had to deal with these things, name fields should never be viewed as unique, its bloody dangerious. Just ask my dad Baash05 Sr.
I'd assume there's an ID or some data set as the app adds to the combo box. Please use that in your map. My guess is the programmer set the data to either the ID of the name, or a pointer to the object that contained the name. (person object/business object/student object...).
If the code that adds the names didn't add a way to tell the difference between George Forman and any of his kids, then make an argument to the boss, that it's implementation should be changed, because by god it should be!
int aComboElementNo = myNameComboBox.GetCount();
for( int aIndex = 0; aIndex < aComboElementNo; aIndex++ )
{
int nameLocal = myNameComboBox.GetItemData( aIndex);
myPhoneComboBox.InsertString(aIndex, aPhoneList[namelocal] );
}

Related

Unable to get data from list control

I am working with list control in MFC. I have written code to insert elements into list control present in a dialog box as follows:
int nIndex = 0;
for (int count = 0; count < arrResults.GetSize(); count++)
{
nIndex = m_cListCtrl.InsertItem(count, _T(arrResults[count].ElementAt(0)));
m_cListCtrl.SetItemText(nIndex, 1, _T(arrResults[count].ElementAt(1)));
}
However, when I try to retrieve data from m_cListCtrl, it always returns blank. Also, the GetItemCount() method also returns 0 items. Any suggestions are appreciated.
Following is the data retrieve code that I have written:
arrResults.SetSize(1);
arrResults[0].Add("Header1");
arrResults[0].Add("Header2");
TestDialog testDlg;
testDlg.FillControlList(arrResults); // This function has above code to add data to control list
EXPECT_EQ("Header1", queryDlg.m_cListCtrl.GetItemText(0, 0));
EXPECT_EQ("Header2", queryDlg.m_cListCtrl.GetItemText(0, 1));
The GetItemText function is returning blank string.
When you call FillControlList(), you are using testDlg object. But when you call GetItemText() you're using queryDlg object. You have inserted the items in one dialog and you're trying to get data from different object. Please check with that.

C++ CListCtrl - GetItemData() returning wrong value?

I have a C++ application with an SQL backend, and have been storing the row id of any retrieved columns (an integer, primary key bigint in the database) with SetItemData() on list control rows as required. This is then retrieved with GetItemData() if that ID needs to be queried.
I am now getting a weird problem in that, in this one scenario, GetItemData() is returning a random 7-digit number instead of the stored ID. When I add the row I use the following code:
CListCtrl& lc = GetListCtrl();
for (int i = 0; i < vInsertItems.size(); i++) {
int j = lc.InsertItem(i,i.strName);
DWORD dwdRowID = (DWORD)cammms,nRowID;
lc.SetItemData(j,dwdRowID);
}
To retrieve and check the value I can do the following (where I have determined that nCurrentlySelectedIndex is correct):
CListCtrl& lc = GetListCtrl();
int msgID = lc.GetItemData(nCurrentlySelectedIndex);
CString debugInt; debugInt.Format(_T("debugInt = %d"),msgID);
AfxMessageBox(debugInt);
What is bizarre, is that if I run the second batch of code directly after the first, it is all fine. But if I run it in a separate function, msgID becomes set to a set of random 7 digits, different every time.
Does anyone have any idea what could be causing this?

Comparing Substrings to JList Strings

In advance, please forgive me if I do not give adequate background information for my question. Long time reader, first time asker.
I am making a program where one has a database of cars accessed through a tab delimited .txt file (we did something like this recently in my programming class, so I wanted to expand upon it).
Instead of using the terminal window, my format is displaying the Car objects (containing make, model, year, price, etc.) in ArrayList. I'm using JFrame, a JList, and a ListModel since I'm using an array of Car objects.
In my program, I wanted to create a delete method where the user could delete items from the database. Initially they would select the item from the JList and then would click on the delete button. This invokes the delete() method, which is the tab shown below...
void delete()
{
int i = list.getSelectedIndex();
String string = (String)listModel.getElementAt(i);
for(Car c : cars)
{
String year = String.valueOf(c.getYear());
String conditionReport = String.valueOf(c.getConditionReport());
String price = String.valueOf(c.getPrice());
if(c.getMake().indexOf(string) != -1 && c.getModel().indexOf(string) != -1 && year.indexOf(string) != -1 && conditionReport.indexOf(string) != -1 && price.indexOf(string) != -1 && c.getWarranty().indexOf(string) != -1 && c.getComments().indexOf(string) != -1)
{
int choice = JOptionPane.showConfirmDialog(null, "Are you sure you would like to remove the " + cars.get(i).getYear() + " " + cars.get(i).getMake() + " " + cars.get(i).getModel() + "?", "Choose One", JOptionPane.YES_NO_OPTION);
if(choice == JOptionPane.NO_OPTION || choice == JOptionPane.CLOSED_OPTION)
{
return;
} else
{
cars.remove(c);
listModel.removeElementAt(i);
}
}
}
writeFile();
}
I have pinpointed my issue to be inside the if statement. (I printed things before and after to try to find where the program is lying. 'list' is my JList and 'listmodel' is my default list model. Car is an object I created that contains the elements (as seen by the get methods). The elements shown in the listModel are merely Strings that show getMake(), getModel(), and so forth... (Each 'get' item is separated by about 10 spaces.)
What am I doing wrong in the if statement? I figured that the getMake() and getModel() (and so forth) would be substrings of the index selected.
Thank you so much for your assistance! Any input regarding ways I could make further questions more specific and clear would be greatly appreciated!
It seems like you are doing this to find the selected Car in some kind of data structure. You would be better off doing something like programming a custom list model that had access to cars itself. Then you could retrieve the selection more immediately. If cars is an ArrayList that list merely parallels I also don't see why you can't do something to the effect of cars.remove(list.getSelectedIndex());. Or since JList can display any object, override Car's toString to display what the list currently displays and have the list display Cars. Then you can cars.remove((Car)list.getSelectedValue());.
But aside from that, based on your description it sounds like you mean to do the evaluation the other way. It's the list item that should contain all of the Car attributes, rather than all of the Car attributes containing the list item. So something like
if( string.contains(c.getMake()) && string.contains(year) // and so on
(Or with indexOf but since contains merely returns indexOf > -1, using contains makes your code somewhat shorter.)

Can I put a lua_table in another table to build a multi-dimensional array via C++?

for my game im trying to accomplish the following array structure by C++ because the data come from an external source and should be available in a lua_script.
The array structure should look like this: (The data are in a map, the map contains the name of the variable and a list of Pairs (Each pair is a key value pair considered to be one element in one subarray)...
The data prepared in the map are complete and the structure is definetly okay.
So basically I have
typedef std::map<std::string, std::list<std::pair> >;
/\index(e.g: sword) /\ /\
|| ||
|| Pair: Contains two strings (key/value pair)
||
List of Pairs for each array
items = {
["sword"] = {item_id = 1294, price = 500},
["axe"] = {item_id = 1678, price = 200},
["red gem"] = {item_id = 1679, price = 2000},
}
What I got so far now is:
for(ArrayMap::iterator it = this->npc->arrayMap.begin(); it != this->npc->arrayMap.end(); it++) {
std::string arrayName = (*it).first;
if((*it).second.size() > 0) {
lua_newtable(luaState);
for(ArrayEntryList::iterator itt = (*it).second.begin(); itt != (*it).second.end(); itt++) {
LuaScript::setField(luaState, (*itt).first.c_str(), (*itt).second.c_str());
}
lua_setglobal(luaState, arrayName.c_str());
}
}
But this will only generate the following structure:
(table)
[item_id] = (string) 2000
[name] = (string) sword
[price] = (string) 500
The problem is that the table can ofcourse only contain each index once.
Thatswhy I need something like "a table in a table", is that possible?
Is there a way to achieve this? Im glad for any hints.
So from what I understand, if you have two "sword", then you can not store second one? If that's the case, you are doing it wrong. The key of map should be unique and if you decide that you are going to use std::map to store your items then your external source should provide unique keys. I used std::string as key in my previous game. Example:
"WeakSword" -> { some more data }
"VeryWeakSword" -> { some more data }
or, with your data (assuming item_ids are unique) you can get something like following from external source:
1294 -> { some more data }
1678 -> { some more data }
I'm not sure how efficient is this but I wasn't programming a hardware-hungry 3D bleeding-edge game so it just did a fine job.
The data structure that you are using also depends on the how you are going to use it. For example, if you are always iterating through this structure why don't you store as follows:
class Item {public: ... private: std::string name; int id; int value;}
std::vector<Item> items // be careful tho, std::vector copies item before it pushes
Extract(or Parse?) the actual value you want from each entity in external source and store them in std::vector. Reaching the middle of std::vector is expensive, however, if your intention is not instant accessing but rather iterating over data, why use map? But, if your intention is actually reaching a specific key/value pair, you should alter your external data and use unique keys.
Finally, there is also another associative container that stores non-unique key/value pairs called std::multimap but I really doubt you really need it here.

How to move an item up and down in a wxListCtrl (wxwidgets)

This should be pretty easy but I'm having a heck of a time doing it. Basically I want to move a row in my wxListCtrl up or down. I posted this to wxwidgets forum and got the following code.
m_list->Freeze();
wxListItem item;
item.SetId(item_id); // the one which is selected
m_list->GetItem(item); // Retrieve the item
m_list->DeleteItem(item_id); // Remove it
item.SetId(item_id - 1); // Move it up
m_list->SetItem(item); // Apply it's new pos in the list
m_list->Thaw();
which doesn't work. The element is deleted but not moved up (I guess the setitem line is not working). Then I thought to just switch the text and the image but I can't even get the text from the row reliably. I have
int index = m_right->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
wxString label = m_right->GetItemText(index);
if(index == 0)
return;
wxListItem item;
item.SetId(index);
bool success = m_right->GetItem(item);
wxString text = item.GetText();
but text is blank even though there is text and the index is correct. So, I'm stuck not even being able to do the most basic task. Anybody know how to do this? The code runs in a button callback (the user presses a little up arrow and my code executes to try to move it). I'm using 2.9.1 on windows.
I made it work like this with wxWidgets 2.9.3 :
void FileSelectionPanel::OnMoveUp( wxCommandEvent& WXUNUSED(evt) )
{
int idx = _listCtrl->GetNextItem( -1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED );
if( idx == 0) idx = _listCtrl->GetNextItem( 0, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED );
_listCtrl->Freeze();
while( idx > -1 ) {
wxListItem item;
item.SetId(idx); _listCtrl->GetItem(item);
item.SetId(idx-1); _listCtrl->InsertItem(item);
_listCtrl->SetItemData( idx-1, _listCtrl->GetItemData( idx+1 ));
for( int i = 0; i < _listCtrl->GetColumnCount(); i++ ) {
_listCtrl->SetItem( idx-1, i, _listCtrl->GetItemText( idx+1, i ));
}
_listCtrl->DeleteItem( idx + 1 );
idx = _listCtrl->GetNextItem( idx-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED );
}
_listCtrl->Thaw();
}
The thing I noticed it that wxListItem is more of a convenience struct, for storing state of the view and help pass values into the wxListCtrl "nicely". It is in no way bound to what is actually inside of the wxListCtrl.
Hope this still helps anyone !
Even there is already an answer that is checked. I have the same problem here, but my list is unordered. By looking into wxWidgets' code I found out there is another important information inside the wxListItem object - the mask. I got my reordering to work correctly by setting the mask value to -1, which means that all data shall be copied. This includes the item text as well as other information, like the item data (which was important in my case).
wxListItem item;
item.SetId(item_id); // set needed id
item.SetMask(-1); // set needed data
m_list->GetItem(item); // actually retrieve the item
m_list->DeleteItem(item_id); // remove old copy
item.SetId(item_id - 1); // move item up
m_list->InsertItem(item); // insert copy of item
I also had to use "InsertItem" instead of "SetItem". Otherwise, there was no new item inserted, but an existing one overwritten (see also tomcat31's answer).
Is the list ordered? if it is auto ordering it may be ignoring the order you are trying to apply.
From recollection the internal order was not necessarily sequential, you might have to get the index of the previous item and go one before it.