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

介绍

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

正文

仪表控件,温度计控件,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());

}

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

1911.jpg

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

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
WPF工控软件自定义控件是指在基于.NET6框架下使用WPF MVVM进行UI设计时,开发者可以自定义控件来满足特定的功能需求。这些自定义控件可以根据项目的需求进行设计和修改,以提供更好的用户体验和功能支持。 如果你对WPF工控软件自定义控件感兴趣,我建议你可以下载并编译相关的示例代码,并尝试修改它们以适应你的项目需求。你可以在这个链接上找到相关界面的示例代码:https://blog.csdn.net/u010186391/article/details/125601226。通过实际操作和修改示例代码,你可以更好地理解和应用WPF自定义控件、样式、MVVM和异步线程等方面的知识。<span class="em">1</span><span class="em">2</span> #### 引用[.reference_title] - *1* [NET6+WPF+MVVM ](https://download.csdn.net/download/u010186391/85926327)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [C# WPF 自定义控件 滑块控件 开关控件 ToggleButton Switcher](https://blog.csdn.net/shizu11zz/article/details/120459009)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值