📄 tyopcclientview.cpp
字号:
int nColumnCount = cListCtrl.GetHeaderCtrl()->GetItemCount();
int nItem=0;
CString strText;
cListCtrl.InsertItem(LVIF_TEXT|LVIF_STATE, nItem, strText,
LVIS_SELECTED , LVIS_SELECTED,
0, 0);
int nIndex=1;
// Item ID
cListCtrl.SetItemText (nItem,nIndex++,pItem->GetItemID ());
// Data Type
cListCtrl.SetItemText (nItem,nIndex++,pItem->GetDataType());
// Value
cListCtrl.SetItemText (nItem,nIndex++,pItem->GetValue(pItem->GetValue()));
// Timestamp
cListCtrl.SetItemText (nItem,nIndex++,pItem->GetTimeStamp ());
// Quality
cListCtrl.SetItemText (nItem,nIndex++,pItem->GetQuality ());
// Update Count
cListCtrl.SetItemText (nItem,nIndex++,pItem->GetUpdateCount ());
//*/
// Create a CSafeLock to make this object thread safe. Our critical
// section gets locked here, and will automatically be unlocked when the
// CSafeLock goes out of scope.
CSafeLock cs (&m_csSortedList);
// Make sure item pointer was set (debuf only):
ASSERT (pItem != NULL);
// If sorted item list is full, we need to allocate another block of
// memory big enough for current list plus room for more items and
// transfer current list to it:
if (m_nSortedItems == m_nSortedListSize)
{
DWORD *pSortList = NULL;
// Be prepared to deal with allocation problems (p will be NULL in
// this event):
try
{
// Allocate the next largest size:
pSortList = new DWORD [m_nSortedListSize + GROWLIST];
// Initialize new memory:
ZeroMemory (pSortList, sizeof (sm_pSortedItems [0]) * (m_nSortedListSize + GROWLIST));
// Transfer existing items to the new memory:
if (0<m_nSortedItems) //存在COPCItem数据
{
// Copy old to new:
memcpy (pSortList, sm_pSortedItems, m_nSortedItems * sizeof (sm_pSortedItems [0]));
// Free old memory:
delete [] sm_pSortedItems;
sm_pSortedItems=NULL;
}
// Point to new list:
sm_pSortedItems = pSortList;
// Increment allocated list size:
m_nSortedListSize += GROWLIST;
}
catch (...)
{
pSortList = NULL;
}
}
// Add the item to the sorted list:
sm_pSortedItems [m_nSortedItems++] = (DWORD)pItem;
//*/
}
void CViewOPCItem::OnGetDispInfo(NMHDR* pNMHDR, LRESULT* pResult)
{
// HD_NOTIFY * phdn = (HD_NOTIFY *) pHNMHDR;
// TODO: Add your control notification handler code here
// Create a CSafeLock to make this object thread safe. Our critical
// section gets locked here, and will automatically be unlocked when the
// CSafeLock goes out of scope.
CSafeLock cs (&m_csSortedList);
// Cast generic notification message pointer to list view notification
// message pointer:
LV_DISPINFO *plvdi = (LV_DISPINFO *)pNMHDR;
// Get pointer to list view item information structure from message
// notification structure:
LV_ITEM *plvItem = &plvdi->item;
// If there are no items in the sorted item list, then there is no
// work to be done here.
if (sm_pSortedItems == NULL //数据项地址数组
|| m_nSortedItems == 0 //数据项地址数组中无数组
)
return;
// If index of item we are being ased to supply information for is
// greater than the number of items in our sorted item list, then
// there is something wrong. Return immediately.
if (plvItem->iItem >= m_nSortedItems)
{ //存在一个错误----可能程序计算错误
return;
}
// Get pointer to COPCItem object from sorted item list:
COPCItem *pItem = (COPCItem *)sm_pSortedItems [plvItem->iItem];
ASSERT (pItem != NULL);
// If we are being asked to supply item text:
if (plvItem->mask & LVIF_TEXT)
{
// See what subitem (column) text is needed for. Copy requested
// text to output structure:
switch (plvItem->iSubItem)
{
case 0: // Item Alias
{
// TRACE("CViewOPCItem::OnGetDispInfo()--%s\n",pItem->GetItemID ());
lstrcpyn (plvItem->pszText, pItem->GetAlias (), plvItem->cchTextMax);
break;
}
case 1: // Item ID
{
// TRACE("CViewOPCItem::OnGetDispInfo()--%s\n",pItem->GetItemID ());
lstrcpyn (plvItem->pszText, pItem->GetItemID (), plvItem->cchTextMax);
break;
}
case 2: // Data Type
{
// Convert data type to string:
static CString strDataType;
pItem->GetDataType (strDataType);
lstrcpyn (plvItem->pszText, strDataType, plvItem->cchTextMax);
break;
}
case 3: // Value
{
static CString strValue;
pItem->GetValue (strValue);
lstrcpyn (plvItem->pszText, strValue, plvItem->cchTextMax);
break;
}
case 4: // Timestamp
{
static CString strTimeStamp;
pItem->GetTimeStamp (strTimeStamp);
lstrcpyn (plvItem->pszText, strTimeStamp, plvItem->cchTextMax);
break;
}
case 5: // Quality
{
static CString strQuality;
pItem->GetQuality (strQuality);
lstrcpyn (plvItem->pszText, strQuality, plvItem->cchTextMax);
break;
}
case 6: // Active
{
static CString strActive;
if(pItem->IsActive ())
strActive=_T("√");
else
strActive=_T("×");
lstrcpyn (plvItem->pszText, strActive, plvItem->cchTextMax);
break;
}
case 7: // Update Count
{
// Format numerical value as string:
TCHAR szNum [64];
wsprintf (szNum, _T("%u"), pItem->GetUpdateCount ());
lstrcpyn (plvItem->pszText, szNum, plvItem->cchTextMax);
break;
}
default:
break;
}
}
// If we are being asked to supply item image. Return index into
// list control's image list:
if (plvItem->mask & LVIF_IMAGE)
{
// If item is valid, specify active or inactive item image
// as the case may be.
// if (pItem->IsValid ())
plvItem->iImage = pItem->IsActive () ? 0 : 1;
// else // Else specify invalid item image:
// plvItem->iImage = 2;
}
*pResult = 0;
}
void CViewOPCItem::SortItems()
{
// Create a CSafeLock to make this object thread safe. Our critical
// section gets locked here, and will automatically be unlocked when the
// CSafeLock goes out of scope.
CSafeLock cs (&m_csSortedList);
// Get reference to out list control:
CListCtrl &cList = GetListCtrl ();
// If there are no items in the list, then there is nothing to do:
if (0>=m_nSortedItems)
return;
// Get number of selected items:
int cnSelections = cList.GetSelectedCount ();
// Initialize a variable to contain the index of item with focus:
int nFocus = -1;
// Save off selected items so we can restore them after sort:
CMemFile cMem (cnSelections * sizeof (DWORD));
// Don't bother looking for selected items if there are none:
if (cnSelections)
{
// Find the first selected item:
int nSel = cList.GetNextItem (-1, LVNI_ALL | LVNI_SELECTED);
// Save the items index if it has the focus:
if (cList.GetItemState (nSel, LVIS_FOCUSED) == LVIS_FOCUSED)
nFocus = sm_pSortedItems [nSel];
// Clear the selection and store off the array element (pointer
// to COPCItem object):
cList.SetItemState (nSel, 0, LVIS_SELECTED | LVIS_FOCUSED);
cMem.Write (&sm_pSortedItems [nSel], sizeof (DWORD));
// Store off remaining selections:
int n = cnSelections;
while (--n)
{
// Get index of next selected item:
nSel = cList.GetNextItem (nSel, LVNI_BELOW | LVNI_SELECTED);
ASSERT (nSel != -1);
// Store it's index if it has the focus:
if (nFocus == -1 && cList.GetItemState (nSel, LVIS_FOCUSED) == LVIS_FOCUSED)
nFocus = sm_pSortedItems [nSel];
// Clear the selection and store off the index:
cList.SetItemState (nSel, 0, LVIS_SELECTED | LVIS_FOCUSED);
cMem.Write (&sm_pSortedItems [nSel], sizeof (DWORD));
}
}
// Sort the list. qsort function requires us to define a function to
// compare items.
qsort ((void *)sm_pSortedItems, m_nSortedItems,
sizeof (sm_pSortedItems [0]), CompareItems);
// Now restore original selections:
if (cnSelections)
{
// Reset file pointer to beginning:
cMem.SeekToBegin ();
// There is one unsorted index in the memory file for each
// selection detected above:
for (int i = 0; i < cnSelections; i++)
{
// Read the index (actually pointer to COPCItem object cast as DWORD)
// of first selected item:
DWORD dwIndex;
cMem.Read (&dwIndex, sizeof (DWORD));
// Find the item's location in the sorted array. Look at each
// element in array until we find the item:
for (int j = 0; j < m_nSortedItems; j++)
{
// We have found the item if the array element is the original index:
if (sm_pSortedItems [j] == dwIndex)
{
// Make sure the focused item is visible:
if (dwIndex == (DWORD)nFocus)
{
cList.EnsureVisible (j, false);
cList.SetItemState (j, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
}
// Restore selection:
else
cList.SetItemState (j, LVIS_SELECTED, LVIS_SELECTED);
// If we are here, we found the item. No need to continue
// searching so break out of loop.
break;
}
}
}
}
// Force the list control to repaint itself:
GetListCtrl ().Invalidate (true);
}
// **************************************************************************
// CompareItems ()
//
// Description:
// Compares the order of items when sorting by values in one of the list
// control columns. Used by the qsort function, so we need to declare
// parameters as void pointers.
//
// Parameters:
// const void *arg1 Pointer to the first items.
// const void *arg2 Pointer to the second item.
//
// Returns:
// int - Returns a negative number if the arg1 comes first, 0 if arg1 and
// arg2 are the same, or a positive value if arg2 comes first.
// **************************************************************************
int CViewOPCItem::CompareItems(const void *arg1, const void *arg2)
{
// Initialize a variable to contain comparison result:
int nRC = 0;
// Cast arguments to COPCItem pointers (this what the calling routine
// is really comparing).
COPCItem *pItem1 = (COPCItem *)(*(DWORD *)arg1);
COPCItem *pItem2 = (COPCItem *)(*(DWORD *)arg2);
// Sort based on the column parameter passed to SortItems():
switch (sm_wSortColumn)
{
case 0: // Item Alias
// Item Alias is a string, so do a simple string compare:
nRC = lstrcmp (pItem1->GetAlias (), pItem2->GetAlias ());
break;
case 1: // Item ID
// Item ID is a string, so do a simple string compare:
nRC = lstrcmp (pItem1->GetItemID (), pItem2->GetItemID ());
break;
case 2: // Data Type
{
// Must get data types and convert them to strings:
static CString strType1;
static CString strType2;
pItem1->GetDataType (strType1);
pItem2->GetDataType (strType2);
// Now compare strings:
nRC = lstrcmp (strType1, strType2);
}
break;
case 3: // Value
{
// Get string representation of values:
static CString strValue1;
static CString strValue2;
pItem1->GetValue (strValue1);
pItem2->GetValue (strValue2);
// Compare strings:
nRC = lstrcmp (strValue1, strValue2);
}
break;
case 4: // Timestamp
{
// Get string representation of timestamp:
static CString strTimeStamp1;
static CString strTimeStamp2;
pItem1->GetTimeStamp (strTimeStamp1);
pItem2->GetTimeStamp (strTimeStamp2);
// Compare strings:
nRC = lstrcmp (strTimeStamp1, strTimeStamp2);
}
break;
case 5: // Quality
{
// Quality is a string, so do string compare:
static CString strQuality1;
static CString strQuality2;
pItem1->GetQuality (strQuality1);
pItem2->GetQuality (strQuality2);
nRC = lstrcmp (strQuality1, strQuality2);
break;
}
case 6: // Active
{
// Quality is a string, so do string compare:
static BOOL bActive1;
static BOOL bActive2;
bActive1=pItem1->IsActive ();
bActive2=pItem2->IsActive ();
// Compare numerical update counts:
if (bActive1 == bActive2)
nRC = 0;
else if (bActive1 > bActive2)
nRC = -1;
else
nRC = 1;
break;
}
case 7: // Update Count
{
// Get update counts:
DWORD dwUpdates1 = pItem1->GetUpdateCount ();
DWORD dwUpdates2 = pItem2->GetUpdateCount ();
// Compare numerical update counts:
if (dwUpdates1 == dwUpdates2)
nRC = 0;
else if (dwUpdates1 > dwUpdates2)
nRC = -1;
else
nRC = 1;
}
break;
// Unexpected column index:
default:
ASSERT (FALSE);
break;
}
// Equal items should be sorted by item ID:
if (sm_wSortColumn && nRC == 0)
nRC = lstrcmp (pItem1->GetItemID (), pItem2->GetItemID ());
// If the order is descending, reverse the result:
if (LOWORD (sm_wSortOrder) == DESCENDING)
nRC = -nRC;
// Return the result:
return (nRC);
}
void CViewOPCItem::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code here and/or call default
// Process according to timer event type:
switch (nIDEvent)
{
// Update the item pane. This will cause the items' value,
// quality, timestamp, etc. to get refreshed.
case UPDATE_ITEMPANE_EVENT:
{
// Get reference to our list control:
CListCtrl &cList = GetListCtrl ();
// If there are items in the list control, update the view:
if (cList.GetItemCount () > 0)
{
int nTopIndex;
CRect rc;
CRect rcitem;
// Get index of the first visible item:
nTopIndex = cList.GetTopIndex ();
// Get client area rectangle. We will modify this rectangle to
// only include the area of the view we wish to refresh.
cList.GetClientRect (&rc);
// Get rectangel that bounds top visible item:
cList.GetItemRect (nTopIndex, &rcitem, LVIR_BOUNDS);
// Reset left bound of rc to exclude first column. There
// is no need to refresh this (item ID and image). We are
// interested in refreshing all other properties/columns.
rc.left = cList.GetColumnWidth (0);
// No need to refresh anything above top of uppermost item:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -