judico
asked on
How can data resulting from checksum exceptions in VC++ /NET be ignored
Occasionally, when communicating with an external device the incoming data is corrupted and a checksum exception occurs. I'd like to ignore such data. What is the best way to do that?
When checksum error occurs, set the data value to a well-known value outside the normal range and then ignore all data with that well-known value.
ASKER
drichards,
I tried to do all you advise me to do in:
https://www.experts-exchange.com/questions/21092168/Passing-of-values-between-functions.html
1) In MultiMeter.cpp I replaced return 0.0; with
return System::Double::MaxValue;
2) in temperature.h I placed if-else selection statement in the OnTimeEvent function:
private:
void OnTimedEvent(Object* source, System::Timers::ElapsedEve ntArgs* e)
{
try
{
BYTE *pBuf = NULL;
dMeterReading = mmeter->ReadData();
if ( dMeterReading == System::Double::MaxValue)
;
else
evtCounter += 1;
yVALUE[ evtCounter ] = dMeterReading;
Invalidate();
textBox2->Text = System::Convert::ToString( dMeterRead ing);
xVALUE[ evtCounter ] = evtCounter;
textBox1->Text = System::Convert::ToString( evtCounter ,10);
// Restart timer
aTimer->Start();
}
catch (System::Exception *ex)
{
System::Console::WriteLine (ex->Messa ge);
}
}
but these changes still don’t ignore the faulty data from being plotted. Maybe there is something more I should do because I don’t understand very well all points in your instruction:
1) Set dMeterReading to System::Double::MaxValue on error and check this value on return
2) Set an error flag in multimeter and read it after getting dMeterReading
3) Add a pointer parameter to the read function and pass a pointer to a value that will accept an error code
4) Have the read function return error status and pass dMeterReading to the read function as a pointer.
I tried to do all you advise me to do in:
https://www.experts-exchange.com/questions/21092168/Passing-of-values-between-functions.html
1) In MultiMeter.cpp I replaced return 0.0; with
return System::Double::MaxValue;
2) in temperature.h I placed if-else selection statement in the OnTimeEvent function:
private:
void OnTimedEvent(Object* source, System::Timers::ElapsedEve
{
try
{
BYTE *pBuf = NULL;
dMeterReading = mmeter->ReadData();
if ( dMeterReading == System::Double::MaxValue)
;
else
evtCounter += 1;
yVALUE[ evtCounter ] = dMeterReading;
Invalidate();
textBox2->Text = System::Convert::ToString(
xVALUE[ evtCounter ] = evtCounter;
textBox1->Text = System::Convert::ToString(
// Restart timer
aTimer->Start();
}
catch (System::Exception *ex)
{
System::Console::WriteLine
}
}
but these changes still don’t ignore the faulty data from being plotted. Maybe there is something more I should do because I don’t understand very well all points in your instruction:
1) Set dMeterReading to System::Double::MaxValue on error and check this value on return
2) Set an error flag in multimeter and read it after getting dMeterReading
3) Add a pointer parameter to the read function and pass a pointer to a value that will accept an error code
4) Have the read function return error status and pass dMeterReading to the read function as a pointer.
ASKER
I applied a palliative solution. Just avoing plotting a point that's zero:
for (int iii = 1; iii <= 500; iii++)
{
if ( yVALUE[ iii ] == 0)
;
else
graphicsObject->DrawEllips e( pen, xVALUE[ iii ], yVALUE[ iii] * 10, 7, 7 );
}
for (int iii = 1; iii <= 500; iii++)
{
if ( yVALUE[ iii ] == 0)
;
else
graphicsObject->DrawEllips
}
Like this:
private:
void OnTimedEvent(Object* source, System::Timers::ElapsedEve ntArgs* e)
{
try
{
BYTE *pBuf = NULL;
dMeterReading = mmeter->ReadData();
if ( dMeterReading == System::Double::MaxValue) {}
else
{
evtCounter += 1;
yVALUE[ evtCounter ] = dMeterReading;
Invalidate();
textBox2->Text = System::Convert::ToString( dMeterRead ing);
xVALUE[ evtCounter ] = evtCounter;
textBox1->Text = System::Convert::ToString( evtCounter ,10);
}
// Restart timer
aTimer->Start();
}
catch (System::Exception *ex)
{
System::Console::WriteLine (ex->Messa ge);
}
}
private:
void OnTimedEvent(Object* source, System::Timers::ElapsedEve
{
try
{
BYTE *pBuf = NULL;
dMeterReading = mmeter->ReadData();
if ( dMeterReading == System::Double::MaxValue) {}
else
{
evtCounter += 1;
yVALUE[ evtCounter ] = dMeterReading;
Invalidate();
textBox2->Text = System::Convert::ToString(
xVALUE[ evtCounter ] = evtCounter;
textBox1->Text = System::Convert::ToString(
}
// Restart timer
aTimer->Start();
}
catch (System::Exception *ex)
{
System::Console::WriteLine
}
}
Initially when the window paints it will paint before the initial value has even been read. The value will be 0 at that time. You should probably initialize evtCounter to -1 in the constructor and don't plot if evtCounter < 0. That way you won't plot anything until you've read a data point. Also, as your code sits (will be OK with initial evtCounter value of -1) you increment evtCounter BEFORE loading the values into the arrays, so you are skipping the 0 index of the array. You never load a value into the 0 index.
void OnPaint( PaintEventArgs *paintEvent )
{
if ( evtCounter >= 0 )
{
// call base OnPaint method
__super::OnPaint( paintEvent );
// get graphics object
Graphics *graphicsObject = paintEvent->Graphics;
SolidBrush *brush = new SolidBrush( Color::Blue );
Pen *pen = new Pen( Color::Black );
for ( int ii = 0; ii <= evtCOunter; ii++)
{
graphicsObject->DrawEllips e( pen,xVALUE[ii], yValue[ii] * 10, 7, 7 );
}
}
}
Also, in previous post, you should check if evtCounter is 500 (your array size, I assume) and reset it to 0 so you don't do off the array.
void OnPaint( PaintEventArgs *paintEvent )
{
if ( evtCounter >= 0 )
{
// call base OnPaint method
__super::OnPaint( paintEvent );
// get graphics object
Graphics *graphicsObject = paintEvent->Graphics;
SolidBrush *brush = new SolidBrush( Color::Blue );
Pen *pen = new Pen( Color::Black );
for ( int ii = 0; ii <= evtCOunter; ii++)
{
graphicsObject->DrawEllips
}
}
}
Also, in previous post, you should check if evtCounter is 500 (your array size, I assume) and reset it to 0 so you don't do off the array.
ASKER
Still plots the zero point. After your advice I placed evtCounter = -1 in the constructor:
temperature(void)
{
InitializeComponent();
evtCounter = -1;
}
and then placed an if-else selection statement where the plotting occurs
if (evtCounter < 0 ) {}
else
{
graphicsObject->DrawEllips e( pen, xVALUE[ iii ], yVALUE[ iii] * 10, 7, 7 );
}
bit, as I said, this doesn't remove the zero point.
temperature(void)
{
InitializeComponent();
evtCounter = -1;
}
and then placed an if-else selection statement where the plotting occurs
if (evtCounter < 0 ) {}
else
{
graphicsObject->DrawEllips
}
bit, as I said, this doesn't remove the zero point.
ASKER
See, it works with the palliative solution I mentioned before but I prefer it to work the way you explained it, with the flag.
If you're still looping from 0 to 499, you're going to get lots of zeros because the data is not yet filled in.
Also, if there are 0 values in positions less than evtCounter, do they come from the data read from the meter? Check the return value for debug purposes. Before checking if dMeterReading is MaxValue, check if it's 0. If you see the dialog box, you know that the meter reading was 0. If the zeros are coming from somewhere else, it's because you are not manipulating the array correctly.
Test code to see if meter reads 0:
private:
void OnTimedEvent(Object* source, System::Timers::ElapsedEve ntArgs* e)
{
try
{
BYTE *pBuf = NULL;
dMeterReading = mmeter->ReadData();
// Code for debugging
if ( dMeterreading == 0 ) System::Windows::Forms::Me ssageBox(S "dMeterRea ding is 0!");
if ( dMeterReading == System::Double::MaxValue) {}
else
{
evtCounter += 1;
yVALUE[ evtCounter ] = dMeterReading;
Invalidate();
textBox2->Text = System::Convert::ToString( dMeterRead ing);
xVALUE[ evtCounter ] = evtCounter;
textBox1->Text = System::Convert::ToString( evtCounter ,10);
}
// Restart timer
aTimer->Start();
}
catch (System::Exception *ex)
{
System::Console::WriteLine (ex->Messa ge);
}
}
Also, if there are 0 values in positions less than evtCounter, do they come from the data read from the meter? Check the return value for debug purposes. Before checking if dMeterReading is MaxValue, check if it's 0. If you see the dialog box, you know that the meter reading was 0. If the zeros are coming from somewhere else, it's because you are not manipulating the array correctly.
Test code to see if meter reads 0:
private:
void OnTimedEvent(Object* source, System::Timers::ElapsedEve
{
try
{
BYTE *pBuf = NULL;
dMeterReading = mmeter->ReadData();
// Code for debugging
if ( dMeterreading == 0 ) System::Windows::Forms::Me
if ( dMeterReading == System::Double::MaxValue) {}
else
{
evtCounter += 1;
yVALUE[ evtCounter ] = dMeterReading;
Invalidate();
textBox2->Text = System::Convert::ToString(
xVALUE[ evtCounter ] = evtCounter;
textBox1->Text = System::Convert::ToString(
}
// Restart timer
aTimer->Start();
}
catch (System::Exception *ex)
{
System::Console::WriteLine
}
}
ASKER
For some reason
if ( dMeterReading == 0 ) System::Windows::Forms::Me ssageBox(S "dMeterRea ding is 0!");
gives the error
temperature.h(154): error C2440: 'type cast' : cannot convert from 'System::String __gc *' to 'System::Windows::Forms::M essageBox'
and I can't do the debuggigng.
if ( dMeterReading == 0 ) System::Windows::Forms::Me
gives the error
temperature.h(154): error C2440: 'type cast' : cannot convert from 'System::String __gc *' to 'System::Windows::Forms::M
and I can't do the debuggigng.
ASKER
OK, it should be
if ( dMeterReading == 0 ) System::Windows::Forms::Me ssageBox:: Show(S"dMe terReading is 0!");
if ( dMeterReading == 0 ) System::Windows::Forms::Me
ASKER
No, the debugging shows that the zero value isn't coming from the multimeter and is due to what you already suggested -- the first time the form paints it paints with zero values because the program hasn't yet called the multimeter. The flag -1 should be put before that first painting. I tried placing it in temperature.cpp:
System::Threading::Thread: :CurrentTh read->Apar tmentState = System::Threading::Apartme ntState::S TA;
evtCounter = -1;
Application::Run(new temperature());
return 0;
declaring static int evtCounter; at the head of temperature.h but it didnt help as well.
System::Threading::Thread:
evtCounter = -1;
Application::Run(new temperature());
return 0;
declaring static int evtCounter; at the head of temperature.h but it didnt help as well.
It's probably because you have this code which resets evtCOnter to 0 after the program starts.:
private: System::Void timer1_Tick(System::Object * sender, System::EventArgs * e)
{
if ( mmeter == NULL )
{
timer1->Stop();
mmeter = new MultiMeter;
mmeter->ConfigureSerialInt erface();
aTimer = new System::Timers::Timer(500) ;
aTimer->Elapsed+=new System::Timers::ElapsedEve ntHandler( this, OnTimedEvent);
// Only raise the event the first time Interval elapses.
aTimer->AutoReset = false;
aTimer->Enabled = true;
evtCounter = 0; // <----------------Problem here
}
}
};
private: System::Void timer1_Tick(System::Object
{
if ( mmeter == NULL )
{
timer1->Stop();
mmeter = new MultiMeter;
mmeter->ConfigureSerialInt
aTimer = new System::Timers::Timer(500)
aTimer->Elapsed+=new System::Timers::ElapsedEve
// Only raise the event the first time Interval elapses.
aTimer->AutoReset = false;
aTimer->Enabled = true;
evtCounter = 0; // <----------------Problem here
}
}
};
ASKER
I changed that line to evtCounter = -1; but the problem persists. Somehow, the first time the OnPaint method is invoked the values of xVALUE and yVALUE are zero because the multimeter hasn't been called yet. Can't this first invoking of the OnPaint method be overridden somehow?
ASKER
Can't the first values of xVALUE and yVALUE be obtained in the constructor before initializing the component?
If the multimeter read hasn't been called yet, how is evtCOunter changing from -1 to 0 since the only place that is supposed to happen is in the timer method where the read happens? I'd put a break in the constructor and set a watch on evtCOunter and see when it gets changed.
They could as long as you've initialized the multimeter class so the serial port is open.
ASKER
Yeah, that's logical. I don't know how to set a watch on evtCounter but I did the following -- I set breaks in the constructor:
temperature(void)
and in the line where evtCounter changes:
evtCounter += 1;
and I saw the following:
When F11 is depressed, after certain waiting period, the program goes to temperature.cpp, as expected:
System::Threading::Thread: :CurrentTh read->Apar tmentState = System::Threading::Apartme ntState::S TA;
then
Application::Run(new temperature());
after which gets into temperature.h into the constructor:
temperature(void)
followed by
InitializeComponent();
and then goes through the whole list of the initialization parameters, untill it reaches the end of the constructor. Then, back to temperature.cpp
Application::Run(new temperature());
And now, the most interesting -- the form appears on the screen momentarily, then disappears, and the program reaches:
evtCounter += 1;
Thus, it appears that evtCounter gets changed only after one painting of the form has already occurred.
temperature(void)
and in the line where evtCounter changes:
evtCounter += 1;
and I saw the following:
When F11 is depressed, after certain waiting period, the program goes to temperature.cpp, as expected:
System::Threading::Thread:
then
Application::Run(new temperature());
after which gets into temperature.h into the constructor:
temperature(void)
followed by
InitializeComponent();
and then goes through the whole list of the initialization parameters, untill it reaches the end of the constructor. Then, back to temperature.cpp
Application::Run(new temperature());
And now, the most interesting -- the form appears on the screen momentarily, then disappears, and the program reaches:
evtCounter += 1;
Thus, it appears that evtCounter gets changed only after one painting of the form has already occurred.
ASKER
How can this first painting of the form be gotten rid of?
ASKER
Something else ... Insertion of another breakpoint in the line
evtCounter = -1;
showed that above assignment of -1 to evtCounter occurs only after the first painting of the form.
evtCounter = -1;
showed that above assignment of -1 to evtCounter occurs only after the first painting of the form.
You can't get rid of first painting. When the form is rendered, it needds to paint. Anytime the form is uncovered, unminimized, or moved (or first shown) it will do OnPaint to render the form surface.
When you say
>> And now, the most interesting -- the form appears on the screen momentarily, then disappears, and the program reaches:
>> evtCounter += 1;
What method is that in? The only place that line should appear is in the timer callback where you are reading the meter. That, combined with the "if ( evtCounter >= 0 ) ..." in OnPaint should prevent plotting data until the meter has been read at least once.
When you say
>> And now, the most interesting -- the form appears on the screen momentarily, then disappears, and the program reaches:
>> evtCounter += 1;
What method is that in? The only place that line should appear is in the timer callback where you are reading the meter. That, combined with the "if ( evtCounter >= 0 ) ..." in OnPaint should prevent plotting data until the meter has been read at least once.
The form has to be constructed before it is painted, so where is the "evtCounter = -1;" that happens after the first painting? Perhaps you should post the whole code again so I can see what's going on. My version works perfectly except that I have a random number generator in place of the meter - or should I just post mine so you can look at it?
Compare this to what you have...
public __gc class temperature : public System::Windows::Forms::Fo rm
{
public:
temperature(void)
{
InitializeComponent();
evtCounter = -1;
xValues = new int __gc[500];
yValues = new double __gc[500];
rnd = new Random();
mmeter = new MultiMeter;
mmeter->ConfigureSerialInt erface(1);
aTimer = new System::Timers::Timer(500) ;
aTimer->Elapsed+=new System::Timers::ElapsedEve ntHandler( this, OnTimedEvent);
aTimer->AutoReset = false; // Don't automatically restart timer
aTimer->Enabled = true;
}
protected:
void Dispose(Boolean disposing)
{
if (disposing && components)
{
components->Dispose();
}
__super::Dispose(disposing );
}
private: System::Windows::Forms::Te xtBox * textBox1;
private: System::Windows::Forms::Te xtBox * textBox2;
private: System::Windows::Forms::Te xtBox * textBox3;
private: System::ComponentModel::IC ontainer * components;
private:
System::Timers::Timer *aTimer;
double yValues __gc[];
int xValues __gc[];
int evtCounter;
System::Random *rnd;
MultiMeter *mmeter;
private:
/// <summary>
/// Required designer variable.
/// </summary>
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
void InitializeComponent(void)
{
this->textBox1 = new System::Windows::Forms::Te xtBox();
this->textBox2 = new System::Windows::Forms::Te xtBox();
this->textBox3 = new System::Windows::Forms::Te xtBox();
this->SuspendLayout();
//
// textBox1
//
this->textBox1->Location = System::Drawing::Point(520 , 8);
this->textBox1->Name = S"textBox1";
this->textBox1->ReadOnly = true;
this->textBox1->TabIndex = 3;
this->textBox1->Text = S"";
this->textBox1->TextAlign = System::Windows::Forms::Ho rizontalAl ignment::C enter;
//
// textBox2
//
this->textBox2->Location = System::Drawing::Point(520 , 48);
this->textBox2->Multiline = true;
this->textBox2->Name = S"textBox2";
this->textBox2->ReadOnly = true;
this->textBox2->Size = System::Drawing::Size(104, 24);
this->textBox2->TabIndex = 4;
this->textBox2->Text = S"";
this->textBox2->TextAlign = System::Windows::Forms::Ho rizontalAl ignment::C enter;
//
// textBox3
//
this->textBox3->Location = System::Drawing::Point(520 , 136);
this->textBox3->Multiline = true;
this->textBox3->Name = S"textBox3";
this->textBox3->ReadOnly = true;
this->textBox3->Size = System::Drawing::Size(104, 24);
this->textBox3->TabIndex = 5;
this->textBox3->Text = S"";
this->textBox3->TextAlign = System::Windows::Forms::Ho rizontalAl ignment::C enter;
//
// temperature
//
this->AutoScaleBaseSize = System::Drawing::Size(5, 13);
this->ClientSize = System::Drawing::Size(632, 466);
this->Controls->Add(this-> textBox3);
this->Controls->Add(this-> textBox2);
this->Controls->Add(this-> textBox1);
this->Name = S"temperature";
this->StartPosition = System::Windows::Forms::Fo rmStartPos ition::Cen terScreen;
this->Text = S"Form1";
this->ResumeLayout(false);
}
private:
void OnTimedEvent(Object* source, System::Timers::ElapsedEve ntArgs* e)
{
try
{
evtCounter += 1;
textBox1->Text = System::Convert::ToString( evtCounter ,10);
BYTE *pBuf = NULL;
//double dMeterReading = mmeter->ReadData();
double dMeterReading = rnd->NextDouble()*200.0 + 100;
xValues[evtCounter] = evtCounter+20;
yValues[evtCounter] = dMeterReading;
textBox2->Text = System::Convert::ToString( dMeterRead ing);
// Restart timer
this->Invalidate();
aTimer->Start();
}
catch (System::Exception *ex)
{
System::Console::WriteLine (ex->Messa ge);
}
}
protected:
void OnPaint( PaintEventArgs *paintEvent )
{
// call base OnPaint method
__super::OnPaint( paintEvent );
if ( evtCounter >= 0 )
{
// get graphics object
Graphics *graphicsObject = paintEvent->Graphics;
SolidBrush *brush = new SolidBrush( Color::Blue );
Pen *pen = new Pen( Color::Black );
for ( int ii = 0; ii <= evtCounter; ii++ )
{
graphicsObject->DrawEllips e( pen,xValues[ii], yValues[ii], 7, 7 );
}
}
}
};
public __gc class temperature : public System::Windows::Forms::Fo
{
public:
temperature(void)
{
InitializeComponent();
evtCounter = -1;
xValues = new int __gc[500];
yValues = new double __gc[500];
rnd = new Random();
mmeter = new MultiMeter;
mmeter->ConfigureSerialInt
aTimer = new System::Timers::Timer(500)
aTimer->Elapsed+=new System::Timers::ElapsedEve
aTimer->AutoReset = false; // Don't automatically restart timer
aTimer->Enabled = true;
}
protected:
void Dispose(Boolean disposing)
{
if (disposing && components)
{
components->Dispose();
}
__super::Dispose(disposing
}
private: System::Windows::Forms::Te
private: System::Windows::Forms::Te
private: System::Windows::Forms::Te
private: System::ComponentModel::IC
private:
System::Timers::Timer *aTimer;
double yValues __gc[];
int xValues __gc[];
int evtCounter;
System::Random *rnd;
MultiMeter *mmeter;
private:
/// <summary>
/// Required designer variable.
/// </summary>
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
void InitializeComponent(void)
{
this->textBox1 = new System::Windows::Forms::Te
this->textBox2 = new System::Windows::Forms::Te
this->textBox3 = new System::Windows::Forms::Te
this->SuspendLayout();
//
// textBox1
//
this->textBox1->Location = System::Drawing::Point(520
this->textBox1->Name = S"textBox1";
this->textBox1->ReadOnly = true;
this->textBox1->TabIndex = 3;
this->textBox1->Text = S"";
this->textBox1->TextAlign = System::Windows::Forms::Ho
//
// textBox2
//
this->textBox2->Location = System::Drawing::Point(520
this->textBox2->Multiline = true;
this->textBox2->Name = S"textBox2";
this->textBox2->ReadOnly = true;
this->textBox2->Size = System::Drawing::Size(104,
this->textBox2->TabIndex = 4;
this->textBox2->Text = S"";
this->textBox2->TextAlign = System::Windows::Forms::Ho
//
// textBox3
//
this->textBox3->Location = System::Drawing::Point(520
this->textBox3->Multiline = true;
this->textBox3->Name = S"textBox3";
this->textBox3->ReadOnly = true;
this->textBox3->Size = System::Drawing::Size(104,
this->textBox3->TabIndex = 5;
this->textBox3->Text = S"";
this->textBox3->TextAlign = System::Windows::Forms::Ho
//
// temperature
//
this->AutoScaleBaseSize = System::Drawing::Size(5, 13);
this->ClientSize = System::Drawing::Size(632,
this->Controls->Add(this->
this->Controls->Add(this->
this->Controls->Add(this->
this->Name = S"temperature";
this->StartPosition = System::Windows::Forms::Fo
this->Text = S"Form1";
this->ResumeLayout(false);
}
private:
void OnTimedEvent(Object* source, System::Timers::ElapsedEve
{
try
{
evtCounter += 1;
textBox1->Text = System::Convert::ToString(
BYTE *pBuf = NULL;
//double dMeterReading = mmeter->ReadData();
double dMeterReading = rnd->NextDouble()*200.0 + 100;
xValues[evtCounter] = evtCounter+20;
yValues[evtCounter] = dMeterReading;
textBox2->Text = System::Convert::ToString(
// Restart timer
this->Invalidate();
aTimer->Start();
}
catch (System::Exception *ex)
{
System::Console::WriteLine
}
}
protected:
void OnPaint( PaintEventArgs *paintEvent )
{
// call base OnPaint method
__super::OnPaint( paintEvent );
if ( evtCounter >= 0 )
{
// get graphics object
Graphics *graphicsObject = paintEvent->Graphics;
SolidBrush *brush = new SolidBrush( Color::Blue );
Pen *pen = new Pen( Color::Black );
for ( int ii = 0; ii <= evtCounter; ii++ )
{
graphicsObject->DrawEllips
}
}
}
};
ASKER
Let me first mention this, before posting the code. I again inserted evtCounter = -1; (evtCounter being declared globally) in temperature.cpp just above Application::Run(new temperature());, so that I can be sure that evtCounter will be initialized with value -1 before anything else, especially before the form is initialized. Now, having done that I took it for granted that first time drawing of the ellipse would not occur because I had the following:
for (int iii = 1; iii <= 500; iii++)
{
if (evtCounter == -1 )
{
}
else
graphicsObject->DrawEllips e( pen, xVALUE[ iii ], yVALUE[ iii] * 10, 7, 7 );
}
(this 500 is just in this example; I'll take care of it later)
Curiously, the program didn't heed that 'if (evtCounter == -1 )' and performed as if evtCounter had a value different from -1. Thus, something had interfered between the time evtCounter was assigned the value -1 and the moment the program reached for the first time 'if (evtCounter == -1 )'.
I tried placing a breakpoint also in evtCounter += 1; but for some reason depressing F11 never stopped me at that point.
for (int iii = 1; iii <= 500; iii++)
{
if (evtCounter == -1 )
{
}
else
graphicsObject->DrawEllips
}
(this 500 is just in this example; I'll take care of it later)
Curiously, the program didn't heed that 'if (evtCounter == -1 )' and performed as if evtCounter had a value different from -1. Thus, something had interfered between the time evtCounter was assigned the value -1 and the moment the program reached for the first time 'if (evtCounter == -1 )'.
I tried placing a breakpoint also in evtCounter += 1; but for some reason depressing F11 never stopped me at that point.
I think you've got too many evtCounter's running around. Do not put it as a global. Put it in the temperature class and initialize it to -1 in the constructor. See the code I just posted. This is the correct way to handle it.
The code I posted should be functionally identical to yours except that instead of reading the meter I generate a random number between 100.0 and 300.0. If you copy it and switch the "double dMeterReading = rnd->NextDouble()..." line with the commented-out lne right above it, it should work. You will probably need to change the scaling on the plot as well.
The code I posted should be functionally identical to yours except that instead of reading the meter I generate a random number between 100.0 and 300.0. If you copy it and switch the "double dMeterReading = rnd->NextDouble()..." line with the commented-out lne right above it, it should work. You will probably need to change the scaling on the plot as well.
ASKER
OK, I was able to compile your above code. However, it still works in a similarly curious way as the code I have. In your code continuous plotting occurs at the very top of the form. In addition to that you have an immobile point at position x = 1 and y somewhere in the tens of form scale units. This second point changes its position along the y-axis as the values coming from the multimeter change, its x-axis position remaining unchanged.
Also, in your code you have placed the timer in the constructor. Let me post what I have. It at least correctly has the point moving in the plane of the form (one thing I'm noticing is the less selection statements there are the fewer instances of faulty data there are). Here is the code I have
#pragma once
#include "MultiMeter.h"
//static int evtCounter;
//static double dMeterReading;
using namespace System;
using namespace System::IO;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;
static int evtCounter = -1;
namespace Q307398
{
/// <summary>
/// Summary for Form1
///
/// WARNING: If you change the name of this class, you will need to change the
/// 'Resource File Name' property for the managed resource compiler tool
/// associated with all .resx files this class depends on. Otherwise,
/// the designers will not be able to interact properly with localized
/// resources associated with this form.
/// </summary>
public __gc class temperature : public System::Windows::Forms::Fo rm
{
public:
temperature(void)
{
InitializeComponent();
}
static double xVALUE __gc[] = new double __gc[ 1000 ];
static double yVALUE __gc[] = new double __gc[ 1000 ];
protected:
void Dispose(Boolean disposing)
{
if (disposing && components)
{
components->Dispose();
}
__super::Dispose(disposing );
}
private: System::Windows::Forms::Te xtBox * textBox1;
private: System::Timers::Timer* aTimer;
int evtCounter;
double dMeterReading;
MultiMeter *mmeter;
private: System::Windows::Forms::Ti mer * timer1;
private: System::Windows::Forms::Te xtBox * textBox2;
private: System::Windows::Forms::Te xtBox * textBox3;
private: System::Windows::Forms::Te xtBox * textBox4;
private: System::ComponentModel::IC ontainer * components;
private: System::Windows::Forms::La bel * label1;
private:
/// <summary>
/// Required designer variable.
/// </summary>
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
void InitializeComponent(void)
{
this->components = new System::ComponentModel::Co ntainer();
this->textBox1 = new System::Windows::Forms::Te xtBox();
this->timer1 = new System::Windows::Forms::Ti mer(this-> components );
this->textBox2 = new System::Windows::Forms::Te xtBox();
this->textBox3 = new System::Windows::Forms::Te xtBox();
this->textBox4 = new System::Windows::Forms::Te xtBox();
this->label1 = new System::Windows::Forms::La bel();
this->SuspendLayout();
//
// textBox1
//
this->textBox1->Location = System::Drawing::Point(40, 8);
this->textBox1->Name = S"textBox1";
this->textBox1->ReadOnly = true;
this->textBox1->Size = System::Drawing::Size(104, 20);
this->textBox1->TabIndex = 3;
this->textBox1->Text = S"";
this->textBox1->TextAlign = System::Windows::Forms::Ho rizontalAl ignment::C enter;
//
// timer1
//
this->timer1->Enabled = true;
this->timer1->Interval = 500;
this->timer1->Tick += new System::EventHandler(this, timer1_Tick);
//
// textBox2
//
this->textBox2->Location = System::Drawing::Point(40, 32);
this->textBox2->Multiline = true;
this->textBox2->Name = S"textBox2";
this->textBox2->ReadOnly = true;
this->textBox2->Size = System::Drawing::Size(104, 24);
this->textBox2->TabIndex = 4;
this->textBox2->Text = S"";
this->textBox2->TextAlign = System::Windows::Forms::Ho rizontalAl ignment::C enter;
//
// textBox3
//
this->textBox3->Location = System::Drawing::Point(296 , 32);
this->textBox3->Multiline = true;
this->textBox3->Name = S"textBox3";
this->textBox3->ReadOnly = true;
this->textBox3->Size = System::Drawing::Size(104, 24);
this->textBox3->TabIndex = 5;
this->textBox3->Text = S"";
this->textBox3->TextAlign = System::Windows::Forms::Ho rizontalAl ignment::C enter;
//
// textBox4
//
this->textBox4->Location = System::Drawing::Point(296 , 64);
this->textBox4->Multiline = true;
this->textBox4->Name = S"textBox4";
this->textBox4->ReadOnly = true;
this->textBox4->Size = System::Drawing::Size(104, 24);
this->textBox4->TabIndex = 6;
this->textBox4->Text = S"";
this->textBox4->TextAlign = System::Windows::Forms::Ho rizontalAl ignment::C enter;
//
// label1
//
this->label1->Location = System::Drawing::Point(280 , 8);
this->label1->Name = S"label1";
this->label1->Size = System::Drawing::Size(136, 24);
this->label1->TabIndex = 7;
this->label1->Text = S"Values passed to OnPaint";
//
// temperature
//
this->AutoScaleBaseSize = System::Drawing::Size(5, 13);
this->ClientSize = System::Drawing::Size(632, 466);
this->Controls->Add(this-> label1);
this->Controls->Add(this-> textBox4);
this->Controls->Add(this-> textBox3);
this->Controls->Add(this-> textBox2);
this->Controls->Add(this-> textBox1);
this->Name = S"temperature";
this->StartPosition = System::Windows::Forms::Fo rmStartPos ition::Cen terScreen;
this->Text = S"Form1";
this->ResumeLayout(false);
}
private:
void OnTimedEvent(Object* source, System::Timers::ElapsedEve ntArgs* e)
{
try
{
BYTE *pBuf = NULL;
dMeterReading = mmeter->ReadData();
// Code for debugging
if ( dMeterReading == 0 ) System::Windows::Forms::Me ssageBox:: Show(S"dMe terReading is 0!");
if ( dMeterReading == System::Double::MaxValue)
{
}
else
{
evtCounter += 1;
yVALUE[ evtCounter ] = dMeterReading;
Invalidate();
textBox2->Text = System::Convert::ToString( dMeterRead ing);
xVALUE[ evtCounter ] = evtCounter;
textBox1->Text = System::Convert::ToString( evtCounter ,10);
}
// Restart timer
aTimer->Start();
}
catch (System::Exception *ex)
{
System::Console::WriteLine (ex->Messa ge);
}
}
protected:
void OnPaint( PaintEventArgs *paintEvent )
{
// call base OnPaint method
__super::OnPaint( paintEvent );
// get graphics object
Graphics *graphicsObject = paintEvent->Graphics;
SolidBrush *brush = new SolidBrush( Color::Blue );
Pen *pen = new Pen( Color::Black );
textBox3->Text = System::Convert::ToString( dMeterRead ing);
textBox4->Text = System::Convert::ToString( evtCounter );
for (int iii = 1; iii <= 500; iii++)
{
if (evtCounter == -1 )
{
}
else
graphicsObject->DrawEllips e( pen, xVALUE[ iii ], yVALUE[ iii] * 10, 7, 7 );
}
}
private: System::Void timer1_Tick(System::Object * sender, System::EventArgs * e)
{
if ( mmeter == NULL )
{
timer1->Stop();
mmeter = new MultiMeter;
mmeter->ConfigureSerialInt erface();
aTimer = new System::Timers::Timer(500) ;
aTimer->Elapsed+=new System::Timers::ElapsedEve ntHandler( this, OnTimedEvent);
//// Only raise the event the first time Interval elapses.
aTimer->AutoReset = false;
aTimer->Enabled = true;
evtCounter = -1;
}
}
};
}
:
Also, in your code you have placed the timer in the constructor. Let me post what I have. It at least correctly has the point moving in the plane of the form (one thing I'm noticing is the less selection statements there are the fewer instances of faulty data there are). Here is the code I have
#pragma once
#include "MultiMeter.h"
//static int evtCounter;
//static double dMeterReading;
using namespace System;
using namespace System::IO;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;
static int evtCounter = -1;
namespace Q307398
{
/// <summary>
/// Summary for Form1
///
/// WARNING: If you change the name of this class, you will need to change the
/// 'Resource File Name' property for the managed resource compiler tool
/// associated with all .resx files this class depends on. Otherwise,
/// the designers will not be able to interact properly with localized
/// resources associated with this form.
/// </summary>
public __gc class temperature : public System::Windows::Forms::Fo
{
public:
temperature(void)
{
InitializeComponent();
}
static double xVALUE __gc[] = new double __gc[ 1000 ];
static double yVALUE __gc[] = new double __gc[ 1000 ];
protected:
void Dispose(Boolean disposing)
{
if (disposing && components)
{
components->Dispose();
}
__super::Dispose(disposing
}
private: System::Windows::Forms::Te
private: System::Timers::Timer* aTimer;
int evtCounter;
double dMeterReading;
MultiMeter *mmeter;
private: System::Windows::Forms::Ti
private: System::Windows::Forms::Te
private: System::Windows::Forms::Te
private: System::Windows::Forms::Te
private: System::ComponentModel::IC
private: System::Windows::Forms::La
private:
/// <summary>
/// Required designer variable.
/// </summary>
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
void InitializeComponent(void)
{
this->components = new System::ComponentModel::Co
this->textBox1 = new System::Windows::Forms::Te
this->timer1 = new System::Windows::Forms::Ti
this->textBox2 = new System::Windows::Forms::Te
this->textBox3 = new System::Windows::Forms::Te
this->textBox4 = new System::Windows::Forms::Te
this->label1 = new System::Windows::Forms::La
this->SuspendLayout();
//
// textBox1
//
this->textBox1->Location = System::Drawing::Point(40,
this->textBox1->Name = S"textBox1";
this->textBox1->ReadOnly = true;
this->textBox1->Size = System::Drawing::Size(104,
this->textBox1->TabIndex = 3;
this->textBox1->Text = S"";
this->textBox1->TextAlign = System::Windows::Forms::Ho
//
// timer1
//
this->timer1->Enabled = true;
this->timer1->Interval = 500;
this->timer1->Tick += new System::EventHandler(this,
//
// textBox2
//
this->textBox2->Location = System::Drawing::Point(40,
this->textBox2->Multiline = true;
this->textBox2->Name = S"textBox2";
this->textBox2->ReadOnly = true;
this->textBox2->Size = System::Drawing::Size(104,
this->textBox2->TabIndex = 4;
this->textBox2->Text = S"";
this->textBox2->TextAlign = System::Windows::Forms::Ho
//
// textBox3
//
this->textBox3->Location = System::Drawing::Point(296
this->textBox3->Multiline = true;
this->textBox3->Name = S"textBox3";
this->textBox3->ReadOnly = true;
this->textBox3->Size = System::Drawing::Size(104,
this->textBox3->TabIndex = 5;
this->textBox3->Text = S"";
this->textBox3->TextAlign = System::Windows::Forms::Ho
//
// textBox4
//
this->textBox4->Location = System::Drawing::Point(296
this->textBox4->Multiline = true;
this->textBox4->Name = S"textBox4";
this->textBox4->ReadOnly = true;
this->textBox4->Size = System::Drawing::Size(104,
this->textBox4->TabIndex = 6;
this->textBox4->Text = S"";
this->textBox4->TextAlign = System::Windows::Forms::Ho
//
// label1
//
this->label1->Location = System::Drawing::Point(280
this->label1->Name = S"label1";
this->label1->Size = System::Drawing::Size(136,
this->label1->TabIndex = 7;
this->label1->Text = S"Values passed to OnPaint";
//
// temperature
//
this->AutoScaleBaseSize = System::Drawing::Size(5, 13);
this->ClientSize = System::Drawing::Size(632,
this->Controls->Add(this->
this->Controls->Add(this->
this->Controls->Add(this->
this->Controls->Add(this->
this->Controls->Add(this->
this->Name = S"temperature";
this->StartPosition = System::Windows::Forms::Fo
this->Text = S"Form1";
this->ResumeLayout(false);
}
private:
void OnTimedEvent(Object* source, System::Timers::ElapsedEve
{
try
{
BYTE *pBuf = NULL;
dMeterReading = mmeter->ReadData();
// Code for debugging
if ( dMeterReading == 0 ) System::Windows::Forms::Me
if ( dMeterReading == System::Double::MaxValue)
{
}
else
{
evtCounter += 1;
yVALUE[ evtCounter ] = dMeterReading;
Invalidate();
textBox2->Text = System::Convert::ToString(
xVALUE[ evtCounter ] = evtCounter;
textBox1->Text = System::Convert::ToString(
}
// Restart timer
aTimer->Start();
}
catch (System::Exception *ex)
{
System::Console::WriteLine
}
}
protected:
void OnPaint( PaintEventArgs *paintEvent )
{
// call base OnPaint method
__super::OnPaint( paintEvent );
// get graphics object
Graphics *graphicsObject = paintEvent->Graphics;
SolidBrush *brush = new SolidBrush( Color::Blue );
Pen *pen = new Pen( Color::Black );
textBox3->Text = System::Convert::ToString(
textBox4->Text = System::Convert::ToString(
for (int iii = 1; iii <= 500; iii++)
{
if (evtCounter == -1 )
{
}
else
graphicsObject->DrawEllips
}
}
private: System::Void timer1_Tick(System::Object
{
if ( mmeter == NULL )
{
timer1->Stop();
mmeter = new MultiMeter;
mmeter->ConfigureSerialInt
aTimer = new System::Timers::Timer(500)
aTimer->Elapsed+=new System::Timers::ElapsedEve
//// Only raise the event the first time Interval elapses.
aTimer->AutoReset = false;
aTimer->Enabled = true;
evtCounter = -1;
}
}
};
}
:
Interestingly, that is not at all the behavior my code exhibits on my system here. I get a nice plot going across the middle of my form (that's why I offset all the y coords by 100). Like I said, if you switch to use the multimeter readings instead of the random number generator, you'll nned to change the plot scaling. Did you try it with the random number?
Anyway, the reason you keep getting the evtCounter not -1 in OnPaint is because you did not put the evtCounter=-1 in the constructor as I keep mentioning. You have it in timer1_tick method which doesn't get called until long (in CPU time) after the form has been painted. All that code you have in the timer1_tick method beliongs in the constructor right after the call to IntializeComponents. That's what constructors are for.
Anyway, the reason you keep getting the evtCounter not -1 in OnPaint is because you did not put the evtCounter=-1 in the constructor as I keep mentioning. You have it in timer1_tick method which doesn't get called until long (in CPU time) after the form has been painted. All that code you have in the timer1_tick method beliongs in the constructor right after the call to IntializeComponents. That's what constructors are for.
I ran your version of the code and made one change - you need to set the xVALUE array BEFORE calling invalidate. Other than that, except that it's plotting hundreds of points at 0,0 and plots one time before you've even read in any data (see previous post), it seems to work. Again, I replaced
dMeterReading = mmeter->ReadData();
with
dMeterReading = rnd->NextDouble()*100+50;
What exactly is not right?
dMeterReading = mmeter->ReadData();
with
dMeterReading = rnd->NextDouble()*100+50;
What exactly is not right?
ASKER
See, the code above is only one variant of the many ways I tried to place evtCounter = -1;. I placed it in the temperature.cpp, in the constructor, you name it. I just tried again placing it in the constructor -- didn't do any good. The reason, I think, why the code doesn't work is because I don't fully understand the method OnPaint. Somehow, I feel uncomfortable that I have to create sequential events through selection statements. This is one recurrent problem I have which shows itself here as well.
As for your code, I didn't use any special scaling. I'm using the natural scale of the form and I just replaced the random numbers with the data coming from the multimeter. Let me take a look again.
As for your code, I didn't use any special scaling. I'm using the natural scale of the form and I just replaced the random numbers with the data coming from the multimeter. Let me take a look again.
ASKER
Indeed, the program otherwise works just fine. It is that first point you mention that bothers me. I can't understand how is it that something which is declared to be evtCounter = -1 at the onset later cannot be used as a condition and is ignored.
We seem to be homing in on something here. Now that I've run your code and it works exactly as I would expect based on what I see, what is your issue? I've kind of lost that in the shuffle here, but I can probably tell you how to solve it now.
ASKER
See, suppose there is an array of 10 non-zero experimental points to be plotted on the screen. lt will be incorrect if the first of these non-zero points is plotted on the screen (and is saved in a text file) as if it is of zero value.
The way the program works now gives an impression that the first point is always zero. That has to be corrected.
The way the program works now gives an impression that the first point is always zero. That has to be corrected.
ASKER
Mind you, it may happaen that one of the experimental points is indeed zero, therefore, what I did, writing
for (int iii = 1; iii <= 500; iii++)
{
if ( yVALUE[ iii ] == 0)
;
else
graphicsObject->DrawEllips e( pen, xVALUE[ iii ], yVALUE[ iii] * 10, 7, 7 );
}
is incorrect in the general case because it will ignore legitimate points of zero value.
for (int iii = 1; iii <= 500; iii++)
{
if ( yVALUE[ iii ] == 0)
;
else
graphicsObject->DrawEllips
}
is incorrect in the general case because it will ignore legitimate points of zero value.
>> lt will be incorrect if the first of these non-zero points is plotted on the screen (and is saved in a text file) as if it is of zero value.
True enough, but plotting can be easily fixed by initializing evtCounter properly before OnPaint is called. Another approach might be to add another variable in the form:
bool haveData;
initialized to false in the constructor. Then in OnPaint check "if (haveData)..." instead of "if (evtCounter >= 0)...". It's basically the same thing but perhaps less confusing. Then in OnTimedEvent, do "haveData = true;" after reading valid data from the meter. This is the signal to start plotting.
Also, C++ arrays start at 0. You should be iterating from 0 to 500, not 1. If you declare an array ...[n], the valid index values are 0 to n-1. Also a reminder, your code is plotting 400+ points at 0,0 since you iterate to 500 every time. You should really stop at evtCounter since that's how many points you have at any moment.
True enough, but plotting can be easily fixed by initializing evtCounter properly before OnPaint is called. Another approach might be to add another variable in the form:
bool haveData;
initialized to false in the constructor. Then in OnPaint check "if (haveData)..." instead of "if (evtCounter >= 0)...". It's basically the same thing but perhaps less confusing. Then in OnTimedEvent, do "haveData = true;" after reading valid data from the meter. This is the signal to start plotting.
Also, C++ arrays start at 0. You should be iterating from 0 to 500, not 1. If you declare an array ...[n], the valid index values are 0 to n-1. Also a reminder, your code is plotting 400+ points at 0,0 since you iterate to 500 every time. You should really stop at evtCounter since that's how many points you have at any moment.
ASKER
I just tried initializing bool haveData as false in the constructor, then having it become true after reading valid data and checking it in the OnPaint with if (haveData ...). Still gives the first point at 0,0 position ... How can this be?
Also, I don't understand what you mean by saying "your code is plotting 400+ points at 0,0 since you iterate to 500 every time". The code seems to be plotting only one, the first one, point at 0,0 and all other points are plotted at non-zero x and y's.
Also, I don't understand what you mean by saying "your code is plotting 400+ points at 0,0 since you iterate to 500 every time". The code seems to be plotting only one, the first one, point at 0,0 and all other points are plotted at non-zero x and y's.
No, it's not the first one - it's actually evtCounter+1 to 500 that are being plotted right on top of each other at 0,0. Run the code for a couple of seconds and the set a break in OnPaint. Step through and you'll see that after the first few ponts which have valid values, all the rest have x and y values of 0. I think that's what's confusing you.
ASKER
Now, this sounds confusing, indeed. I think it's very important to be clarified and corrected, if that's the case. Otherwise the program will be useless.
Here's a test you can run to see if things are going as expected (assumes you've changed iteration in OnPaint):
1) Put a breakpoint in OnTimedEvent
2) Put a breakpoint at the start of the "for (iii = 0;..." loop in OnPaint which should be inside the "if (haveData)..." block.
3) Run the program
4) You should hit the OnTimedEvent breakpoint first. Validate that haveData is set to true. Step through a few lines if you have to.
5) Continue execution
6) You should hit the OnPaint breakpoint next.
7) Expand xVALUE and yVALUE arrays and validata that yVALUE[0] is non-zero. xValue[0] will be 0 unless you add an offset like I did in my code. I wanted to start plotting a little into the form, so I used evtCounter+20 as my xVALUE - my lowest xVALUE was 20.
If you can do that test successfully, then the code is correct. I think you will find this to be the case. What is confusing you is that you are seeing points plotted at 0,0 and you assume that this is the first point in the array when in fact it is all the unused points at teh end of the array.
1) Put a breakpoint in OnTimedEvent
2) Put a breakpoint at the start of the "for (iii = 0;..." loop in OnPaint which should be inside the "if (haveData)..." block.
3) Run the program
4) You should hit the OnTimedEvent breakpoint first. Validate that haveData is set to true. Step through a few lines if you have to.
5) Continue execution
6) You should hit the OnPaint breakpoint next.
7) Expand xVALUE and yVALUE arrays and validata that yVALUE[0] is non-zero. xValue[0] will be 0 unless you add an offset like I did in my code. I wanted to start plotting a little into the form, so I used evtCounter+20 as my xVALUE - my lowest xVALUE was 20.
If you can do that test successfully, then the code is correct. I think you will find this to be the case. What is confusing you is that you are seeing points plotted at 0,0 and you assume that this is the first point in the array when in fact it is all the unused points at teh end of the array.
ASKER
I tried the test point by point as you asked me to do in your previous post. Unfortunately, I had problems applying it. I set up the breakpoints, as you explained, and then started the program. I don't know, however, what you mean by "Expand xVALUE and yVALUE arrays and validata that yVALUE[0] is non-zero." I don't know how to expand it. Thus, I didn't get too far with that test.
To explore the issue I approached it this way. I added some code which writes the values of xVALUE[ iii ] and yVALUE[ iii ] in a text file named TestFile.txt. The code goes as follows:
if (haveData == false)
;
else
{
for (int iii = 0; iii <= 9; iii++)
{
graphicsObject->DrawEllips e( pen, xVALUE[ iii ], yVALUE[ iii] * 20, 7, 7 );
}
}
StreamWriter* pwriter = new StreamWriter( S"c:/AAAAAAVisual C++/TestFile.txt" );
for ( int jjj = 0; jjj <= 9; jjj++ )
{
String *xxx = xVALUE [ jjj ].ToString();
String *yyy = yVALUE [ jjj ].ToString();
String *xxxyyy = String::Concat(xxx, " ", yyy);
pwriter->WriteLine( xxxyyy );
}
pwriter->Close();
and this is what I obtain in the text file when I run the program until the counter is increased from 0 to 9::
0 10.71
1 10.71
2 10.72
3 10.73
4 10.73
5 10.73
6 9.84
7 9.65
8 9.17
9 8.46
These are the actual values of xVALUE[ iii ] and yVALUE[ iii ] coming in from the multimeter. They are being plotted on the screen and can be observed (in addition to the misterious point at 0,0 which we seen not to be able to get rid of). As you can see there are no 0,0 couples in these data. That's why I was telling you that I don't understand when you're saying:
"What is confusing you is that you are seeing points plotted at 0,0 and you assume that this is the first point in the array when in fact it is all the unused points at teh end of the array."
(I don't know what the term 'teh' means, could you explain, please).
Thus, it seems to me that the whole problem stems from the application of the OnPaint method. It boggles the mind how come one can have have evtCounter assigned to -1 at the onset of the program and yet when the selection statement in the OnPaint method is to obey it, it in fact disregards it. I think that's what is unclear in this problem.
To explore the issue I approached it this way. I added some code which writes the values of xVALUE[ iii ] and yVALUE[ iii ] in a text file named TestFile.txt. The code goes as follows:
if (haveData == false)
;
else
{
for (int iii = 0; iii <= 9; iii++)
{
graphicsObject->DrawEllips
}
}
StreamWriter* pwriter = new StreamWriter( S"c:/AAAAAAVisual C++/TestFile.txt" );
for ( int jjj = 0; jjj <= 9; jjj++ )
{
String *xxx = xVALUE [ jjj ].ToString();
String *yyy = yVALUE [ jjj ].ToString();
String *xxxyyy = String::Concat(xxx, " ", yyy);
pwriter->WriteLine( xxxyyy );
}
pwriter->Close();
and this is what I obtain in the text file when I run the program until the counter is increased from 0 to 9::
0 10.71
1 10.71
2 10.72
3 10.73
4 10.73
5 10.73
6 9.84
7 9.65
8 9.17
9 8.46
These are the actual values of xVALUE[ iii ] and yVALUE[ iii ] coming in from the multimeter. They are being plotted on the screen and can be observed (in addition to the misterious point at 0,0 which we seen not to be able to get rid of). As you can see there are no 0,0 couples in these data. That's why I was telling you that I don't understand when you're saying:
"What is confusing you is that you are seeing points plotted at 0,0 and you assume that this is the first point in the array when in fact it is all the unused points at teh end of the array."
(I don't know what the term 'teh' means, could you explain, please).
Thus, it seems to me that the whole problem stems from the application of the OnPaint method. It boggles the mind how come one can have have evtCounter assigned to -1 at the onset of the program and yet when the selection statement in the OnPaint method is to obey it, it in fact disregards it. I think that's what is unclear in this problem.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
OK, here’s the solution of that “mystery”. Believe it or not it consists in changing just one little thing. In the for loop one should have evtCounter instead of 500, namely
for (int iii = 0; iii <= evtCounter; iii++)
{
graphicsObject->DrawEllips e( pen, xVALUE[ iii ], yVALUE[ iii] * 20, 7, 7 );
}
}
And it stands to reason. As you explained, the loop containing 500 as a parameter will inevitably loop 500 times every time the OnPaint method is called. This will lead to multiple 0,0 points in the initial stages of the acquisition of the points (in fact, until 500 actual points are acquired). Thus, a “mysterious” 0,0 point will always be seen plotted on the screen as many times as there are zeros (due to still not acquired data) coming from the 500-turn for-loop.
Now, with the above code that 0,0 point is gone because the for-loop turns only as many times as the multimeter has actually been called (accounted for by the value of the evtCounted). Undoubtedly, evtCounter has to be initialized as –1 so that even initially no bogus 0,0 point is seen on the graph.
Now, due to the discussion with you this problem is taken care of. What remains is the checksum problem. Obviously, if one needs to retain the actual number of points taken one mustn’t write code which skips unpleasant points. Probably, correction of the point values should occur somehow manually, after all data has been acquired.
I will open later a special question to discuss that. Now I’m closing this question and would like to thank you so much for the great help.
P.S. Please note, I’m increasing your points to 250. Please let me know if you have problems in getting the increased points.
for (int iii = 0; iii <= evtCounter; iii++)
{
graphicsObject->DrawEllips
}
}
And it stands to reason. As you explained, the loop containing 500 as a parameter will inevitably loop 500 times every time the OnPaint method is called. This will lead to multiple 0,0 points in the initial stages of the acquisition of the points (in fact, until 500 actual points are acquired). Thus, a “mysterious” 0,0 point will always be seen plotted on the screen as many times as there are zeros (due to still not acquired data) coming from the 500-turn for-loop.
Now, with the above code that 0,0 point is gone because the for-loop turns only as many times as the multimeter has actually been called (accounted for by the value of the evtCounted). Undoubtedly, evtCounter has to be initialized as –1 so that even initially no bogus 0,0 point is seen on the graph.
Now, due to the discussion with you this problem is taken care of. What remains is the checksum problem. Obviously, if one needs to retain the actual number of points taken one mustn’t write code which skips unpleasant points. Probably, correction of the point values should occur somehow manually, after all data has been acquired.
I will open later a special question to discuss that. Now I’m closing this question and would like to thank you so much for the great help.
P.S. Please note, I’m increasing your points to 250. Please let me know if you have problems in getting the increased points.
ASKER
Small correction. To avoid the momentary appearance of the 0,0 point at the beginning the above loop should start from iii = 1:
for (int iii = 1; iii <= evtCounter; iii++)
for (int iii = 1; iii <= evtCounter; iii++)