📄 itempropertiesdlg.cpp
字号:
// **************************************************************************
// itempropertiesdlg.cpp
//
// Description:
// Implements a dialog class for assigning OPC item properties.
//
// DISCLAIMER:
// This programming example is provided "AS IS". As such Kepware, Inc.
// makes no claims to the worthiness of the code and does not warranty
// the code to be error free. It is provided freely and can be used in
// your own projects. If you do find this code useful, place a little
// marketing plug for Kepware in your code. While we would love to help
// every one who is trying to write a great OPC client application, the
// uniqueness of every project and the limited number of hours in a day
// simply prevents us from doing so. If you really find yourself in a
// bind, please contact Kepware's technical support. We will not be able
// to assist you with server related problems unless you are using KepServer
// or KepServerEx.
// **************************************************************************
#include "stdafx.h"
#include "opctestclient.h"
#include "itempropertiesdlg.h"
#include "item.h"
#include "server.h"
#include "mainwnd.h"
#define NUMCOLUMNS 4
/////////////////////////////////////////////////////////////////////////////
// CKItemPropertiesDlg dialog
/////////////////////////////////////////////////////////////////////////////
// **************************************************************************
BEGIN_MESSAGE_MAP (CKItemPropertiesDlg, CDialog)
//{{AFX_MSG_MAP(CKItemPropertiesDlg)
ON_BN_CLICKED (IDC_NEXT, OnNext)
ON_BN_CLICKED (IDC_PREVIOUS, OnPrevious)
ON_BN_CLICKED (IDC_ACTIVE, OnActive)
ON_CBN_SELCHANGE (IDC_DATATYPE, OnChangeDataType)
//}}AFX_MSG_MAP
END_MESSAGE_MAP ()
// **************************************************************************
// CKItemPropertiesDlg ()
//
// Description:
// Constructor.
//
// Parameters:
// CObArray &cItemList Array of items objects that can be viewed and
// modified with this dialog.
// DWORD cdwItems Number of items in cItemList.
// IOPCItemMgt *pIItemMgt Pointer to IOPCItemMgt interface.
// CKServer *pServer Pointer to server items belong to.
// CWnd *pParent Pointer to parent window.
//
// Returns:
// none
// **************************************************************************
CKItemPropertiesDlg::CKItemPropertiesDlg (CObArray &cItemList,
DWORD cdwItems,
IOPCItemMgt *pIItemMgt,
CKServer *pServer,
CWnd *pParent /*=NULL*/)
: CDialog (CKItemPropertiesDlg::IDD, pParent)
{
ASSERT (cdwItems > 0);
ASSERT (pServer);
// Intialize members:
m_pItemList = &cItemList;
m_cnItems = (int) cdwItems;
m_pIItemMgt = pIItemMgt;
m_pIItemProps = pServer->GetIItemProps ();
m_pServer = pServer;
m_nSelIndex = 0;
m_bModified = false;
// Initialize bitmap buttons:
m_cNext.Initialize (IDB_NEXT, IDB_NEXTGRAY);
m_cPrev.Initialize (IDB_PREVIOUS, IDB_PREVIOUSGRAY);
}
// **************************************************************************
// DoDataExchange ()
//
// Description:
// This method is called by the framework to exchange and validate dialog data.
//
// Parameters:
// CDataExchange *pDX A pointer to a CDataExchange object.
//
// Returns:
// void
// **************************************************************************
void CKItemPropertiesDlg::DoDataExchange (CDataExchange *pDX)
{
// Perform default processing:
CDialog::DoDataExchange (pDX);
// Exchange data between controls and associated member variables:
//{{AFX_DATA_MAP(CKItemPropertiesDlg)
DDX_Text (pDX, IDC_ACCESSPATH, m_strAccessPath);
DDX_Check (pDX, IDC_ACTIVE, m_bActive);
DDX_Text (pDX, IDC_ITEMID, m_strItemID);
//}}AFX_DATA_MAP
// Get pointer to data type combo box:
CComboBox *pCombo = (CComboBox *)GetDlgItem (IDC_DATATYPE);
CString strType;
// If not save and validate, use member vaiable value to make
// data type combo box selection:
if (!pDX->m_bSaveAndValidate)
{
CString strType;
switch (m_vtDataType & ~VT_ARRAY)
{
case VT_BOOL: strType = _T("Boolean"); break;
case VT_UI1: strType = _T("Byte"); break;
case VT_I1: strType = _T("Char"); break;
case VT_UI2: strType = _T("Word"); break;
case VT_I2: strType = _T("Short"); break;
case VT_UI4: strType = _T("DWord"); break;
case VT_I4: strType = _T("Long"); break;
case VT_R4: strType = _T("Float"); break;
case VT_R8: strType = _T("Double"); break;
case VT_BSTR: strType = _T("String"); break;
default: strType = _T("Native"); break;
}
// Update array flag data:
if ((m_vtDataType & VT_ARRAY) != 0)
strType += _T(" Array");
// Select data type:
pCombo->SelectString (-1, strType);
}
// else transfer data type combo box index to vartype member variable:
else
{
pCombo->GetLBText (pCombo->GetCurSel (), strType);
m_vtDataType = VartypeFromString (strType);
}
}
/////////////////////////////////////////////////////////////////////////////
// CKItemPropertiesDlg message handlers
/////////////////////////////////////////////////////////////////////////////
// **************************************************************************
// OnInitDialog ()
//
// Description:
// Called immediately before the dialog box is displayed. Use opportunity
// to initialize controls.
//
// Parameters:
// none
//
// Returns:
// BOOL - Result of base class processing.
// **************************************************************************
BOOL CKItemPropertiesDlg::OnInitDialog ()
{
CString strText;
// Limit the access path to 255 chars:
((CEdit *)GetDlgItem (IDC_ACCESSPATH))->LimitText (255);
// Allow 10 levels of 32 character names plus a tag name of 31 characters:
((CEdit *)GetDlgItem (IDC_ITEMID))->LimitText (10*32 + 31);
// Subclass image buttons:
m_cNext.SubclassDlgItem (IDC_NEXT, this);
m_cPrev.SubclassDlgItem (IDC_PREVIOUS, this);
// Create tool tips for image buttons:
m_cToolTip.Create (this);
m_cToolTip.AddWindowTool (&m_cNext);
m_cToolTip.AddWindowTool (&m_cPrev);
// Intialize IItemProperties 2.0 list control headings:
CListCtrl *pList = (CListCtrl *) GetDlgItem (IDC_LIST);
ASSERT (pList != NULL);
// Get rectangle that bounds list control:
CRect rc;
pList->GetWindowRect (&rc);
// Calculate the width of the list control:
int nTotalWidth;
nTotalWidth = rc.right - rc.left;
// Create the list control columns. Headers will be loaded from
// string resources and widths will be a function of total width
// of list control:
for (int i = 0; i < NUMCOLUMNS; i++)
{
int nWidth;
switch (i)
{
case 0: // ID
strText.LoadString (IDS_ID);
nWidth = nTotalWidth / 8;
break;
case 1: // Description
strText.LoadString (IDS_DESCRIPTION);
nWidth = nTotalWidth / 3;
break;
case 2: // Value
strText.LoadString (IDS_VALUE);
nWidth = nTotalWidth / 6;
break;
case 3: // Item ID
strText.LoadString (IDS_ITEMID);
nWidth = nTotalWidth / 3;
break;
default:
ASSERT (FALSE);
break;
}
// Insert the column:
pList->InsertColumn (i, strText, LVCFMT_LEFT, nWidth);
}
// Enable/disable the window based on whether or not the 2.0
// functionality is available. (If m_pIItemProps interface
// pointer is NULL, we can assume functionality is not available.)
pList->EnableWindow (m_pIItemProps != NULL);
// Select the first item:
SelectItem (0);
// return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
return (CDialog::OnInitDialog ());
}
// **************************************************************************
// OnNext ()
//
// Description:
// Next button event handler.
//
// Parameters:
// none
//
// Returns:
// void
// **************************************************************************
void CKItemPropertiesDlg::OnNext ()
{
// Select the next item:
if (m_nSelIndex < m_cnItems)
SelectItem (m_nSelIndex + 1);
#ifdef _DEBUG
// Button should be disabled in this case:
else
ASSERT (FALSE);
#endif
}
// **************************************************************************
// OnPrevious ()
//
// Description:
// Previous button event handler.
//
// Parameters:
// none
//
// Returns:
// void
// **************************************************************************
void CKItemPropertiesDlg::OnPrevious ()
{
// Select the previous item:
if (m_nSelIndex > 0)
SelectItem (m_nSelIndex - 1);
#ifdef _DEBUG
// Button should be disabled in this case:
else
ASSERT (FALSE);
#endif
}
// **************************************************************************
// OnApply ()
//
// Description:
// Called to apply changes to currently selected item.
//
// Parameters:
// none
//
// Returns:
// void
// **************************************************************************
void CKItemPropertiesDlg::OnApply ()
{
// Only apply changes if Item ID control is enabled. This will be the
// case if the item is invalid to begin with:
if (GetDlgItem (IDC_ITEMID)->IsWindowEnabled ())
{
try
{
// Transfer dialog contents to member vairables:
UpdateData (true);
// Define an array OPC Item Def structures to make property change
// request:
OPCITEMDEF *pItemArray = NULL;
// Get selected item:
CKItem *pItem = GetSelectedItem ();
ASSERT (pItem);
// Update item object:
pItem->SetAccessPath (m_strAccessPath);
pItem->SetItemID (m_strItemID);
pItem->SetActive (m_bActive);
pItem->SetDataType (m_vtDataType);
// Attempt to add the item to the OPC server:
if (m_pIItemMgt)
{
// Allocate memory for item definition:
pItemArray = (OPCITEMDEF *) CoTaskMemAlloc (sizeof (OPCITEMDEF));
// If allocation succeeds, fill in definition structure:
if (pItemArray)
{
OPCITEMRESULT *pResults = NULL;
HRESULT *pErrors = NULL;
HRESULT hr;
DWORD dwLen;
// COM requires all strings be in UNICODE format. We may have
// to convert format before copying into request structure.
// First process the access path string:
dwLen = lstrlen (pItem->GetAccessPath ());
// Access path is optional. If it is not defined, i.e. it's length
// is zero, just set pointer to string to NULL:
if (dwLen)
{
// Allocate memory for the string:
pItemArray->szAccessPath = (WCHAR *) CoTaskMemAlloc ((dwLen + 1) * sizeof (WCHAR));
#ifdef _UNICODE
// This is a UNICODE build, so copy the string into allocated
// memory as is:
lstrcpyn (pItemArray->szAccessPath, pItem->GetAccessPath (), dwLen + 1);
#else
// This is an ANSI build, so convert format an copy result into
// allocated memory:
MultiByteToWideChar (CP_ACP, 0, pItem->GetAccessPath (), -1, pItemArray->szAccessPath, dwLen + 1);
#endif
}
else
pItemArray->szAccessPath = NULL;
// Next process the item ID string the same way. This string is
// required so we don't expect its length to be zero:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -