unable to make the item as selected in mfc listctrl - mfc

Items are being added to the CListCtrl. If a particular item is present in the list then that item needs to be selected.
I have tried the following code,but the item is not being selected.
BOOL CsampleeeDlg::OnInitDialog()
{
m_List.InsertColumn(0, _T("Full Name"), LVCFMT_LEFT, 90);
m_List.InsertColumn(1, _T("Profession"), LVCFMT_LEFT, 90);
m_List.InsertColumn(2, _T("Fav Sport"), LVCFMT_LEFT, 90);
int nIndex = m_List.InsertItem(0, _T("Sandra C. Anschwitz"));
m_List.SetItemText(nIndex, 1, _T("Singer"));
m_List.SetItemText(nIndex, 2, _T("Handball"));
nIndex = m_List.InsertItem(1, _T("Roger A. Miller"));
m_List.SetItemText(nIndex, 1, _T("Footballer"));
m_List.SetItemText(nIndex, 2, _T("Tennis"));
int nCol = 0;
CString m_SearchThisItemText = _T("Sandra C. Anschwitz");
int var=-1;
for (int i = 0; i < m_List.GetItemCount(); i++)
{
CString szText = m_List.GetItemText(i, nCol);
if (szText == m_SearchThisItemText)
{
var=i;
}
}
m_List.SetFocus();
m_List.SetItemState (var, LVIS_SELECTED, LVIS_SELECTED);
m_List.GetSelectionMark();
return TRUE; // return TRUE unless you set the focus to a control
}
Can you please let me know what is missing here?any hints?.
Thanks for the help

The answer is hinted at by the boilerplate comment to the return statement. Any selection you make to the CListCtrl will be removed if the focus is set to some other control. And that is exactly what will happen if you return TRUE. Windows will set the focus to the default control on the dialog, probably the OK button.
So you fix it by return FALSE; from OnInitDialog, without setting the focus to anything else before returning.

Related

How to control wxCheckListBox items?

I create a wxCheckListBox and add some items in it.Need to control them if any of items be checked I want to do some functions.Actually this is a cheat dll application.
wxArrayString pSkills;//this is array for my list
wxCheckListBox* SkillList = new wxCheckListBox(Panel1, wxID_ANY, wxPoint(3, 3), wxSize(150, 200), pSkills);//my list
I can control and load items whatever I need.
bool MainFrame::IsChecked(unsigned int uiIndex) const
{
if (IsChecked(uiIndex) == true)
{
return true;
}
else { return false; }
}
I use this for control.
SkillList->Bind(wxEVT_CheckListBox, &MainFrame::IsChecked, this);
And I use this didn't work:)
wxCommandEvent::IsChecked() only works for the events from checkboxes and menu items. To get the current state of an item N in the listbox you need to use SkillList->IsChecked(N).
Please find the code snippet below.
class MainFrame
{
private:
wxCheckListBox *SkillList;
public:
MainFrame(/*set of parameters*/);
}
MainFrame::MainFrame(/*set of parameters*/)
{
SkillList = new wxCheckListBox(Panel1, wxID_ANY, wxPoint(3, 3), wxSize(150, 200), pSkills);//my list
SkillList->Bind( wxEVT_CHECKLISTBOX, &MainFRame::check, this );
}
void MainFrame::check(wxCommandEvent &event)
{
if( SkillList->IsChecked( 0 ) )
wxMessageBox( "Item 0 is checked" );
}
Also, I strongly advise you to start using sizers.
Look at the code, compare with what you have, understand you issues and only then use it in your program.

How to get current row of QTableWidget if I clicked on its child?

I have created a QTableWidget in which I've used setCellWidget(QWidget*). I've set QLineEdit in the cell widget. I've also created a delete button and clicking that button sends a signal to the function deleteRow. I've also used a function currentRow() to get the current row, but it returns -1 because of the QLineEdit. The code snippet is below.
void createTable() {
m_table = new QTableWidget(QDialog); //member variable
for (int i = 0; i < 3; i++)
{
QLineEdit *lineEdit = new QLineEdit(m_table);
m_table->setCellWidget(i, 0, lineEdit);
}
QPushButton *deleteBut = new QPushButton(QDiaolg);
connect(deleteBut, SIGNAL(clicked()), QDialog, SLOT(editRow()));
}
editRow() {
int row = m_table->currentRow(); // This gives -1
m_table->remove(row);
}
In above scenario I click in the QLineEdit and then click on the button delete. Please help me out with a solution.
Just tried it here, it seems that currentRow of the table returns -1 when clicking the button right after program start, and when first selecting a cell, then selecting the QLineEdit and then clicking the button, the correct row is returned.
I would do the following as a workaround: Save the row number in the QLineEdit, e.g. by using QObject::setProperty:
QLineEdit *lineEdit = new QLineEdit(m_table);
lineEdit->setProperty("row", i);
m_table->setCellWidget(i, 0, lineEdit);
Then, in the editRow handler, retrieve the property by asking the QTableWidget for its focused child:
int row = m_table->currentRow();
if (row == -1) {
if (QWidget* focused = m_table->focusWidget()) {
row = focused->property("row").toInt();
}
}
The accepted solution, as is, would not work if rows might get deleted while the program runs. Thus the approach would require to update all the properties. Can be done, if this is a rare operation.
I got away with an iteration approach:
for(unsigned int i = 0; i < table->rowCount(); ++i)
{
if(table->cellWidget(i, relevantColumn) == QObject::sender())
{
return i;
}
}
return -1;
Quick, dirty, but worked, and in my case more suitable, as rows got deleted often or changed their positions, only buttons in the widget were connected to the slot and the slot was never called directly. If these conditions are not met, further checks might get necessary (if(QObject::sender()) { /* */ }, ...).
Karsten's answer will work correctly only if QLineEdit's property is recalculated each time a row is deleted, which might be a lot of work. And Aconcagua's answer works only if the method is invoked via signal/slot mechanism. In my solution, I just calculate the position of the QlineEdit which has focus (assuming all table items were set with setCellWidget):
int getCurrentRow() {
for (int i=0; i<myTable->rowCount(); i++)
for (int j=0; j<myTable->columnCount(); j++) {
if (myTable->cellWidget(i,j) == myTable->focusWidget()) {
return i;
}
}
return -1;
}

When deleting item in Combobox the secong one pop-up MFC

I have combo box and delete button. I want to make next combo box item pop-up when delete button pressed and when last item deleted clean combo box selected item.
I tried several methods with indexes but even one wont help me.
there is my code:
if(IDYES == MessageBox(L"Delete save?",L"Delete", MB_YESNO|MB_ICONQUESTION)){
CString pFileName = L"Save\\"+str+".dat";
CFile::Remove(pFileName);
CComboBox* pComboBox = (CComboBox*)GetDlgItem(IDC_COMBO_SAVE);
pComboBox->ResetContent();
}
How I can to make next combo box item pop-up when delete button pressed and when last item deleted clean combo box selected item?
I found a solution:
void CL2HamsterDlg::OnBnClickedButtonDelete(){
if(Validate()){
if(IDYES == MessageBox(L"Delete save?",L"Delete", MB_YESNO|MB_ICONQUESTION)){
CString pFileName = L"Save\\"+str+".dat";
CFile::Remove(pFileName);
CComboBox* pComboBox = (CComboBox*)GetDlgItem(IDC_COMBO_SAVE);
lookforfile();
int nIndex = pComboBox->GetCurSel();
if (nIndex == CB_ERR)
pComboBox->SetCurSel(0);
else{
pComboBox->SetEditSel(0, -1);
pComboBox->Clear();
}
}
LoadSave(false);
}else
AfxMessageBox(L"Please select or write correct name!");
}
the function look for file refreshes index
void CL2HamsterDlg::lookforfile()
{
Value.GetWindowText(str);
CComboBox* pComboBox = (CComboBox*)GetDlgItem(IDC_COMBO_SAVE);
pComboBox->ResetContent();
GetCurrentDirectory(MAX_PATH,curWorkingDir);
_tcscat_s(curWorkingDir, MAX_PATH, _T("\\Save\\*.dat"));
BOOL bWorking = finder.FindFile(curWorkingDir);
while (bWorking){
bWorking = finder.FindNextFile();
if (!finder.IsDots())
pComboBox->AddString(finder.GetFileTitle());
}
GetDlgItem(IDC_COMBO_SAVE)->SetWindowText(str);
}
so, in this case you do not need to use ResetContent(). Provided you already know the currently selected Item in the combobox (I think somewhere along the track you would have used the line int iSel = pComboBox->GetCurSel();) you could use this code IN PLACE OF YOUR pComboBox->ResetContent();:
pComboBox->DeleteString(iSel);
if(iSel < pComboBox->GetCount())
pComboBox->SetCurSel(iSel);
else if(iSel > 0)
pComboBox->SetCurSel(iSel-1);
However, I think this will not be necessary. I think the item will move by itself. So, forget about the code above, just use this:
pComboBox->DeleteString(pComboBox->GetCurSel())

MFC ListView Change Item Image

I have added items to ListControl, they have images. Now I want to change them, I tried to do GetItem and SetItem, but I was not able. At least I don't know how to get an Item I want. How I can change Image of an item in ListView?
Thanks
P.S.
I've managed to solve it. Here is solution:
This is how to loop
LVITEMW pitem;
ZeroMemory(&pitem, sizeof(pitem));
pitem.mask = LVIF_TEXT | LVIF_IMAGE;
pitem.iItem = <SET INDEX OF YOUR ITEMS HERE, YOU CAN LOOP HERE>;
pitem.iSubItem = 0;
pitem.pszText = new wchar_t[256];
pitem.cchTextMax = 255;
mlist.GetItem(&pitem);
And after selecting an item, you can change it's image like this:
pitem.iImage = newindex;
mlist.SetItem(&pitem);
Using CListCtrl::SetItem is right. You have to set the nMask parameter to LVIF_IMAGE and provide the index of the image in der image-list in the iImage parameter.
The solution highlighted in the first post was not working for me. After a short look to Microsoft Documentation, the signature of the SetItem function is:
BOOL SetItem(const LVITEM* pItem);
pItem should be a pointer to a LVITEM which is const, which is not really the case in this situation...
However, the next solution is working for me:
// Let's say my CListCtrl is named m_listCtrl
// Loop on items of CListCtrl
for( int i = 0; i < m_listCtrl.GetItemCount(); i++ )
{
// And then you define a new image with the index iImage for the item i
m_listCtrl.SetItem(i, 0, LVIF_IMAGE, NULL,
iImage, 0, 0, 0);
}

MFC limit selected item in ClistCtrl

Hi
I use ClistCtrl that have 20 items and I want to limit selected item number.
for example only 10 item can be selected.
how i can do it?
thanks for your help herzl.
You would have to handle the LVN_ODSTATECHANGED notification message and count the number of selected item each time the LVIS_SELECTED state changes
Thanks
So I wrote this code. It should work. Just create an event handler for the list
void CDatenbankView::OnLvnItemchangedList1(NMHDR *pNMHDR, LRESULT *pResult)
{
int SelctedItems;
SelctedItems = 0;
int Index;
LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
for (Index = 0; Index < m_List.GetItemCount(); ) //Check every Item
{
if (m_List.GetItemState (Index, LVIS_SELECTED) == LVIS_SELECTED) //Checks if it is selected
{
if (SelctedItems > 10)
{
MessageBox (_T("Cant select more than 10 Items"));
for (Index = 0; Index < m_List.GetItemCount(); )
{
m_List.SetItemState (Index, ~LVIS_SELECTED, LVIS_SELECTED);
Index++;
}
break;
}
else
{
SelctedItems++;
}
}
Index++;
}
*pResult = 0;
}
m_List is my control variable for the CListCtrl
There is no built-in functionality for such a feature. You'd have to write your our code for that. Maybe you can find another way to do it, like having a source list and a "selection list". You copy/move items from the first to the second, but you do not allow the users to put more than 10 items into the destination list.