⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄

📁 在中小型电力行业系统中
💻
字号:
采用HOVEREDIT的READONLY形式显示点各种信息,采用网络上面下载的DIGITAL控件进行当前值的显示。在曲线图上面移动鼠标,当前值准确显示当前点的实际值。
    以下代码在VIEW类中实现,封装工作没有进行,如果各位有兴趣封装可以发送一份代码给我。^_^
    曲线实现思路很简单,即在背景图上面进行点的绘制就可以了,我们以点的形式来描述实现情况。因为在电力系统中我们习惯将各个数据称呼为点,比如某某线路A向电流我们可以称之为点1,我们这里对该点进行定义一个结构体描述
    struct ItemMsg{
    CString szId;               
    CString szName;              //设备名称标示 
    float   fHisVal[720];         //历史记录数据,用于曲线记录 
};
定义全天显示720个点,其中720个点计算方法如下:如果我们采用每2分钟保存一个点的话,那么一天24小时计算为:2×30×24 = 720,对于要求精度比较高的地方,精度集中到几个秒记录一次的话,这里可以根据实际情况进行更改。在我这次的现场实现中720个点已经能够满足要求了,即在屏幕显示区域占用720个象素点,每个象素点描述信息为2分钟的值。如果采用1分钟一个点就需要1440个点了。由于我们常用的显示器为17‘,分辨率基本上为:1024X768,即X方向最多1024个象素点,这时的1440已经超过了1024了,所以我们需要程序代码加载方法进行曲线的扩充(比如动态加载SCROLLBAR进行曲线的扩充和收缩)。那种情况我们暂时不予考虑。^_^
    由于我这次数据库采用点组态功能,将点分为电气(各种外围厂家数据点)和模拟(PLC上来数据点)两个部分,程序开始我们需要对个点进行内容描述。因为这个描述必须与存储历史数据保持一致。
void CCurverDemoView::InitbufferVal()
{
    this->m_ItemMsg = new ItemMsg[1000];    
    CRecordset res(&db);
    CString sql;
    CDBVariant var;
    var.Clear();
    CString szId;
    int nCount = 0;
    sql.Format("Select * From Realanaquantity");
    res.Open(CRecordset::forwardOnly,sql,CRecordset::readOnly);
    while(!res.IsEOF())
    { 
        CString szName;
        res.GetFieldValue("name",var);
        szName = *var.m_pstring;
        if(szName != "undefine")
        {
            res.GetFieldValue("ID",var);
            szId = *var.m_pstring;
            m_ItemMsg[nCount].szId = szId;
            m_ItemMsg[nCount].szName = szName;
            nCount++;
        }
        res.MoveNext();
    }
    res.Close();
    ///
    sql.Format("Select * From Realelecquantity");
    res.Open(CRecordset::forwardOnly,sql,CRecordset::readOnly);
    while(!res.IsEOF())
    { 
        CString szName;
        res.GetFieldValue("name",var);
        szName = *var.m_pstring;
        if(szName != "undefine")
        {
            res.GetFieldValue("ID",var);
            szId = *var.m_pstring;
            m_ItemMsg[nCount].szId = szId;
            m_ItemMsg[nCount].szName = szName;
            nCount++;
        }
        res.MoveNext();
    }
    res.Close();
    nTolCount = nCount;
    for(int i=0;i<this->nTolCount;i++)
        for(int j=0;j<720;j++)
            this->m_ItemMsg[i].fHisVal[j] = float(GetRandom(40000,50000))/100;
}

加载背景位图
void CCurverDemoView::OnPaint() 
{
    CPaintDC dc(this); // device context for painting
    
    // TODO: Add your message handler code here
    CRect rect;
    GetClientRect(&rect); 
    HBITMAP hbitmap;
    switch(this->m_SysType)
    { 
        case CURVE:
        hbitmap=::LoadBitmap(::AfxGetInstanceHandle(),MAKEINTRESOURCE(IDB_ONTIME_CURVE)); 
        break;
    case ABOUT:
        hbitmap=::LoadBitmap(::AfxGetInstanceHandle(),MAKEINTRESOURCE(IDB_BACKBMP)); 
        break;
    default:
        hbitmap=::LoadBitmap(::AfxGetInstanceHandle(),MAKEINTRESOURCE(IDB_ONTIME_CURVE)); 
        break;
    }
    HDC hMenDC=::CreateCompatibleDC(NULL);
    SelectObject(hMenDC,hbitmap);
    ::StretchBlt(dc.m_hDC,0,0,1024,768,hMenDC,0,0,1024,768,SRCCOPY);
    ::DeleteDC(hMenDC);
    ::DeleteObject(hbitmap);

    DrawRealCurve();
    // Do not call CView::OnPaint() for painting messages
}


定义曲线绘制边界和显示区域
#define GRAPH_LEFT                109                        //曲线图位置
#define GRAPH_TOP                143-45                    //曲线图位置
#define GRAPH_RIGHT             935                        //曲线图位置
#define GRAPH_BOTTOM            625-45                    //曲线图位置
#define GRAPH_LEFT_MARGIN        69                        //曲线图左边距
#define GRAPH_RIGHT_MARGIN        37                        //曲线图右边距
#define GRAPH_TOP_MARGIN        30                        //曲线图顶边距
#define GRAPH_BOTTOM_MARGIN        30                        //曲线图底边距
绘制实时曲线:
void CCurverDemoView::DrawRealCurve()
{
    CDC *pDC = GetDC();
    CPen pNewPen,*pOldPen;
    pNewPen.CreatePen(0,1,RGB(0,255,0));
    pOldPen = pDC->SelectObject(&pNewPen);
    int    nXPoint[720],nYPoint[720];
    float fMaxNum = 0.00f;
    for(int i=0;i<720;i++)
    { 
        if(m_ItemMsg[this->nPointSize].fHisVal[i] > fMaxNum)
            fMaxNum = m_ItemMsg[this->nPointSize].fHisVal[i];
    }
    /////显示参数
    CString szMaxNum;
    CSize cSize;
    fMaxNum = fMaxNum*3/2;
    if(fMaxNum == 0) fMaxNum = 1;
    CPen pNewPen1,*pOldPen1;
    pNewPen1.CreatePen(PS_SOLID,1,RGB(255,0,0));
    pOldPen1 = (CPen *)pDC->SelectObject(&pNewPen1);
    pDC->SetBkColor(RGB(0,0,0));
    pDC->SetTextColor(RGB(255,0,0));
    szMaxNum.Format("%.2f",fMaxNum);    
    cSize = pDC->GetTextExtent(szMaxNum);
    pDC->TextOut(GRAPH_LEFT+GRAPH_LEFT_MARGIN-cSize.cx-10,GRAPH_TOP+GRAPH_TOP_MARGIN,szMaxNum);
    szMaxNum.Format("%.2f",fMaxNum*4/5);
    cSize = pDC->GetTextExtent(szMaxNum);
    pDC->TextOut(GRAPH_LEFT+GRAPH_LEFT_MARGIN-cSize.cx-10,GRAPH_TOP+GRAPH_TOP_MARGIN+90,szMaxNum);
    szMaxNum.Format("%.2f",fMaxNum*3/5);
    cSize = pDC->GetTextExtent(szMaxNum);
    pDC->TextOut(GRAPH_LEFT+GRAPH_LEFT_MARGIN-cSize.cx-10,GRAPH_TOP+GRAPH_TOP_MARGIN+180,szMaxNum);
    szMaxNum.Format("%.2f",fMaxNum*2/5);
    cSize = pDC->GetTextExtent(szMaxNum);
    pDC->TextOut(GRAPH_LEFT+GRAPH_LEFT_MARGIN-cSize.cx-10,GRAPH_TOP+GRAPH_TOP_MARGIN+270,szMaxNum);
    szMaxNum.Format("%.2f",fMaxNum/5);
    cSize = pDC->GetTextExtent(szMaxNum);
    pDC->TextOut(GRAPH_LEFT+GRAPH_LEFT_MARGIN-cSize.cx-10,GRAPH_TOP+GRAPH_TOP_MARGIN+360,szMaxNum);
    /*szMaxNum.Format("%.2f",0);
    cSize = pDC->GetTextExtent(szMaxNum);
    pDC->TextOut(GRAPH_LEFT+GRAPH_LEFT_MARGIN-cSize.cx-10,GRAPH_TOP+GRAPH_TOP_MARGIN+410,szMaxNum);
*/    pDC->SelectObject(pOldPen1);
    pNewPen1.DeleteObject();
    ////////////
    float nMinNum = float(30*14)/fMaxNum;
    for(i=0;i<720;i++) 
    {   
        nYPoint[i]=GRAPH_BOTTOM-GRAPH_BOTTOM_MARGIN-int((m_ItemMsg[this->nPointSize].fHisVal[i])*nMinNum);
        if(int((m_ItemMsg[this->nPointSize].fHisVal[i])*nMinNum) > 420)
            nYPoint[i]=GRAPH_TOP+GRAPH_TOP_MARGIN;
        if(int((m_ItemMsg[this->nPointSize].fHisVal[i])*nMinNum) == 0)
            nYPoint[i]=GRAPH_TOP+GRAPH_TOP_MARGIN+420;
        
        nXPoint[i]=GRAPH_LEFT+GRAPH_LEFT_MARGIN+i; 
        if(i==0)
            pDC->MoveTo(nXPoint[i],nYPoint[i]);
        else
            pDC->LineTo(nXPoint[i],nYPoint[i]);
    }
    pDC->SelectObject(&pOldPen);
    pNewPen.DeleteObject();
    ReleaseDC(pDC);
}

程序调用:
void CCurverDemoView::OnMsgSel() 
{ 
    CMsgSelDlg dlg;
    CString szMsg,szDate;
    if(dlg.DoModal() == IDOK)
    {
        if(ReadHisMsgFromFile(dlg.szYear,dlg.szMonth,dlg.szDay))
        {
            szMsg = dlg.szName;
            szDate = dlg.szYear+"年"+dlg.szMonth+"月"+dlg.szDay+"日";
            this->m_LineMsgEdit.SetWindowText(szMsg);
            this->m_LineDataEdit.SetWindowText(szDate);        
            for(int i = 0; i < 1000; i++)
            {
                if(m_ItemMsg[i].szId == dlg.szId)
                {
                    this->nPointSize = i;
                    break;
                }
            }            
            Invalidate();
        }
    }
}

处理鼠标移动进行动态显示数据:
void CCurverDemoView::OnMouseMove(UINT nFlags, CPoint point) 
{
    // TODO: Add your message handler code here and/or call default
    int i = point.x - (GRAPH_LEFT+GRAPH_LEFT_MARGIN);
    CString szVal;
    if(i>=0 && i < 720)
    {
        szVal.Format("%.2f",this->m_ItemMsg[this->nPointSize].fHisVal[i]); 
        this->m_EditMsg.SetText(szVal);
    }
    CView::OnMouseMove(nFlags, point);
}

/////////////
有数据的读取当然必须配合数据的定时存储,下面为数据存储方法:
void CDataSaveWnd::SaveItemVal()
{
    CString sPath,szFileName;
    CTime t = CTime::GetCurrentTime(); 
    sPath.Format("d:\\历史数据文件夹\\%.4d年%.2d月%.2d日",
        t.GetYear(),t.GetMonth(),t.GetDay()); 
    szFileName.Format(sPath+"\\Device.qigao");  
    
    //read file data
    CFile file; 
    float *pfValue=new float[this->nTolCount+1];
    for(int i = 0; i<this->nTolCount+1; i++)
    {
        if(i == 0)
            pfValue[i] = float(t.GetHour()*30+t.GetMinute()/2);
        else 
            pfValue[i] = fVal[i-1]; 
    }
    ::CreateDirectory(sPath,NULL); 
    file.Open(szFileName,CFile::modeCreate|CFile::modeReadWrite|CFile::modeNoTruncate);
    file.SeekToEnd();
    file.Write(pfValue,sizeof(float)*(this->nTolCount+1));
    file.Close();
    
    if(pfValue)
        delete pfValue;
}

void CDataSaveWnd::ReadItemVal()
{
    CRecordset res(&db);
    CString sql;
    CDBVariant var;
    var.Clear();
    CString szId;
    int nCount = 0;
    sql.Format("Select * From Realanaquantity");
    res.Open(CRecordset::forwardOnly,sql,CRecordset::readOnly);
    while(!res.IsEOF())
    { 
        CString szName;
        res.GetFieldValue("name",var);
        szName = *var.m_pstring;
        if(szName != "undefine")
        {
            res.GetFieldValue("RealValue",var);
            fVal[nCount] = (float)atof(*var.m_pstring);
            nCount++;
        }
        res.MoveNext();
    }
    res.Close();
    ///
    sql.Format("Select * From Realelecquantity");
    res.Open(CRecordset::forwardOnly,sql,CRecordset::readOnly);
    while(!res.IsEOF())
    { 
        CString szName;
        res.GetFieldValue("name",var);
        szName = *var.m_pstring;
        if(szName != "undefine")
        {
            res.GetFieldValue("RealValue",var);
            fVal[nCount] = (float)atof(*var.m_pstring);
            nCount++;
        }
        res.MoveNext();
    }
    res.Close();
    nTolCount = nCount;
}


详细方法可以见示例工程。

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -