How to efficiently copy contents between two list controls - c++

I want to copy rows from one List Control to another List Control. I am only able to copy them by sub item. I think this is not very efficient. There must be a method to copy the content by rows. The following is my code that copies content one sub item at a time.
CString CurItem, tem, copystr;
int j = 0;
m_combo_list.GetLBText(m_combo_list.GetCurSel(), CurItem);
for (int i = 0; i < m_list.GetItemCount(); i++) {
tem = m_list.GetItemText(i, 0);
if (CurItem == tem) {
m_report_list.InsertItem(j, _T(""));
for (int k = 0; k < 14; k++) { // 14 items per row.
copystr = m_list.GetItemText(i, k);// get one item per time from one list control.
m_report_list.SetItemText(j, k, copystr); // this is another list control. Copy the item to this list control.
}
j++;
}
}
Could anyone give a method to replace the for loop by copy a row from m_list to m_report_list directly? I think such a way must save a lot of time.

Related

Selective Infinite Loop in Making a Tournament Tree

I want to write a program that randomly generates a tournament tree using only the number of challengers. I read into another such problem, but the answer described how ranks would take part and seeding the players, which went a little over head.
The problem I am facing is that my algorithm produces an infinite loop for values between 1 and 4 inclusively. For all values otherwise, the program runs as desired.
My approach was to take in an array of strings for the competitors' names. Then, I would iterate over each position and randomly select a competitor's name to take that spot. Because I am swapping the names, I have to check for duplicates in the array. I believe this is where my code is experiencing issues.
Here is the snippet that actually determines the tree
for(int i = 0; i < no_players;) {
int index = rand() % ((no_players - i) + i);
// randomly choose an element from the remainder
string temp = players[index];
bool unique = true;
// check all the elements before the current position
for(int j = 0; j < i; j++) {
// if the element is already there, it is not unique
if(players[j] == temp)
unique = false;
}
// only if the element is unique, perform the swap
if(unique) {
players[index] = players[i];
players[i] = temp;
i++;
}
}
Any help is much appreciated!

How to delete selected row of a List Control in MFC?

I want to delete selected row of list control in MFC.
I have created a Delete Button, So If any row (it could be one or more than one row) is/are selected and I press delete button that/those rows should be deleted.
If lets say there are 100 rows and I select rows from 50-60, all the rows in this range should be deleted and rest of rows should have indexes from 1 to 90. means indexing should be proper after deletion also.
Adapted from this MSDN article:
UINT i, uSelectedCount = m_myListCtrl.GetSelectedCount();
int nItem;
if (uSelectedCount > 0)
for (i=0; i < uSelectedCount; i++)
{ nItem = m_myListCtrl.GetNextItem(-1, LVNI_SELECTED);
ASSERT(nItem != -1);
m_myListCtrl.DeleteItem(nItem);
}
When deleting a multiple selection having several items I prefer to do it like this:
int nItem = -1;
while ((nItem = m_list.GetNextItem(nItem, LVNI_SELECTED)) != -1)
{
if (m_list.DeleteItem(nItem))
nItem--;
}
Notice the important nItem--; line
UPDATE
I had to give up from this approach as the ItemData of an element gots fucked up. If I remove the nth element then the n+1 element will be my new nth. That element has a completely screwed up Itemdata.
UPDATE 2
I also tried with
int nItem = -1;
while ((nItem = m_list.GetNextItem(-1, LVNI_SELECTED)) != -1)
{
m_list.DeleteItem(nItem);
}
This approach also has the problem of screwing the Itemdata I reported before.
The following approach worked perfecly for me:
std::stack< int > items;
int nItem = -1;
while ((nItem = myListCtrl.GetNextItem(nItem, LVNI_SELECTED)) != -1)
{
items.push(nItem);
}
bool removed = false;
while (!items.empty())
{
nItem = items.top();
if (myListCtrl.DeleItem(nItem))
removed = true;
items.pop();
}
if (removed)
// update some application state;
Explanation:
When you remove things from the end to the start, you do not have to worry about the validity of positions. As the CListCtrl does not provide a GetPrevItem or any other way to get items in the reverse order, you need to store them in a collection where you can have that reverse order.
The most practical way to do it is to use a stack. Due to the way it works, you will put things in there in the normal order, and when you retrieve things they are automatically in reverse order.

QTableWidget update items

I’m having trouble with updating QTableWidgetItems. I don’t understand what I’m doing wrong :(
code and explanation.
Step by step problem.
at first insertion = OK, all first cells are filled.
updating firstly inserted items = OK, all first cells are updated.
at second insertion = OK, all second cells are filled.
updating second inserted items = OK, all second cells are updated.
updating first inserted items = FAIL, all first cells are updated, but NEXT cell’s first table is empty. WHY?
Code:
void MainWindow::fillTable(QList<QByteArray> Info)
{
int Row = ui->clientsList->rowCount() - 1; //Starts from 0.
//Check if client row already exists.
for(int i = Row; i >= 0; i--)
{
if(ui->clientsList->item(i, 0)->text().contains(QString(Info[1])))
{
//Update row.
for(int u = 0; u < Info.count() - 1; u++)
{
ui->clientsList->setItem(i, u, new QTableWidgetItem(QString(Info[u + 1])));
}
return; //avoid new row insertion.
}
}
//Insert new row.
Row = ui->clientsList->rowCount() + 1;
ui->clientsList->setRowCount(Row);
for(int i = 0; i < Info.count() - 1; i++)
{
//Fill rows.
ui->clientsList->setItem(Row - 1, i, new QTableWidgetItem(QString(Info[i + 1])));
}
}
Not full solution yet, but few comments:
1.There may be memory leak in line
ui->clientsList->setItem(i, u, new QTableWidgetItem(QString(Info[u + 1])));
why not use
ui->clientsList->item(i, u)->setText(QString(Info[u + 1]));
which is safer and more clear.
2.My understanding is you are relying on the fact that Info has same length as the row length is, perhaps it worth to add check for that?

Why object be deleted without obvious code?

In qt, I use tablewidget to store 100 rows. At first, I new tableWidgetItems to fill the rows.
As it runs, I set the items' propertities and no longer 'new'.
But I find after I use 'ui->tableWidget->setRowCount(index);', and later set back to 100, the code "ui->tableWidget->item(index, 0)->setText(...);" will crash the program. That's so bad!!! ;(
I debugged and find the new index > index set as row count before 'setting back to 100'.
Did the system delete the table items automatically when I set smaller row count???
I fear about this so much because even my code cannot determine the lifetime of the objects I created... Does anyone know how to keep them 'alive' after setting row count?(otherwise, I have to new them...).
I really appreciate it you take the patience to read my poor ELis:)
new:
//TABLE
ui->tableWidget->setColumnCount(3);
ui->tableWidget->setRowCount(100);
ui->tableWidget->setHorizontalHeaderLabels(headers);
for(int i = 0; i < 100; i++)//new
{
ui->tableWidget->setItem( i, 0 , new QTableWidgetItem(""));//time
ui->tableWidget->setItem( i, 1 , new QTableWidgetItem(""));//name
ui->tableWidget->setItem( i, 2 , new QTableWidgetItem(""));//BITS
}
Related code lines only:
{
int index = 0;
for(int queue_i = size_1; queue_i >= 0; queue_i--)
{
if(logDisplayQueue.at(queue_i).at(3) == "0" || logDisplayQueue.at(queue_i).at(3) == "2")continue;
QStringList BITList = bits2Hexs(queue_i);
ui->tableWidget->item(index, 0)->setText(logDisplayQueue.at(queue_i).at(0));//time
ui->tableWidget->item(index, 1)->setText(logDisplayQueue.at(queue_i).at(1));//name
ui->tableWidget->item(index, 2)->setText(BITList.join(""));//BITS
if(queue_i == oldRowItemNo)ui->tableWidget->selectRow(index);
index++;
}
ui->tableWidget->setRowCount(index);//set row count to be 30 more or less
}
Another function:
{
ui->tableWidget->setRowCount(100);//back to be 100 again
for(int queue_i = size_1, index = 0; queue_i >= 0; queue_i--, index++)
{
QStringList BITList = bits2Hexs(queue_i);
ui->tableWidget->item(index, 0)->setText(logDisplayQueue.at(queue_i).at(0));//time
ui->tableWidget->item(index, 1)->setText(logDisplayQueue.at(queue_i).at(1));//name
ui->tableWidget->item(index, 2)->setText(BITList.join(""));//BITS
//In debugging, when index reches the value of old row-count, "->setText" crashes the //program.
if(queue_i == oldRowItemNo)ui->tableWidget->selectRow(index);
}
}
When running, it returns message like 'instruction 0x00421727 refers to 0x00000000 memory, the memory cannot be 'read''
if I comment off this line:
'ui->tableWidget->setRowCount(index);//set row count to be 30 more or less', it runs well without crash and rows after index-referred-row show the same data as before.
setRowCount ensures that the table holds exactly that many rows. If you had more rows than index before, those rows are gone (deleted).
If you want to temporarily hide rows, you should probably use hideRow(int)/showRow rather than resetting the row count.

Remove specific items from a listbox in MFC

CString dance[] = {L"Atb", L"Tiesto", L"Madonna", L"Paul van Dyk", L"Armin van Burren", L"Jennifer Lopez"};
for(int i = 0; i < m_ItemsListBox.GetCount(); ++i)
{
CString item;
int length = m_ItemsListBox.GetTextLen(i);
m_ItemsListBox.GetText(i, item.GetBuffer(length));
for(int j = 0; j < sizeof(dance)/sizeof(*dance); ++j)
{
if(item != dance[j])
{
m_ItemsListBox.DeleteString(i);
}
}
}
I'm trying to remove from a listbox(m_ItemsListbox) all elements that are not part from the CString array. But how I coded it doesnt work, because if the first element its different it will delete it without searching the entire array.
Doesn't seemed like a hard task but I really have no idee how to do it. I think one way should be to use a CList instead of the array because it has a find() method, but I don't like it because I have to manually add all the elements, do you guys have another idee? Or the CList solution is the only one ?
Sorry, I'm a MFC begginer. Thanks for your time.
Hmmm I wouldn't be comfortable deleting things from the list box while iterating through the items in the listbox seems to be asking for problems down the line.
Honestly you could do something like this, I've just whipped together - construct a list of all the item indexes you want to remove and remove them at the end.
CList<int, int> ListIndexItemsToRemove;
for(int i = 0; i < m_ItemsListBox.GetCount(); ++i)
{
CString item;
int length = m_ItemsListBox.GetTextLen(i);
m_ItemsListBox.GetText(i, item.GetBuffer(length));
bool isMatchFound = false;
for(int j = 0; j < sizeof(dance)/sizeof(*dance); ++j)
{
if(item == dance[j])
{
isMatchFound = true;
}
}
if (!isMatchFound)
ListIndexItemsToRemove.AddHead(i);
}
for(int i = 0; i < ListIndexItemsToRemove.GetCount(); ++i)
m_ItemsListBox.DeleteString(ListIndexItemsToRemove.GetAt(ListIndexItemsToRemove.FindIndex(i));
but - it may be better to clear the whole list and refill it everytime something changes, as Martin says (if it doesn't affect anything.
For dynamic lists I tend to store data in its own variable and clear/re-populate the list when that data changes. Especially as the list gets bigger re-adding the strings tends to be much faster than doing searches through the list and/or original source.