 |
|
 |
I want to add the Print facility to this control like some graph controls has.
Could you tell me how can i do this?
Any suggestion and direction?
Thanks in advance
|
|
|
|
 |
|
 |
Nice work, keep up the good work Mark!
--Arun
|
|
|
|
 |
|
 |
I have modified the class to have units after the value and a name to the meter:
3DMeterCtrl.h:
public:
...
CString m_strName ;
public:
...
void SetName(CString &strName) ;
3DMeterCtrl.cpp:
C3DMeterCtrl::C3DMeterCtrl()
{
...
m_strUnits.Format("V") ;
m_strName.Format("Volts") ;
...
}
void C3DMeterCtrl::DrawValue(CDC *pDC)
{
...
strTemp.Format("%.*f %s", m_nValueDecimals, m_dCurrentValue, m_strUnits) ;
...
}
void C3DMeterCtrl::DrawMeterBackground(CDC *pDC, CRect &rect)
{
...
// draw the units below the meter face
pDC->SetTextAlign(TA_CENTER|TA_BASELINE) ;
pDC->TextOut(m_nValueCenter, m_rectValue.top - m_nValueFontHeight/4, m_strName) ;
...
}
void C3DMeterCtrl::SetName(CString &strName)
{
m_strName = strName ;
ReconstructControl() ;
}
|
|
|
|
 |
|
 |
Sometimes when my application shuts down the analog meter generates a GPF in it's destructor.
m_dcBackground.SelectObject(m_pBitmapOldBackground);
The control is placed in a CFormView.
How can this be fixed?
Michel Wassink
We must make user friendly software. Where are friendly users?
|
|
|
|
 |
|
 |
With the SetUnits() function it is not possible to pass a literal string.
Better change
void SetUnits(CString &strUnits);
to
void SetUnits(LPCTSTR lpszUnits);
Then it is possible to write SetUnits(_T("mm"));.
A CString can then still be passed
regards,
Michel Wassink
We must make user friendly software. Where are friendly users?
|
|
|
|
 |
|
 |
This is the "cat's meow". But, I have an application where I need to I need to set some external hardware, wait 2 seconds (Sleep(2000);) then read the hardware and pass the value along to the Analog Meter updateneedle function. My single function sets up and reads 4 different hardwares but the value that is shown on the meter is only the last one. I am using a OnTimer function as show in the example but I think the Sleep(2000) is causing it not to update the needle "on the fly"
It would be better, I think, to get ride of the timer event and put the update needle call right in the same functiont that selects and reads the hardware. But, that does the same thing.
Does anyone have any idea as to how to update the needle on the fly for multiple readings inside one "button click" function?
Thanks
CG
|
|
|
|
 |
|
 |
Thanks for the kind words.
Perhaps one of you "experts" out there can help on this as I think it's a Windows message queue problem. The meter's "UpdateNeedle" function calls an "Invalidate" inside the control - forcing a re-paint.
It seems as though Clav's problem is that Windows gets busy and doesn't get around to repainting. Perhaps the call to Sleep(2000) also stops Windows from dealing with messages.
One thought would be to modify the UpdateNeedle function to perhaps call "OnPaint" directly, but I'm not sure of there are any ramifications.
Ideas?
- Mark
|
|
|
|
 |
|
 |
I fixed it my using a pointer to the voltmeter window as shown. It works great
void CAPM_ScreenDlg::OnDebugButton()
{
CWnd* pDISPLAY_Wnd = GetDlgItem(IDC_VOLTMETER);
for(float x=0; x<6; x+=.5)
{
m_VoltMeter.UpdateNeedle(x);
pDISPLAY_Wnd->UpdateWindow(); <---this is what allows me to update on the fly
Sleep(2000); without a timer
}
for(x=5; x>=0; x-=.5)
{
m_VoltMeter.UpdateNeedle(x);
pDISPLAY_Wnd->UpdateWindow();
Sleep(2000);
}
}
|
|
|
|
 |
|
 |
Hi Mark,
Nice control!
I accidently found out that it gives floating point error when min and max value are the same.
// calculate the angle for the tip of the needle
dAngleRad = (m_dCurrentValue-m_dMinValue)*(m_dRightAngleRad-m_dLeftAngleRad)/
(m_dMaxValue-m_dMinValue) + m_dLeftAngleRad ;
A division by zero occurs then. You better add a check before it.
regards,
Michel Wassink
We must make user friendly software. Where are friendly users?
|
|
|
|
 |
|
 |
Oops! Nice catch - you are right!!! In my own defense, I check Max vs. Min elsewhere in the code when I use the control. But, nonetheless, this control should be changed in order to make it more robust.
|
|
|
|
 |
|
 |
This is a wonderful bit of code. Amazing.
A few questions:
Any idea how one would go about getting rid of the black line that surrounds the picture?
How could one increase the font size without throwing off the proportions of the meter?
Thanks for your help.
Your program is incredible!
Phillip Anderson
|
|
|
|
 |
|
 |
Thanks for the kind words. The black line is set in the resource editor (look at one of the tabs when you are setting up the static picture control that will eventually hold the meter). The font is set based on the size of the rectangle that the meter is drawn in. You can dig around in the code and find the font stuff.
Thanks again,
- Mark
|
|
|
|
 |
|
 |
hie,
can any one tell me the required steps to add this to a dialog box?
|
|
|
|
 |
|
 |
Would it be possible to put in a red line/section for peak indication?
Like on an audio meter or an RPM gauge of a car?
The idea would to allow a setting of this value from the control.
Just a thought,
alan
|
|
|
|
 |
|
 |
That would be a really cool feature... unfortunately I'm working on some other things and don't have a chance to do it in the near future.
Great idea, nonetheless. Perhaps somebody else would like to go into the source and do this.
- Mark
|
|
|
|
 |
|
 |
About the peak indication: I used this gauge to display tire pressure, so I needed both low and high pressure regions. It also displays messages and warnings on the bottom, like the recommended pressure etc. I don't know how to paste the all different code files, but basically what I did was: In C3DMeterCtrl::DrawMeterBackground, create a new thick red pen, with flat ends: <code> penRed.CreatePen(PS_SOLID | PS_GEOMETRIC | PS_ENDCAP_FLAT , 12, &logBrush, 0, NULL); </code> than calculate the vertices of the new line (internal arch) based on the original calculations of the border polygon (done in the same loops): <code> dTemp = m_nBottomCX + m_nTopRadius*cos(dAngleRad)*0.968 ; m_pointDanger[nRef].x = ROUND(dTemp) ; dTemp = m_nBottomCY - m_nTopRadius*sin(dAngleRad)*0.968 ; m_pointDanger[nRef].y = ROUND(dTemp) ;</code> (you have to do it on both sides, like in the original code) than comes the tricky part of deciding which points to use (there is probably a neater way to do this), to create the 2 arches: <code> //start at the right corner pDC->MoveTo(m_pointDanger[0]) ; for (int index = 0; index < 26; index++) { if((m_pointBoundary[index].y < (m_nBottomCY - m_nTopRadius*cos(30*dRadPerDeg))) &&(m_pointBoundary[index].x > (m_nBottomCX + m_nTopRadius*sin((m_dMaxPressure/(m_dMaxValue-m_dMinValue)*60-30)*dRadPerDeg)))){ pDC->LineTo(m_pointDanger[index]) ; }; } //start at the left corner pDC->MoveTo(m_pointDanger[12]) ; for (index = 11; index > 0; index--) { if((m_pointBoundary[index].y < (m_nBottomCY - m_nTopRadius*cos(30*dRadPerDeg))) &&(m_pointBoundary[index].x < (m_nBottomCX - m_nTopRadius*sin((30-m_dMinPressure/(m_dMaxValue-m_dMinValue)*60)*dRadPerDeg))) && (m_pointBoundary[index-1].x > m_pointBoundary[index].x )){ pDC->LineTo(m_pointDanger[index]) ; }; }</code> do the above before the drawing of the tick marks, so they would apeare above the red stripe. then add the commands in the menu to set the min and max level for the safe region: <code> void CMeterTestFormView::OnMeterMinPressure() { double dTemp ; CDlgString dlg ; dlg.m_strEdit.Format("%.*f", m_3DMeter.m_nScaleDecimals, m_3DMeter.m_dMinPressure) ; dlg.m_strPrompt.Format("Enter the min pressure.") ; if (dlg.DoModal() == IDOK) { dTemp = atof(dlg.m_strEdit) ; m_3DMeter.SetPressureRange(dTemp, m_3DMeter.m_dMaxPressure) ; } }</code> I would post a screen capture if I knew how. Thanks a lot to the author of the article and code, it really made my life easier since my field is more about electronics than C++ coding. I hope it helps, Boaz Avta
|
|
|
|
 |
|
 |
Hi,
can you send me the source code by email?
Thank you very much
Dieter
...
|
|
|
|
 |
|
 |
I can't see what you tap on the control to make sure the needle isn't stuck.
.... whistles innocently ....
Tim Smith
I'm going to patent thought. I have yet to see any prior art.
|
|
|
|
 |
|
 |
LOL!
|
|
|
|
 |
|
 |
I was able to easily integrate this into one of my tools! Integration was seamless and functionality was well thought out!!
I also added support for a second needle that marks the max value until it is reset.
|
|
|
|
 |
|
 |
Thank you very much.
- Mark
|
|
|
|
 |
|
 |
Nice job Mark - I only wish there were more controls like these. I'm only a newbie to VC++ MFC and still only using dialogs, so this was of great use as I wanted data to be quickly interpreted by a user.
One very small point, MemDC.h has to be included too (I don't think this is mentioned on this site) and SetDecimals has become SetValueDecimals.
Thanks for sharing your hard work
Lea
|
|
|
|
 |
|
 |
Hi fellows,
I you want to insert this control directly as a child of your frame window, insert the following initialization:
C3DMeterCtrl::C3DMeterCtrl()
{
m_dCurrentValue = 0.0 ;
m_dMaxValue = 5.0 ;
m_dMinValue = -5.0 ;
m_nScaleDecimals = 1 ;
m_nValueDecimals = 3 ;
m_strUnits.Format("Volts") ;
m_pBitmapOldBackground=NULL; //<-- Here
m_colorNeedle = RGB(255, 0, 0) ;
}
|
|
|
|
 |
|
|
 |
 | Nice  |  | Jimbob | 14:34 15 Jan '02 |
|
 |
Very very good.
Making a guitar tuner so I needed an analog gauge.
Just one problem, it is much more, but really much more CPU intensive than the "cheaper" non-3D version. If I optimize it, I'll post that
Jimbob
|
|
|
|
 |