CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 11 of 11

Threaded View

  1. #1
    Join Date
    Oct 2006
    Posts
    23

    MFC, ListCtrl selection question

    Project_Main_Code.cpp
    Code:
    #include "Project_Main_Header.h"
    #include "resource.h"
    
    CMyApp myApp;
    
    BOOL CMyApp::InitInstance()
    {
    	//Create dialog box as the main window
    	m_pMainWnd = new CMainDialog;
    	m_pMainWnd->ShowWindow(m_nCmdShow);
    	m_pMainWnd->UpdateWindow();
    	return TRUE;
    }
    
    
    BEGIN_MESSAGE_MAP(CMainDialog,CDialog)
    	
    	//Message Handlers for the button pressed
    	ON_BN_CLICKED(IDC_BUTTON_EXIT,OnDialogExit)
    	ON_BN_CLICKED(IDC_BUTTON_ADD,OnAddTask)
    	ON_BN_CLICKED(IDC_BUTTON_DELETE,OnDeleteTask)
    	ON_BN_CLICKED(IDC_BUTTON_INSA,OnInsertAbove)
    	ON_BN_CLICKED(IDC_BUTTON_INSB,OnInsertBelow)
    
    	//Message Handler to repaint the dialog box
    	ON_WM_PAINT()
    
    	//Message Handler to check if any changes has been made in Edit Box
    	ON_EN_CHANGE(IDC_EDIT_TASKTITLEWRITE,OnUpdateEditCtrl)
    
    	//Message Handler to check if any selections made in ListCtrl
    	ON_NOTIFY(LVN_ITEMCHANGED,IDC_LIST_TASK,OnUpdateListCtrl)
    
    END_MESSAGE_MAP()
    
    CMainDialog::CMainDialog()
    {
    	//Constructor to create the dialog box
    	Create(IDD_MAIN_DIALOG);
    }
    
    BOOL CMainDialog::OnInitDialog()
    {
    	CDialog::OnInitDialog();
    	//Initialization function call for ListCtrl.
    	OnInitListCtrl(); 
    	OnInitCalCtrl();
    
    	//Disables the buttons initially
    	GetDlgItem(IDC_BUTTON_ADD)->EnableWindow(FALSE);
    	GetDlgItem(IDC_BUTTON_DELETE)->EnableWindow(FALSE);
    	GetDlgItem(IDC_BUTTON_INSA)->EnableWindow(FALSE);
    	GetDlgItem(IDC_BUTTON_INSB)->EnableWindow(FALSE);
    	
    	//Modifies the DWSTYLE. Changes to a window without a system 
    	//close button on Top-Right corner of the dialog box.
    	ModifyStyle(WS_SYSMENU,0,0);
    
    	return TRUE;
    }
    
    void CMainDialog::OnInitCalCtrl()
    {
    	//Create a local Month Calendar Control Object
    	CMonthCalCtrl *l_MonthCalCtrl = (CMonthCalCtrl*)GetDlgItem(IDC_MONTHCALENDAR);
    	//Set the cursor in the month calendar object to the current date
    	l_MonthCalCtrl->SetCurSel(COleDateTime::GetCurrentTime());
    
    	//Create a local DateTimeCtrl object
    	CDateTimeCtrl *l_DateTimeCtrl = (CDateTimeCtrl*)GetDlgItem(IDC_DATETIMEPICKER);
    	//Set the current time in the object
    	l_DateTimeCtrl->SetTime(COleDateTime::GetCurrentTime());
    }
    
    void CMainDialog::OnInitListCtrl()
    {
    	//Retrieve Dialog item for List Ctrl
    	//And store it in pListCtrl
    	pListCtrl = (CListCtrl*) GetDlgItem(IDC_LIST_TASK);
    
    	//Insert all columns displayed on the list control
    	pListCtrl->InsertColumn(0,"Start Time",LVCFMT_LEFT,100);
    	pListCtrl->InsertColumn(1,"Month",LVCFMT_CENTER,100);
    	pListCtrl->InsertColumn(2,"Date",LVCFMT_CENTER,100);
    	pListCtrl->InsertColumn(3,"Day",LVCFMT_CENTER,100);
    	pListCtrl->InsertColumn(4,"Year",LVCFMT_CENTER,100);
    	pListCtrl->InsertColumn(5,"Title",LVCFMT_CENTER,270);
    }
    
    
    void CMainDialog::DoDataExchange(CDataExchange *pDX)
    {
    	CDialog::DoDataExchange(pDX);
    
    	//DoDataExchange functions for the title, monthctrl and time.
    	DDX_Text(pDX, IDC_EDIT_TASKTITLEWRITE, m_sTitle);
    	DDX_MonthCalCtrl(pDX,IDC_MONTHCALENDAR,m_cMonth);
    	DDX_DateTimeCtrl(pDX,IDC_DATETIMEPICKER,m_cTime);
    
    }
    
    void CMainDialog::OnUpdateEditCtrl()
    {
    	//As soon as any changes have been made in the Editbox,
    	//Enables the add button
    	GetDlgItem(IDC_BUTTON_ADD)->EnableWindow(TRUE);
    }
    
    void CMainDialog::OnUpdateListCtrl(NMHDR * pNotifyStruct, LRESULT * result )
    {
    	UpdateData(FALSE);
    	//As soon as any selections have been made in the list control,
    	//Enables the insert above and insert below objects.
    	GetDlgItem(IDC_BUTTON_INSA)->EnableWindow(TRUE);
    	GetDlgItem(IDC_BUTTON_INSB)->EnableWindow(TRUE);
    
    	//pListCtrl must be retrieved again
    	//as the variable is modified in the memory
    	//during run-time of application
    
    	//I.E : Code crashes if the item is not retrieved again.
    	pListCtrl = (CListCtrl*) GetDlgItem(IDC_LIST_TASK);
    
    	//Retrieve the index of the item selected (Row #)
    	int l_nSelected = pListCtrl->GetSelectionMark();
    
    	//Concatenate the strings, based on the column entries
    	CString l_tempStr = pListCtrl->GetItemText(l_nSelected,1)
    		+ " " + pListCtrl->GetItemText(l_nSelected,2) + " "
    		+ pListCtrl->GetItemText(l_nSelected,3) + " " +
    		pListCtrl->GetItemText(l_nSelected,4);
    
    	//Set the string in edit control box (Day)
    	//Object must be fetched again
    	l_EditBoxDay = (CEdit*) GetDlgItem(IDC_EDIT_TASKDAY);
    	l_EditBoxDay->SetWindowText(l_tempStr);
    
    	//Set the string for the time (Column 0)
    	l_tempStr = pListCtrl->GetItemText(l_nSelected,0);
    
    	//Set the string in edit control box (Time)
    	l_EditBoxTime = (CEdit*) GetDlgItem(IDC_EDIT_TASKTIME);
    	l_EditBoxTime->SetWindowText(l_tempStr);
    
    	//Set the string for the title
    	l_tempStr = pListCtrl->GetItemText(l_nSelected,5);
    
    	//Set the string in edit control box (Title)
    	l_EditBoxTitle = (CEdit*) GetDlgItem(IDC_EDIT_TASKTITLEDISP);
    	l_EditBoxTitle->SetWindowText(l_tempStr);
    }
    
    void CMainDialog::OnPaint()
    {
    	//Repaints the client area
    	CPaintDC dc (this);	
    }
    
    void CMainDialog::OnDialogExit()
    {
    	//Destroys the window
    	DestroyWindow();
    }
    
    void CMainDialog::OnInsertAbove()
    {
    	//Method to call DoDataExchange. 
    	//UpdateData() is used, as DoDataExchange
    	//Cannot be called directly.
    	UpdateData();
    
    	//pListCtrl must be retrieved again
    	//as the variable is modified in the memory
    	//during run-time of application
    
    	//I.E : Code crashes if the item is not retrieved again.
    	pListCtrl = (CListCtrl*) GetDlgItem(IDC_LIST_TASK);
    
    	//Fetch the row # from the selection made
    	int l_listCtrlRow = pListCtrl->GetSelectionMark();
    
    	//Insert the time as a selectable item
    	pListCtrl->InsertItem(l_listCtrlRow,m_cTime.Format("%I:%M %p"));
    
    	//Set the corresponding texts onto the same column (Unselectable)
    
    	//Sets the Month, Day, Date and Year based on the format given
    	pListCtrl->SetItemText(l_listCtrlRow,1,m_cMonth.Format("%B"));
    	pListCtrl->SetItemText(l_listCtrlRow,2,m_cMonth.Format("%d"));
    	pListCtrl->SetItemText(l_listCtrlRow,3,m_cMonth.Format("%A"));
    	pListCtrl->SetItemText(l_listCtrlRow,4,m_cMonth.Format("%Y"));
    
    	//Sets the title
    	pListCtrl->SetItemText(l_listCtrlRow,5,m_sTitle);
    	
    	//Creates a local CEdit object to clear the box
    	CEdit *pEditBox = (CEdit*) GetDlgItem(IDC_EDIT_TASKTITLEWRITE);
    	pEditBox->SetSel(0,-1);
    	pEditBox->Clear();
    
    	//Disables the Add, Insert Above and Insert Below buttons	
    	GetDlgItem(IDC_BUTTON_ADD)->EnableWindow(FALSE);
    	GetDlgItem(IDC_BUTTON_INSA)->EnableWindow(FALSE);
    	GetDlgItem(IDC_BUTTON_INSB)->EnableWindow(FALSE);
    }
    
    void CMainDialog::OnInsertBelow()
    {
    	//Method to call DoDataExchange. 
    	//UpdateData() is used, as DoDataExchange
    	//Cannot be called directly.
    	UpdateData();
    
    	//pListCtrl must be retrieved again
    	//as the variable is modified in the memory
    	//during run-time of application
    
    	//I.E : Code crashes if the item is not retrieved again.
    	pListCtrl = (CListCtrl*) GetDlgItem(IDC_LIST_TASK);
    
    	//Fetch the row # from the selection made
    	int l_listCtrlRow = pListCtrl->GetSelectionMark() + 1;
    
    	//Insert the time as a selectable item
    	pListCtrl->InsertItem(l_listCtrlRow,m_cTime.Format("%I:%M %p"));
    
    	//Set the corresponding texts onto the same column (Unselectable)
    
    	//Sets the Month, Day, Date and Year based on the format given
    	pListCtrl->SetItemText(l_listCtrlRow,1,m_cMonth.Format("%B"));
    	pListCtrl->SetItemText(l_listCtrlRow,2,m_cMonth.Format("%d"));
    	pListCtrl->SetItemText(l_listCtrlRow,3,m_cMonth.Format("%A"));
    	pListCtrl->SetItemText(l_listCtrlRow,4,m_cMonth.Format("%Y"));
    
    	//Sets the title
    	pListCtrl->SetItemText(l_listCtrlRow,5,m_sTitle);
    	
    	//Creates a local CEdit object to clear the box
    	CEdit *pEditBox = (CEdit*) GetDlgItem(IDC_EDIT_TASKTITLEWRITE);
    	pEditBox->SetSel(0,-1);
    	pEditBox->Clear();
    
    	//Disables the Add, Insert Above and Insert Below buttons
    	GetDlgItem(IDC_BUTTON_ADD)->EnableWindow(FALSE);
    	GetDlgItem(IDC_BUTTON_INSA)->EnableWindow(FALSE);
    	GetDlgItem(IDC_BUTTON_INSB)->EnableWindow(FALSE);
    }
    
    void CMainDialog::OnAddTask()
    {
    	//Method to call DoDataExchange. 
    	//UpdateData() is used, as DoDataExchange
    	//Cannot be called directly.
    	UpdateData();
    
    	//pListCtrl must be retrieved again
    	//as the variable is modified in the memory
    	//during run-time of application
    
    	//I.E : Code crashes if the item is not retrieved again.
    	pListCtrl = (CListCtrl*) GetDlgItem(IDC_LIST_TASK);
    
    	//Assign the amount of items into the variable
    	m_itemCount = pListCtrl->GetItemCount();
    
    	//Insert the time as a selectable item
    	pListCtrl->InsertItem(m_itemCount,m_cTime.Format("%I:%M %p"));
    
    	//Set the corresponding texts onto the same column (Unselectable)
    
    	//Sets the Month, Day, Date and Year based on the format given
    	pListCtrl->SetItemText(m_itemCount,1,m_cMonth.Format("%B"));
    	pListCtrl->SetItemText(m_itemCount,2,m_cMonth.Format("%d"));
    	pListCtrl->SetItemText(m_itemCount,3,m_cMonth.Format("%A"));
    	pListCtrl->SetItemText(m_itemCount,4,m_cMonth.Format("%Y"));
    
    	//Sets the title
    	pListCtrl->SetItemText(m_itemCount,5,m_sTitle);
    	
    	//Creates a local CEdit object to clear the box
    	CEdit *pEditBox = (CEdit*) GetDlgItem(IDC_EDIT_TASKTITLEWRITE);
    	pEditBox->SetSel(0,-1);
    	pEditBox->Clear();
    
    	//Disables the add, insert above and below button
    	GetDlgItem(IDC_BUTTON_ADD)->EnableWindow(FALSE);
    	GetDlgItem(IDC_BUTTON_INSA)->EnableWindow(FALSE);
    	GetDlgItem(IDC_BUTTON_INSB)->EnableWindow(FALSE);
    
    	//Enables the delete button
    	GetDlgItem(IDC_BUTTON_DELETE)->EnableWindow(TRUE);
    
    }
    
    void CMainDialog::OnDeleteTask()
    {
    	//pListCtrl must be retrieved again
    	//as the variable is modified in the memory
    	//during run-time of application
    
    	//I.E : Code crashes if the item is not retrieved again.
    	pListCtrl = (CListCtrl*) GetDlgItem(IDC_LIST_TASK);
    
    	//Check if the user has made any selections in List Control
    	if(pListCtrl->GetSelectionMark() == -1)
    		MessageBox("Select a Task to Delete","Error");
    	else
    	{
    		//Delete the selected item
    		pListCtrl->DeleteItem(pListCtrl->GetSelectionMark());
    
    		//Check if there's any item remaining in the list control
    		//and disable the delete button, if itemcount = 0
    		if(pListCtrl->GetItemCount()==0)
    			GetDlgItem(IDC_BUTTON_DELETE)->EnableWindow(FALSE);
    
    		//Unselect on the List Control
    		pListCtrl->SetSelectionMark(-1);
    
    		//Disable the Insert Above and Insert Below buttons
    		GetDlgItem(IDC_BUTTON_INSA)->EnableWindow(FALSE);
    		GetDlgItem(IDC_BUTTON_INSB)->EnableWindow(FALSE);
    
    		//Clear the readable-only edit boxes
    		//All the objects needs to be fetched again
    		//(Same case with pListCtrl)
    		l_EditBoxDay = (CEdit*) GetDlgItem(IDC_EDIT_TASKDAY);
    		l_EditBoxDay->SetWindowText("");
    		l_EditBoxTime = (CEdit*) GetDlgItem(IDC_EDIT_TASKTIME);
    		l_EditBoxTime->SetWindowText("");
    		l_EditBoxTitle = (CEdit*) GetDlgItem(IDC_EDIT_TASKTITLEDISP);
    		l_EditBoxTitle->SetWindowText("");
    	}
    	
    }
    
    void CMainDialog::PostNcDestroy()
    {
    	delete this;
    }
    Ok, I'm having a serious problem with the list control and it updating the text to a read-only edit control box.

    Under the OnUpdateListCtrl function, where it triggers as soon as the user selects an item in the list control box, it's supposed to update the read-only edit control box based on the selection made. Now, the problem occurs on this particular line -

    int l_nSelected = pListCtrl->GetSelectionMark();

    This returns the integer of the row # (0, from the first one), but it returns it a tad-bit late. Let me demonstrate what I mean -

    Suppose the program had two items and I clicked on the second item - this properly returns an integer of 1. NOW suppose that I clicked on the first item, it's supposed to return an integer of 0, right? well it doesn't. It returns 1. Again, if I were to click on the second item (Where it should return 1), it returns 0. This becomes a problem because the read-only edit control box updates the information one-step too late.

    This function acts immediately upon WM_NOTIFY message, tricking the list control to think that it hasn't made the selection change just yet.

    I believe I have pinpointed the problem correctly, but I do not know of the correct fix. I was thinking about using CPoint in the OnUpdateListCtrl, but I believe that's taking things way too far in terms of the correction. There has to be an easier fix for this.

    Can anyone tell me any suggestions? I'd greatly appriciate any help.
    Last edited by l46kok; May 4th, 2008 at 12:59 PM.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured