Introduction
Graphic Display plays an important role in the development of industrial control systems. Compared with many dedicated configuration software, they have powerful graphics systems that can be configured with very beautiful systems. Today, many industrial graphics Development kits have to be paid, and many beautiful controls, such as instruments, can only look at the figure and sigh. A friend of mine made a monitoring system for a pumping station a few days ago. Due to the lack of related controls, he studied the programming methods of these controls and used some programming materials on the network for reference, completed some controls that can be used for industrial control system development.
Body
Many of the current domestic industrial configuration software uses configuration software, such as Kingview, iFIX, and tuwang. Many vendors also provide control Development kits, such as the control development kit of the century flying sky and the graphic king. Many configuration systems belong to the Project Authorization Form and are separately authorized for each project. In the process of system implementation in small and medium-sized enterprises, this is not a small pressure, so many companies write their own Configuration Software suitable for their own products. In the preparation of industrial control software systems, related controls are essential. For example, the use of meter simulation can more realistically reflect the current situation than the direct digital display.
Currently, the commonly used method for writing such controls on the network is to use dual-buffer technology. The principle of double buffering can be understood as follows: the computer screen is regarded as a blackboard. First, we create a "virtual" blackboard in the memory environment, and then draw complex graphics on this blackboard. When all the graphics are finished, copy the image drawn in the memory to another blackboard (screen) at one time. This method can increase the drawing speed and greatly improve the drawing effect.
Here we create a new class cdiscmeter to integrate cstatic, map the wm_paint message, and then draw the image in the middle of onpaint.
Void cdiscmeter: onpaint ()
{
Cpaintdc DC (this); // device context for painting
// Obtain the control area
Getclientrect (& m_rectctrl );
Cdiscmemdc memdc (& DC, & m_rectctrl );
// Draw a dashboard
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 );
Drawneedle (& memdc );
Drawvalue (& memdc );
}
Since our background does not change in real time, we plot the background for the first time, in the future, the bitbtn method of CDC will be called each time invalidate is called to re-paint the background.
In the rendering backgroundProgramBased on calculation methods such as radians, We dynamically calculate the location of the background of the instrument, and then call a series of methods of the CDC object to draw the image.
// Draw the gauge background
Void cdiscmeter: drawmeterbackground (CDC * PDC, crect & rect)
{
Cpen m_penmeter, * poldpen;
Cbrush m_brushback, * poldbrush;
PDC-> setbkcolor (m_backcolor );
M_brushback.createsolidbrush (m_backcolor );
Poldbrush = (cbrush *) PDC-> SelectObject (& m_brushback );
PDC-> fillrect (rect, & m_brushback); // draw the background
PDC-> rectangle (rect); // draw a border
PDC-> SelectObject (poldbrush );
M_brushback.deleteobject ();
M_penmeter.createpen (ps_solid, 2, RGB (0, 0, 0 ));
Poldpen = (cpen *) PDC-> SelectObject (& m_penmeter );
PDC-> settextcolor (RGB (0, 0, 0 ));
PDC-> setbkmode (transparent );
int ntmplong = _ min (rect. width (), rect. height ();
m_ptmetercenter.x = ntmplong/2; // point center X coordinate
m_ptmetercenter.y = ntmplong/2; // y coordinate of the Point center
m_nradiusframe = ntmplong/2-3;
// Draw the instrument Disc
Crect rectround (m_ptmetercenter.x-m_nradiusframe,
M_ptmetercenter.y + m_nradiusframe,
M_ptmetercenter.x + m_nradiusframe,
M_ptmetercenter.y-m_nradiusframe );
PDC-> ellipse (rectround );
// Draw the Inner Frame of the current value
Cpen pinnerframepen, * poldinnerframepen;
Pinnerframepen. createpen (ps_solid, 1, RGB (0, 0, 0 ));
Poldinnerframepen = (cpen *) PDC-> SelectObject (& pinnerframepen );
Crect rectinnerframe (m_ptmetercenter.x-m_nradiusframe * 9/20,
M_ptmetercenter.y + m_nradiusframe * 6/10,
M_ptmetercenter.x-m_nradiusframe * 9/20 + m_nradiusframe * 9/10,
M_ptmetercenter.y + m_nradiusframe * 6/10 + m_nradiusframe * 5/20 );
M_rectinnerframe = rectinnerframe;
PDC-> fillsolidrect (rectinnerframe, RGB (230,232,232 ));
Drawrectangle (PDC, rectinnerframe, RGB (0, 0, 0 ));
Rectinnerframe. Left ++;
Rectinnerframe. Top ++;
Rectinnerframe. Bottom --;
Rectinnerframe. Right --;
Drawrectangle (PDC, rectinnerframe, RGB (255,255,255 ));
PDC-> SelectObject (poldinnerframepen );
Pinnerframepen. deleteobject ();
// Draw the arc of the outer ring
Int ntmpradius = m_nradiusframe-4;
Cpoint ptboundary, ptstart, ptend;
Ptboundary. x = int (sin (PI/3) * ntmpradius );
Ptboundary. Y = int (COS (PI/3) * ntmpradius );
Ptstart. x = m_ptmetercenter.x + ptboundary. X;
Ptstart. Y = m_ptmetercenter.y + ptboundary. Y;
Ptend. x = m_ptmetercenter.x-ptboundary. X;
Ptend. Y = m_ptmetercenter.y + ptboundary. Y;
Crect arcangle (m_ptmetercenter.x-ntmpradius,
M_ptmetercenter.y-ntmpradius,
M_ptmetercenter.x + ntmpradius,
M_ptmetercenter.y + ntmpradius );
PDC-> arc (& arcangle, ptstart, ptend );
// Draw the scale
Int nticks = m_nticks;
Int nsubticks = m_nsubticks;
Char strfigure [maxnamelength + 1];
Const int nsidepos = 40;
Memset (strfigure, 0, sizeof (strfigure ));
Double dmaxangle = double (240.00f/nticks); // The angle of each big Grid
Double dminanble = dmaxangle/nsubticks; // angle of each cell
For (INT I = 0; I {
Cpoint ptstarttick, ptendtick;
Ptstarttick. x = int (m_ptmetercenter.x + (m_nradiusframe *
Cos (dmaxangle * (nticks-I)-30) * PI/180.00f )));
Ptstarttick. Y = int (m_ptmetercenter.y-(m_nradiusframe *
Sin (dmaxangle * (nticks-I)-30) * PI/180.00f )));
Ptendtick. x = int (m_ptmetercenter.x + (m_nradiusframe-10 )*
Cos (dmaxangle * (nticks-I)-30) * PI/180.00f )));
Ptendtick. Y = int (m_ptmetercenter.y-(m_nradiusframe-10 )*
Sin (dmaxangle * (nticks-I)-30) * PI/180.00f )));
PDC-> moveTo (ptstarttick );
PDC-> lineto (ptendtick );
Sprintf (strfigure, "%. 1f", (m_dmaxvalue-m_dminvalue) * I/nticks );
If (dmaxangle * (nticks-I)-30 <60)
{
PDC-> textout (ptendtick. X-nsidepos, ptendtick. Y, strfigure );
}
Else if (dmaxangle * (nticks-I)-30 <= 90)
{
PDC-> textout (ptendtick. X-nsidepos/2, ptendtick. Y + 3, strfigure );
}
Else if (dmaxangle * (nticks-I)-30 <140)
{
PDC-> textout (ptendtick. X-nsidepos/3, ptendtick. Y, strfigure );
}
Else
{
PDC-> textout (ptendtick. X-nsidepos/10, ptendtick. Y, strfigure );
}
}
For (I = 0; I {
Cpoint ptsubstarttick, ptsubendtick;
Ptsubstarttick. x = int (m_ptmetercenter.x + (m_nradiusframe *
Cos (dminanble * (nticks * nsubticks-I)-30) * PI/180.00f )));
Ptsubstarttick. Y = int (m_ptmetercenter.y-(m_nradiusframe *
Sin (dminanble * (nticks * nsubticks-I)-30) * PI/180.00f )));
Ptsubendtick. x = int (m_ptmetercenter.x + (m_nradiusframe-6 )*
Cos (dminanble * (nticks * nsubticks-I)-30) * PI/180.00f )));
Ptsubendtick. Y = int (m_ptmetercenter.y-(m_nradiusframe-6 )*
Sin (dminanble * (nticks * nsubticks-I)-30) * PI/180.00f )));
PDC-> moveTo (ptsubstarttick );
PDC-> lineto (ptsubendtick );
}
// Initialize the text format
Cfont punitfont, * poldfont;
Logfont lf;
Lf. lfescapement = 0;
Lf. lfitalic = NULL;
Lf. lfunderline = NULL;
Lf. lfstrikeout = NULL;
Lf. lfcharset = default_charset;
Lf. lfheight = m_nradiusframe/5;
Strcpy (LF. lffacename, "impact ");
Punitfont. createfontindirect (& lf );
Poldfont = (cfont *) PDC-> SelectObject (& punitfont );
Crect rectunits (INT (m_ptmetercenter.x-m_nradiusframe * 0.18f ),
INT (m_ptmetercenter.y + m_nradiusframe * 0.25f ),
INT (m_ptmetercenter.x-m_nradiusframe * 0.18f + m_nradiusframe * 0.4f ),
INT (m_ptmetercenter.y + m_nradiusframe * 0.25f + m_nradiusframe * 6/20 ));
PDC-> drawtext (m_strunits, & rectunits, dt_center | dt_singleline | dt_vcenter );
PDC-> SelectObject (poldfont );
Punitfont. deleteobject ();
PDC-> SelectObject (poldpen );
M_penmeter.deleteobject ();
}
The invalidate method of the cstatic class is called to trigger the wm_paint message when the control displays data. After the background is drawn, We need to display the pointer and actual value of the control, the control is complete.
// Draw the meter pointer
Void cdiscmeter: drawneedle (CDC * PDC)
{
Cbrush pcenterbrush, * poldbrush;
If (m_dcurrentvalue <m_dminvalue)
{
M_dcurrentvalue = m_dminvalue;
}
Else if (m_dcurrentvalue> m_dmaxvalue)
{
M_dcurrentvalue = m_dmaxvalue;
}
Double dangle = double (240.00f * (m_dcurrentvalue-m_dminvalue )/
(M_dmaxvalue-m_dminvalue )));
Int ntmpradius1 = int (m_nradiusframe/1.4f );
Int ntmpradius2 = m_nradiusframe/6;
Crgn prgn;
Point ptangle [3];
Ptangle [0]. x = long (m_ptmetercenter.x + ntmpradius2 *
Cos (210-dangle-90) * PI/180.00f ));
Ptangle [0]. Y = long (m_ptmetercenter.y-ntmpradius2 *
Sin (210-dangle-90) * PI/180.00f ));
Ptangle [1]. x = long (m_ptmetercenter.x + ntmpradius2 *
Cos (210-dangle + 90) * PI/180.00f ));
Ptangle [1]. Y = long (m_ptmetercenter.y-ntmpradius2 *
Sin (210-dangle + 90) * PI/180.00f ));
Ptangle [2]. x = long (m_ptmetercenter.x + ntmpradius1 *
Cos (210-dangle) * PI/180.00f ));
Ptangle [2]. Y = long (m_ptmetercenter.y-ntmpradius1 *
Sin (210-dangle) * PI/180.00f ));
Prgn. createpolygonrgn (ptangle, 3, alternate );
PDC-> fillrgn (& prgn, & cbrush (RGB (0, 0, 0 )));
pcenterbrush. createsolidbrush (RGB (255, 0, 0);
poldbrush = (cbrush *) PDC-> SelectObject (& pcenterbrush);
crect rectcenter (m_ptmetercenter.x-ntmpradius2,
m_ptmetercenter.y-ntmpradius2,
m_ptmetercenter.x + ntmpradius2,
latency + ntmpradius2);
PDC-> ellipse (rectcenter );
PDC-> SelectObject (poldbrush);
pcenterbrush. deleteobject ();
}
// Plot the real-time value of the instrument
Void cdiscmeter: drawvalue (CDC * PDC)
{
Char strcurrentvalue [10];
Memset (strcurrentvalue, 0, sizeof (strcurrentvalue ));
Sprintf (strcurrentvalue, "%. 2f", m_dcurrentvalue );
cfont punitfont, * poldfont;
logfont lf;
lf. lfescapement = 0;
lf. lfitalic = NULL;
lf. lfunderline = NULL;
lf. lfstrikeout = NULL;
lf. lfcharset = default_charset;
lf. lfheight = m_nradiusframe/6;
strcpy (LF. lffacename, "Arial");
punitfont. createfontindirect (& lf);
poldfont = (cfont *) PDC-> SelectObject (& punitfont);
PDC-> setbkmode (transparent );
PDC-> drawtext (strcurrentvalue, m_rectinnerframe, dt_center | dt_singleline | dt_vcenter);
PDC-> SelectObject (poldfont);
punitfont. deleteobject ();
}