登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

面包会有的

... ...

 
 
 

日志

 
 

工控软件图形界面-控件实现(温度计控件)  

2008-03-25 14:01:50|  分类: VC++ |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

介绍

在工业控制系统开发过程中,图形显示方面占有着很重要的作用。比起很多专用的组态软件,他们有着强大的在图形系统,能够组态出来非常漂亮的系统。现在的很多的工业图形开发包都需要支付费用,很多漂亮的控件比如仪表等只能看图兴叹了。前些天一个朋友做一个泵站的监控系统,由于缺少相关的控件,在研究了该类控件的编程方法上,借鉴网络上的一些编程资料,完成了一些可用于工业控制系统开发使用的控件

正文

仪表控件,温度计控件,LED控件等是工业组态软件中最常用的人际交互控件,能够提供一种更友好的界面展示方法。而温度计控件其实综合起来就是一个水银柱绘制和一个刻度的绘制的过程。由于考虑到刷新可能对界面的产生的影响,我们采用双缓冲技术实现。

    通过VC的ClassWizard建立一个温度计显示控件类,继承CStatic。我们映射WM_PAINT消息,在这里完成温度计的各种绘制工作就可以了。这个和前面的仪表控件绘制原理是一致的。唯一的区别就是在界面展示不同的绘制效果而已。

void CThermoMeter::OnPaint()

{

    CPaintDC dc(this);

    // 获得控件区域

    GetClientRect (&m_rectCtrl);

    CMemDC memDC(&dc, &m_rectCtrl);

    //绘制仪表盘

    if (m_dcMeterPlate.GetSafeHdc() == NULL || (m_bitmapMeterPlate.m_hObject == NULL))

    {

        m_dcMeterPlate.CreateCompatibleDC(&dc);

        m_bitmapMeterPlate.CreateCompatibleBitmap(&dc, m_rectCtrl.Width(),                                                                                     m_rectCtrl.Height()) ;

        m_pbitmapOldMeterPlate = m_dcMeterPlate.SelectObject(&m_bitmapMeterPlate) ;

        DrawMeterBackground(&m_dcMeterPlate, m_rectCtrl);

    }

    memDC.BitBlt(0, 0, m_rectCtrl.Width(), m_rectCtrl.Height(),

                       &m_dcMeterPlate, 0, 0, SRCCOPY);

    DrawScale(&memDC);

    m_ctrlUnit.Draw(&memDC);

}

由于在双缓冲绘制过程中,我们的背景可以认为是不变的,所以在程序运行的数据刷新过程中,我们可以在初始化的时候在内存中间完成这部分的绘制工作,然后调用的时候将他Bitbtn到界面就可以了。刷新数据的时候每次调用以前绘制的成果BitBtn(贴)到界面上,这样就可以省掉了刷新的时候给人的闪烁的感觉了。然后完成水银柱的绘制以及实时值的绘制。界面绘制为这个控件的核心部分了。

//绘制仪表背景

void CThermoMeter::DrawMeterBackground(CDC *pDC, CRect &rect)

{

    CString strScale;

    CFont fScaleFont, *pOldFont;

    CPen penThick, penThin, penShadow, penScale, *pOldPen;

    CBrush m_brushBack, pBackBrush, *pOldBrush;

    pDC->SetBkColor(m_BackColor);

    m_brushBack.CreateSolidBrush(m_BackColor);

    pOldBrush = (CBrush *)pDC->SelectObject(&m_brushBack);    

    pDC->FillRect(rect, &m_brushBack);   //绘制背景

    pDC->SelectObject(pOldBrush);

    m_brushBack.DeleteObject();

    //绘制边框的立体效果    

    penThick.CreatePen(PS_SOLID, 1, RGB(172, 168, 153));

    penThin.CreatePen(PS_SOLID, 1, RGB(113, 111, 110));

    penShadow.CreatePen(PS_SOLID, 1, RGB(255, 255, 255));

    pOldPen = (CPen *)pDC->SelectObject(&penShadow);

    pDC->MoveTo(rect.left, rect.top);

    pDC->LineTo(rect.right - 1, rect.top);

    pDC->MoveTo(rect.left + 1, rect.top + 1);

    pDC->LineTo(rect.right - 2, rect.top + 1);

    pDC->MoveTo(rect.left, rect.top);

    pDC->LineTo(rect.left, rect.bottom - 1);

    pDC->MoveTo(rect.left + 1, rect.top + 1);

    pDC->LineTo(rect.left + 1, rect.bottom - 2);

    pDC->SelectObject(&penThick);

    pDC->MoveTo(rect.left + 1, rect.bottom - 1);

    pDC->LineTo(rect.right - 1, rect.bottom - 1);

    pDC->LineTo(rect.right - 1, rect.top + 1);

    pDC->SelectObject(&penThin);

    pDC->MoveTo(rect.left, rect.bottom);

    pDC->LineTo(rect.right, rect.bottom);

    pDC->LineTo(rect.right, rect.top);

    pDC->SelectObject(pOldPen);    

    //绘制指针显示区域

    CRect rectScale;

    rectScale.SetRect(rect.left + rect.Width() / 4,

                      rect.top + rect.Height() / 12,

                      rect.left + rect.Width() / 4 + rect.Width() / 10,

                      rect.bottom - rect.Height() / 12);

    pBackBrush.CreateSolidBrush(RGB(128, 0, 0));

    pOldBrush = (CBrush *)pDC->SelectObject(&pBackBrush);

    pDC->FillRect(&rectScale, &pBackBrush);

    pDC->SelectObject(pOldBrush);

    pBackBrush.DeleteObject();

    //绘制指针区域立体效果

    pDC->SelectObject(&penThick);

    pDC->MoveTo(rectScale.left, rectScale.bottom);

    pDC->LineTo(rectScale.left, rectScale.top);

    pDC->LineTo(rectScale.right, rectScale.top);

    pDC->SelectObject(&penThin);

    pDC->MoveTo(rectScale.left + 1, rectScale.bottom);

    pDC->LineTo(rectScale.left + 1, rectScale.top + 1);

    pDC->LineTo(rectScale.right, rectScale.top + 1);

    pDC->SelectObject(&penShadow);

    pDC->MoveTo(rectScale.right - 1, rectScale.top + 1);

    pDC->LineTo(rectScale.right - 1, rectScale.bottom - 1);

    pDC->LineTo(rectScale.left + 1, rectScale.bottom - 1);

    pDC->MoveTo(rectScale.right, rectScale.top);

    pDC->LineTo(rectScale.right, rectScale.bottom);

    pDC->LineTo(rectScale.left, rectScale.bottom);

    m_rectScale = rectScale;

    m_rectScale.DeflateRect(2, 2, 2, 2);

    //绘制刻度

    fScaleFont.CreateFont(rect.Height() / 8, 0,  

        0,  

        0,  

        FW_NORMAL,

        FALSE,

        FALSE,

        FALSE,

        DEFAULT_CHARSET,

        OUT_DEFAULT_PRECIS,

        CLIP_DEFAULT_PRECIS,

        DEFAULT_QUALITY,

        DEFAULT_PITCH | FF_DONTCARE,

        "System");  

    pOldFont = (CFont *)pDC->SelectObject(&fScaleFont);

    penScale.CreatePen(PS_SOLID, 1, RGB(0, 0, 0));

    for (int i=0; i<>

    {

        CPoint ptStartTick, ptEndTick;

        int nTickDisc = rect.Height() * 5 * i / (6 * m_nTicks);

        ptStartTick.x = rect.left + rect.Width() * 3 / 7;

        ptStartTick.y = rect.bottom - rect.Height() / 12 - nTickDisc;

        ptEndTick.x = rect.left + rect.Width() * 3 / 5;

        ptEndTick.y = rect.bottom - rect.Height() / 12 - nTickDisc;

        pDC->SelectObject(penScale);

        pDC->MoveTo(ptStartTick);

        pDC->LineTo(ptEndTick);

        //绘制立体感觉

        CPoint ptShadowStartTick, ptShadowEndTick;

        ptShadowStartTick = ptStartTick;

        ptShadowEndTick = ptEndTick;

        ptShadowStartTick.y--;

        ptShadowEndTick.y--;

        pDC->SelectObject(penShadow);

        pDC->MoveTo(ptShadowStartTick);

        pDC->LineTo(ptShadowEndTick);        

        //绘制子刻度

        for (int j=0; j<>

        {

            if (i < m_nTicks)

            {

                CPoint ptSubStartTick, ptSubEndTick;

                int nSubTickDisc = (rect.Height() * 5 / (6 * m_nTicks)) * j / m_nSubTicks;

                ptSubStartTick.x = ptStartTick.x;

                ptSubStartTick.y = ptStartTick.y - nSubTickDisc;

                ptSubEndTick.x = ptSubStartTick.x + (ptEndTick.x - ptSubStartTick.x) / 2;

                ptSubEndTick.y = ptSubStartTick.y;

                pDC->SelectObject(penScale);

                pDC->MoveTo(ptSubStartTick);

                pDC->LineTo(ptSubEndTick);

                CPoint ptShadowSubStartTick, ptShadowSubEndTick;

                ptShadowSubStartTick = ptSubStartTick;

                ptShadowSubEndTick = ptSubEndTick;

                ptShadowSubStartTick.y--;

                ptShadowSubEndTick.y--;

                pDC->SelectObject(penShadow);

                pDC->MoveTo(ptShadowSubStartTick);

                pDC->LineTo(ptShadowSubEndTick);

            }

        }

        //绘制刻度

        CRect ptScale;

        pDC->SetBkMode(TRANSPARENT);

        strScale.Format("%.0f", (m_dMaxValue - m_dMinValue) * i / m_nTicks);

        CSize size = pDC->GetTextExtent(strScale);

        pDC->SetTextColor(RGB(255, 255, 255));

        ptScale.SetRect(rect.left + rect.Width() * 2 / 3,

                        ptStartTick.y - size.cy / 2,

                        rect.right,

                        ptStartTick.y + size.cy / 2);

        pDC->DrawText(strScale, ptScale, DT_LEFT | DT_VCENTER | DT_SINGLELINE);

        pDC->SetTextColor(RGB(0, 0, 0));

        ptScale.DeflateRect(-1, -1, 1, 1);

        pDC->DrawText(strScale, ptScale, DT_LEFT | DT_VCENTER | DT_SINGLELINE);

    }

    pDC->SelectObject(pOldPen);

    pDC->SelectObject(pOldBrush);

    pDC->SelectObject(pOldFont);

    penThick.DeleteObject();

    penThin.DeleteObject();

    penShadow.DeleteObject();

    m_brushBack.DeleteObject();

    pBackBrush.DeleteObject();

    fScaleFont.DeleteObject();

    penScale.DeleteObject();

}

下面是温度计水银柱的绘制。

void CThermoMeter::DrawScale(CDC *pDC)

{

    if (m_dCurrentValue > m_dMaxValue)

    {

        m_dCurrentValue = m_dMaxValue;

    }

    else if (m_dCurrentValue < m_dMinValue)

    {

        m_dCurrentValue = m_dMinValue;

    }

    CRect rectScale;

    double yScale = (m_dCurrentValue - m_dMinValue) / (m_dMaxValue - m_dMinValue);

    rectScale.SetRect(m_rectScale.left,

                      m_rectScale.bottom - int(yScale * (m_rectScale.Height())),

                      m_rectScale.right,

                      m_rectScale.bottom);

    

    CBrush pBackBrush, *pOldBrush;

    pBackBrush.CreateSolidBrush(RGB(255, 0, 0));

    pOldBrush = (CBrush *)pDC->SelectObject(&pBackBrush);

    pDC->FillRect(&rectScale, &pBackBrush);

    pDC->SelectObject(pOldBrush);

    pBackBrush.DeleteObject();

    m_ctrlUnit.SetRect(GetUnitRect());

}

然后在工程中运用这个控件,我们就可以看到大略的效果了。如下:

其中温度计显示的标识和实时值标识这里没有显示出来,各位有兴趣可以参考我前面的仪表绘制的实现方法添加实现就可以了。

这个绘制效果比较粗糙,如果各位有好的绘制效果和改进方法欢迎与我联系:

  评论这张
 
阅读(2780)| 评论(0)

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018