Graphics ... almost working ... missing one line?

  • Thread starter Thread starter Peter Webb
  • Start date Start date
P

Peter Webb

I previously asked about two problems I had with some graphics - the first
was that when I drew animation to a picturebox it wouldn't display when the
Form loaded.

It was suggested to me by everyone that I stop using my own CreateGraphics
calls, and override an OnPaint call to do this. As suggested, I created a
custom control "drawBox" with an override on its OnPaint. Because I am using
manual double buffering, as people suggested it was really just a matter of
putting myBuffer.Render() into the OnPaint, and using drawBox.Invalidate as
the call. In the end I only had to change/add about 8 lines of code, and its
only taken about 16 hours to work out exactly which ones.

However, there is one annoying problem that remains. I can get it to show
the initial screen just fine when it loads. But what I really want it to do
is play the opening animation.

If I put the call to animate the screen

play_animation();

As the very last line of Form1_Load or anywhere else that I have tried, then
the Form1 doesn't actually load and show anything until the animation is
finished, at which point the Form pops up showing only the final (end) frame
of the animation.

I had the same problem with the old (bad) way I did graphics, so I assume
its not related ... but FWIW, here are they key parts of my new graphics:

public partial class Form1 : Form
{
static public drawBox pictureBoxn;

....

public class drawBox : Control
{
public drawBox()
{
this.Height = 600;
this.Width = 600;
}
protected override void OnPaint(PaintEventArgs pe)
{
base.OnPaint(pe);
myBuffer.Render();

}
}

I call the following in Form1_Load:

pictureBoxn = new drawBox();
currentContext = BufferedGraphicsManager.Current;
myBuffer =
currentContext.Allocate(pictureBoxn.CreateGraphics(),
pictureBoxn.DisplayRectangle);
this.Controls.Add(pictureBoxn);

canvas = myBuffer.Graphics;
canvas.SmoothingMode =
System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
// canvas.Clear(Color.White);
screenwidth = pictureBoxn.Width;
screenheight = pictureBoxn.Height;
tracks = new Bitmap((int)screenwidth, (int)screenheight);
backgroundcanvas = Graphics.FromImage(tracks);
backgroundcanvas.SmoothingMode =
System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
backgroundcanvas.Clear(Color.Red);
pictureBoxn.Paint += new
System.Windows.Forms.PaintEventHandler(this.pictureBoxn_Paint);

pictureBoxn.Refresh();
pictureBoxn.Show();
pictureBoxn.Update();
pictureBoxn.Invalidate();
 
Peter,

What is in the code for play_animation? Are you looping through and
repainting on every invocation of the loop? It seems like that is the case
here.

What you really want to do is create a timer which you invalidate your
picturebox on every tick (the frame rate of your animation will depend on
the frequency of the timer).
 
Nicholas Paldino said:
Peter,

What is in the code for play_animation? Are you looping through and
repainting on every invocation of the loop? It seems like that is the
case here.

What you really want to do is create a timer which you invalidate your
picturebox on every tick (the frame rate of your animation will depend on
the frequency of the timer).

Yes. I am looping through dozens of on-screen objects, updating their
position. That's what my program does, and spends all its time. In the main
animation loop, I still use a myBuffer.Render() command, as the
drawBox.Invalidate() command flickers (even though it just does a
myBuffer.Render() ).

I was told before (and I think by you) to use a timer in asynchronous
thread. It didn't seem an issue in my app, as most people will want to run
it flat out, so having two threads was more complexity that I didn't
understand.

The annoying thing is that it is just a problem at start up of the Form.
Everything else works brilliantly.

Is there some quick and dirty I can do for the start-up to make the form
appear before the animation starts (or even finishes!)?

Or if I have to do this properly, can you refer me to a web page that might
get me started?
 
Yes. I am looping through dozens of on-screen objects, updating their
position.

Don't do that.
That's what my program does, and spends all its time.

Even so, don't do that.
In the main animation loop, I still use a myBuffer.Render() command, as
the drawBox.Invalidate() command flickers (even though it just does a
myBuffer.Render() ).

The flicker is because calling Invalidate() causes the entire control to
be erased first, before the OnPaint() method is called. You can avoid
this in a couple of ways, but the simplest in a custom control is to just
set the DoubleBuffered property of your control to true (note that this
property has nothing to do with your own buffering...it causes the OS to
create a new off-screen buffer to be used for drawing during updates to
the control).

Flicker isn't a good reason to abandon the standard Windows drawing
model. There are better ways to fix it.
I was told before (and I think by you) to use a timer in asynchronous
thread. It didn't seem an issue in my app, as most people will want to
run it flat out, so having two threads was more complexity that I didn't
understand.

Some points here:

* You might not need a different thread. It's possible that the
Forms.Timer class provides enough accuracy for your animation. It offers
a slightly simpler way to deal with timing.

* A second thread should not be all that complicated in this case.
The trickiest part is remembering that you need to use Control.Invoke() to
call any methods that directly use the UI component. In this case, that's
likely to just be the call to Invalidate(), which you can accomplish like
this (using an anonymous method):

myCustomControl.Invoke((MethodInvoker)delegate()
{ myCustomControl.Invalidate(); });

Note: when using a second thread, you _might_ still run into timing
issues, because while the thread itself might be able to manage its own
timing reasonably well, the redraw stuff (invalidation and redrawing after
invalidation) still has to go through the normal window message queue that
the Forms.Timer object would have had to. There are some basic
limitations when writing a regular Windows applications that will be
present no matter _how_ you do the drawing, right way or wrong way.

I would recommend you try for the Forms.Timer class first, as it provides
a nice, easy API where you don't have cross-thread issues. In addition to
the requirement to invalidate from the main GUI thread (and thus the need
to use Invoke()), using a second thread will also mean you need to impose
some sort of thread synchronization. Either you'll need to essentially
double-buffer your buffer, always having a finished copy used for handling
the control update and a second copy into which you actually draw the new
data, or you'll need to use lock() to protect any code using the buffer so
that you don't have two threads trying to manipulate the data structure at
the same time. Neither is difficult, but why introduce the complexities
if you don't have to?

Note that no matter what you do, you're going to be limited to something
like 15-20 fps using a mechanism like this. Trying to update any more
frequently than that is likely to lead to uneven animation, with some
frames being displayed much shorter or longer periods of time than
others. For faster animation than that, you simply need to get away from
the standard Windows application model completely, which you're not going
to do with a regular .NET forms application.

* It's not really true that most people "will want to run it flat
out". Practically every user I've met wants to be able to exit an
application whenever they want to. Using your design won't allow that, as
the form will not respond to user input until the animation has completed.
The annoying thing is that it is just a problem at start up of the Form.
Everything else works brilliantly.

I'm not sure I'd use the term "brilliantly" to describe how _everything
else_ in your application works. You may have gotten the animation to
animate, but other than that your application isn't a very well-behaved
Windows application.

As promised to you, by failing to adhere to the standard drawing model in
Windows, you've created new, difficult-to-solve problems.
Is there some quick and dirty I can do for the start-up to make the form
appear before the animation starts (or even finishes!)?

Well, one option would be to move your animation code to some place where
you know it will take place after the form has drawn. But keep in mind
that doing that will only change the specific scenarios in which your form
won't draw. It will be trivial to demonstrate other scenarios in which
the form needs to be draw _again_, but won't be able to because you're
stuck in your animation loop.

The correct fix, and the only one I will recommend, is to fix your code so
that your control _only_ draws itself in response to WM_PAINT messages.
In other words, in the OnPaint() method, and in there drawing only the
_current_ state of the data. Updates of the data used for animation
(which in your case basically just means your off-screen buffer) must be
done outside of the drawing code. When the data is updated, simply call
Invalidate() to cause a redraw to happen.
Or if I have to do this properly, can you refer me to a web page that
might get me started?

I posted a number of useful links in the previous thread, to pages on the
MSDN web site. I believe someone else has posted one or more links to Bob
Powell's web site as well (which I can't vouch for, but I've seen other
people recommend it highly).

Mostly though, you really need to just focus on the basics. There's a
very specific, but easily-described paradigm here:

* Make sure your drawing code responds correctly to OnPaint(),
rendering the current state of the data and being able to do so at any
time.
* Don't draw from the same place where you change the data. Call
Invalidate() instead.

From that, everything else derives.

Pete
 
Is there some quick and dirty I can do for the start-up to make the form
Yes. Try the FormShown event instead. The FormLoad event is NOT the place
to try animation.
 
Yes. Try the FormShown event instead. The FormLoad event is NOT the
place to try animation.

Neither is FormShown. _Starting_ some animation process might be
appropriate there, and would be just as appropriate in the FormLoad
event. Actually _doing_ the animation belongs there no more than it
belongs in FormLoad.
 
I never said that the FormShown event was the optimum place to do
animation.

This isn't about what's "optimum". It's about what's correct. The world
already has plenty of crummy software. No one needs our help adding to
the list.
I was answering a specific question from the poster which is, "Is there
some quick and dirty I can do for the start-up to make the form appear
before the animation starts (or even finishes!)?" Did you notice the
quick and dirty reference? Hence, I offered the FormShown event. Quick
and dirty.

It's worse than quick and dirty. It's pure, unadulterated excrement.
Granted, it's just my opinion, but that opinion is that we as a community
have no business helping other people make .NET applications _worse_.
Which is just what you've done.

Note that now that Webb has a hack that appears to him to get done what he
thinks he wants done, he has no interest in making the application work
correctly before he releases it on whatever unsuspecting customers he's
got. So now, whatever that application does (I seem to recall something
about an orbit simulation or something), anyone who wants to do anything
with the application other than watch whatever animation is going on
(like, for example, exit the application...a basic function that every
user has the right to expect from any application) isn't going to be able
to do it.

Some questions are best left unanswered.

Pete
 
[...]
Actually, there is a little bit of multi-threading/re-entrancy in my
code. When I kick-off the animation, I turn off all the buttons that
"do" things that aren't reasonable to change in the middle of an
animation. I leave a "Stop" button, and some options to do with the
animation - level of detail, speed, etc. I have a DoEvents call after
each animation loop that allows the buttons to respond during the
animation.

Ah. Great. You've compounded the original error with another, which is
the use of DoEvents(). :(

Oh well...at least your users can exit the application that way.
[...]
Again, thankyou for your advice and help.

I guess I should be glad you found my posts helpful. From here though, I
don't really see that any of my advice wound up in your program. Mostly,
I'm just sad about the whole thing.

Pete
 
I never said that the FormShown event was the optimum place to do animation.
I was answering a specific question from the poster which is, "Is there some
quick and dirty I can do for the start-up to make the form appear before the
animation starts (or even finishes!)?" Did you notice the quick and dirty
reference? Hence, I offered the FormShown event. Quick and dirty.
 
Joey Joe Joe said:
Yes. Try the FormShown event instead. The FormLoad event is NOT the place
to try animation.

Yes, thankyou. Changing "Form_Load" to "Form_Show" solved the problem. I
suspect that this would also have solved my original problem (the PictureBox
coming up blank, instead of showing the default setup screen), without my
needing to redevelop this using a custom control and OnPaint. Having said
that, I am still pleased that I investigated and implemented OnPaint, at
least I now know how to implement V2 "more properly", and learned a lot in
the process. As it is, V1.0 is now ready to ship - thankyou again.
 
Thankyou for your advice now, and previously.

My app actually now works extremely well, at least on my computer. By having
it entirely single threaded, I also know that it will work on any computer -
there is obviously far less scope for timing issues etc if my app runs that
way.

Having said that, your advice has always been excellent, and if and when I
decide to develop V2 it will be done in the way you suggest (as will any
future programs).

Actually, there is a little bit of multi-threading/re-entrancy in my code.
When I kick-off the animation, I turn off all the buttons that "do" things
that aren't reasonable to change in the middle of an animation. I leave a
"Stop" button, and some options to do with the animation - level of detail,
speed, etc. I have a DoEvents call after each animation loop that allows the
buttons to respond during the animation. Clicking these buttons just set
flags and values used in the animation loop; these are all read-only in the
animation so critical races cannot occur.

I don't know how fast it runs, but having a Thread.Sleep(10) after each
animation frame makes a noticeable difference to the speed, so its pretty
fast. Considering that I redraw my entire 1000 x 768 bitmap on every loop,
its pretty good - almost a million points are copied on every animation. I
can speed this up by redrawing only the part that has changed, as you
suggested - difficult to do with how the code is implemented now (as the
draws are intermingled with the position logic code) but when I develop V2 I
will clean this up in the manner you suggest.

Again, thankyou for your advice and help.


Peter Webb
 
Peter Duniho said:
This isn't about what's "optimum". It's about what's correct. The world
already has plenty of crummy software. No one needs our help adding to
the list.


It's worse than quick and dirty. It's pure, unadulterated excrement.
Granted, it's just my opinion, but that opinion is that we as a community
have no business helping other people make .NET applications _worse_.
Which is just what you've done.

Note that now that Webb has a hack that appears to him to get done what he
thinks he wants done, he has no interest in making the application work
correctly before he releases it on whatever unsuspecting customers he's
got.

My "customer" is my 13 year old daughter - and, if she wants, her friends -
for who I have developed this as a Xmas present.

I had said before - and apologised before - that I was doing this for
recreational purposes, and was very conscious that I was wasting the time of
professionals. I have been and remain grateful for the assistance - its
purely because of this newsgroup that I have been able to leapfrog from 6502
assembler to C# in a month.

If there is a "hack" in my code, its because I hack the underlying physics
model to prevent step size errors from accumulating and causing instability.

So now, whatever that application does (I seem to recall something about
an orbit simulation or something),

Yes. I want to show my daughter the various stable ways a 3 body orbit can
be formed, and show the principles of slingshot acceleration caused by close
approaches. My app does that wonderfully.
anyone who wants to do anything with the application other than watch
whatever animation is going on (like, for example, exit the
application...a basic function that every user has the right to expect
from any application) isn't going to be able to do it.

Some questions are best left unanswered.

Pete

I really have appreciated your help, and I would appreciate if you responded
in future.

However, I don't know why you feel it necessary to engage in a pissing
contest with somebody who has in the last few weeks written their first
program in almost 30 years.

My "crummy little app" as you describe it unseen:

1. Does far more than I ever thought possible when I started and does a very
plausible job on small n-body problems.
2. On simple animations, runs at better than 50 frames/sec, rock steady,
admittedly on my top end home PC.
3. Implements a very well designed UI (IMHO, and designing UIs is one of the
things I do know something about). This provides stop, pause, change speed,
etc controls while the animation is running.
4. Is ready to give to my daughter for Christmas.
 
_Peter_,

Man, you're _smug_ and arrogant. I bet it's not easy going though _life_ so
smug. Yet, you seem to do it with such ease. Granted, that's just _my_
opinion, but it's probably the opinion of others as well.
have no business helping other people make .NET applications _worse_.

Maybe _you're_ the reason for lousy software. People are afraid to ask
questions for fear of being ridiculed by newsgroup bullies. Did you ever
think of that? I guess calling someone's project _excrement_ is one way to
assure that they will continue to _ask_ for help in the future. Nice going,
genius.
Some questions are best left unanswered

Maybe you should _take_ your own advice for a change. I think the _reason_
you answer so many questions is because you need approval. You want people
to _say_, "Peter, you're a genius. Thanks for you help." I bet your chest
_inflates_ every time you read something like that. _No_?
 
[...]
I really have appreciated your help, and I would appreciate if you
responded in future.

However, I don't know why you feel it necessary to engage in a pissing
contest with somebody who has in the last few weeks written their first
program in almost 30 years.

I don't see this as a pissing contest. How you get that impression, I'm
not sure. To me, a "pissing contest" implies that both people insist that
they are each superior to the other. I'm not asserting superiority,
except in the sense that I do have more experience in this type of
programming than you do. Even if you were asserting your own superiority
(and you don't seem to be), it takes two to tango.

What I do see is repeatedly having provided advice that was repeatedly
ignored. Even after you ran into problems with the wrong design, admitted
it was because of the wrong design, and were provided additional details
on how to do it right, you insisted on doing it wrong.

On top of all that, in the time you spent hacking around the wrong design,
you could have done it right and at the same time actually learned
something that would be useful in building good applications in the
future. I'm not exaggerating. It really doesn't take that much time to
do it right. It takes more time to do it wrong. Especially when you're
still learning how to do it either way.

So not only did you ignore the advice offered, you didn't save any time
doing it.

I can't speak for your 13-year-old daughter. However, part of my career
has been spent writing children's software, and the audience we had would
not appreciate software with bugs in it. They want the program to do what
it's supposed to, including behave like a normal Windows application as
appropriate.

I can't predict what might go wrong here. However, the fact is that
you've created a situation where in response to a particular event
(FormShown, apparently) you create a situation where you never return from
the event. This is antithetical to the correct operation of a Windows
application. The moment you run into a situation where the framework
expected to have completed the FormShown event and fails to do something
correctly because it never has, you're going to run into yet another
problem.

I recognize that you may be able to control the use of the application so
tightly that you never see a problem manifest itself. But I personally do
not believe that just because a program is going to be used casually, or
by a child, that that justifies not putting the same care and quality into
it that one would put in any other program. Your mileage may vary;
obviously you don't agree with that philosophy.

Mostly, however, I'm frustrated at having spent so much time trying to
answer questions about how to do it _right_, and then having all of that
information just ignored. I could have accomplished the same thing by not
replying at all.

I don't consider my time wasted if it helps people. And I don't care what
they are doing. Whether they are working on personal projects, a
commercial retail product, or just some throw-away code so that they can
learn something, I'm happy to answer questions.

But am I happy to put time and effort into explaining concepts and
details, only to have that information ignored? No. It makes me
decidedly _unhappy_.

Pete
 
Peter Duniho said:
[...]
I really have appreciated your help, and I would appreciate if you
responded in future.

However, I don't know why you feel it necessary to engage in a pissing
contest with somebody who has in the last few weeks written their first
program in almost 30 years.

I don't see this as a pissing contest. How you get that impression, I'm
not sure. To me, a "pissing contest" implies that both people insist that
they are each superior to the other. I'm not asserting superiority,
except in the sense that I do have more experience in this type of
programming than you do. Even if you were asserting your own superiority
(and you don't seem to be), it takes two to tango.


Yes, you are asserting your own superiority in this domain. Despite the fact
that I acknowledge this, I still get told what a crap job I have done, and
you still go out of your way to make me feel bad about what I have done.
What I do see is repeatedly having provided advice that was repeatedly
ignored. Even after you ran into problems with the wrong design, admitted
it was because of the wrong design, and were provided additional details
on how to do it right, you insisted on doing it wrong.

Here is the overall design advice you gave me a couple of weeks ago:

****************
It seems to me that you actually have two different issues. One is, where
to do the drawing? That is, where does your drawing code go? The other
is, how do you cause the drawing to occur?

With respect to the first question...

The PictureBox class is not for people who want to do their own drawing.
It's a convenient control to which you can attach an existing Image, and
let the control itself deal with a variety of display issues. Such as,
when to draw, if and how to scale the image, that sort of thing.

You _could_ certainly derive a new class from PictureBox and override the
OnPaint() method, but that would be sort of pointless. You can easily do
the same thing deriving from the Control class, without having all the
extra PictureBox functionality dragged along.

You could also handle the PictureBox's Paint event, but again it would be
pointless, for the same reasons.

The reason for deriving from PictureBox would be if you want to use and
extend or override functionality that is specific to the PictureBox
class. So far I haven't seen anything that would suggest that's what
you're doing or what you want.

So where should you do the drawing? IMHO, it depends on what your UI is
like, which I don't know. If you intend to manage all of the drawing
inside the form, then drawing in the form class would be a reasonable
place. If, however, you want to be able to use the VS Designer to
implement and maintain the user interface, and you want to be able to
manipulate where you custom drawing happens as part of that maintenance,
then you will probably want to create a custom Control-derived class.
That way, you'll get a custom control added to your Designer toolbox that
you can drag and drop, placing it wherever you like.

Creating a custom control is very simple, practically the same as creating
a new form class. Just add a new item to the project (using the
Project/Add New Item... menu or the Solution Explorer), and select "Custom
Control" from the template list. This will create a new class derived
from Control. In that class, you can override OnPaint() where you want to
draw.

Of course, you will want to move any other code related to managing the
graphics into that control class, or somewhere related to it. That's a
broader design question, and frankly it's much harder to answer those
questions in a newsgroup like this. Providing good advice on design
generally requires a lot of background knowledge of the problem being
solved, and not only is that background knowledge difficult to express in
this context, so too is explaining how a good design would work.

Suffice to say, a good design makes it easy to put all your pieces
together. Conversely, if you're having trouble putting the pieces
together, you should rethink the design.

Now, finally...there's the question of how to cause the drawing to occur.
The basic mechanism is invalidation of the control. In this context
"invalidation" means something very specific: to communicate to Windows
that an area of the control no longer has valid graphics and needs to be
redrawn. You use the Control.Invalidate() method to do this.

I've already explained that in this thread, and I believe that the various
links that have been posted, by myself and others, also explain it
reasonably well. The basic idea is this though: you don't draw in direct
reaction to changes in the data; you design your drawing code so that it
can always draw whatever the current state of the data is, and you
invalidate the control in reaction to changes to data.

Since you're using the BufferedGraphics class, it seems to me that this
should be especially simple. When you change the BufferedGraphics by
drawing to it, you need to call Invalidate() on whatever control it is
that you are drawing to (the Form class inherits Control as well). If you
know specifically what area of the BufferedGraphics has changed, you can
use that information to restrict the invalidated area, passing a rectangle
to the Invalidate() method so that only the part that changed winds up
getting redrawn.

*******************

I rewrote my app to do it *exactly* this way. I created a custom control
("drawBox"), put my drawing code into it, and triggered screen redraws off
the drawBox1.Invalidate() which calls OnPaint. I did exactly what you
suggested. I didn't even know you could create custom controls, and learned
a lot. It didn't actually solve the problem I had, but I know it was good
advice and so I did it. I thanked you then, and I thank you again.

On top of all that, in the time you spent hacking around the wrong design,
you could have done it right and at the same time actually learned
something that would be useful in building good applications in the
future. I'm not exaggerating. It really doesn't take that much time to
do it right. It takes more time to do it wrong. Especially when you're
still learning how to do it either way.

And that is why I am pleased that I went down your suggested route of using
OnPaint. I didn't solve my problem, but I do know how to do it next time.

So not only did you ignore the advice offered, you didn't save any time
doing it.

I spent several days implementing the suggestion you made. It took a while,
because 6502 Assembler doesn't actually contain an opcode for inhereting the
graphics functionality of base control classes, so there was a bit of a
learning curve.

I can't speak for your 13-year-old daughter. However, part of my career
has been spent writing children's software, and the audience we had would
not appreciate software with bugs in it. They want the program to do what
it's supposed to, including behave like a normal Windows application as
appropriate.

I can't predict what might go wrong here. However, the fact is that
you've created a situation where in response to a particular event
(FormShown, apparently) you create a situation where you never return from
the event. This is antithetical to the correct operation of a Windows
application. The moment you run into a situation where the framework
expected to have completed the FormShown event and fails to do something
correctly because it never has, you're going to run into yet another
problem.

I recognize that you may be able to control the use of the application so
tightly that you never see a problem manifest itself. But I personally do
not believe that just because a program is going to be used casually, or
by a child, that that justifies not putting the same care and quality into
it that one would put in any other program. Your mileage may vary;
obviously you don't agree with that philosophy.

No, I don't agree with that philosophy. This "orbital simulator" is not
going to be used to generate real orbits for NASA spacecraft, and if it was,
I would build it to higher software engineering standards. The suggestion
that I put as much "care and quality" into a toy for my 13 year old daughter
as I would for a piece of code used to calculate space shuttle launch
parameters strikes me as bizarre.

Mostly, however, I'm frustrated at having spent so much time trying to
answer questions about how to do it _right_, and then having all of that
information just ignored. I could have accomplished the same thing by not
replying at all.

You continually make two allegations that are incorrect:

1. I ignored your advice. No, I didn't. I have spent a good part of the last
two weeks completely implementing the suggestion you made above, as I have
done with previous suggestions you have made. As I said, it didn't actually
solve my problem, but it taught me a lot.

2. My app is shit because it is missing basic functionality such as the
ability to stop and pause animations, exit the program, etc. Again, this is
not correct.

I don't consider my time wasted if it helps people. And I don't care what
they are doing. Whether they are working on personal projects, a
commercial retail product, or just some throw-away code so that they can
learn something, I'm happy to answer questions.

Thankyou.

But am I happy to put time and effort into explaining concepts and
details, only to have that information ignored? No. It makes me
decidedly _unhappy_.

It wasn't.

I do need help. I don't need someone telling me that what I have done is
shit. I know that already. Its my first program in 30 years. When I started,
I didn't know that you could call "Button1" whatever you liked. I didn't
know how to attach handlers to events. I didn't know how to extract
information concerning graphic surfaces from event handler arguments. There
are large chunks where I couldn't see how to do it properly in an OO sense
(never having done any OO programming) and which would look at home in a
Fortran program. There are a mass of ad-hoc switches to hack together the
different UI modes I support. My physics model is kludged to prevent
step-size instabilities from accumulating - it seems to work properly for 2
and 3 body problems, but for all I know is completely and totally wrong for
four body problems (or even 3 body problems with boundary conditions that
impose chaotic orbits).

It doesn't really worry me that you keep telling me that what I have done is
not of professional quality. I know its not. It does annoy me that you claim
that I have ignored your advice, when I have spent considerable time doing
*exactly* what you suggested. It also annoys me that you are criticising my
program for not implementing facilities which it does in fact provide. I
don't know why you have to go out of your way to "invent" further
limitations of my program just to prove what a bad program it is, and what a
bad programmer I am. As I said before, I know its shit, and I know I am not
a good C# programmer.

Does your job involve "mentoring" less experienced staff than yourself ? I
bet they just love your motivational tactics, and your ability to publicly
criticise the functionality of applications you haven't even seen. Of
course, you don't need to see the program, the fact that I am writing my
first program in 30 years is immaterial, and just because its a Christmas
present for my 13 year old daughter doesn't excuse me from not building it
to the highest possible engineering standards. You don't even need to know
anything about what my program actually does, and what it is for, to tell me
it is shit.

Anyway, thanks for your advice to implement a drawBox class and use
Invalidate. It took a while, didn't solve my problem, but at least I (sort
of) know how I am supposed to handle redraws. My next go will have
asynchronous update and draw threads; by that time I will hopefully know
enough to make this about C# and .Net to be able to have a go (at least) of
doing it better. In the short term, I intend working out what the hell a
"delegate" is and how to use them; you have mentioned them a couple of times
and so I figure this will be a pre-requisite to me working out how to manage
multiple asynchronous threads.

Peter Webb
 
Yes, you are asserting your own superiority in this domain. Despite the
fact that I acknowledge this, I still get told what a crap job I have
done, and you still go out of your way to make me feel bad about what I
have done.

Out of my way? Hardly. I made one mention regarding my opinion of the
implementation you made, and it wasn't even directed at you. Furthermore,
the "excrement" comment I made was about a specific element of the
implementation. You're making a mountain of the molehill by incorrectly
assuming it was directed at the application as a whole.

What did I go out of my way to do? Well, other than helping in the first
place, I _did_ go out of my way to try to explain my frustration. I'm
starting to suspect that might have been wasted time as well.
[...]
I rewrote my app to do it *exactly* this way. I created a custom control
("drawBox"), put my drawing code into it, and triggered screen redraws
off the drawBox1.Invalidate() which calls OnPaint.

If you had rewritten your application in "*exactly*" the way I had
suggested, you wouldn't be calling DoEvents().

I'm willing to admit that my advice may not have clear enough to get fully
up to speed someone completely new to the Windows application model. But
there's absolutely no question that your implementation is not what I
recommended, never mind "*exactly*" what I recommended. No recommendation
of mine should ever lead to calling DoEvents().
[...]
No, I don't agree with that philosophy. This "orbital simulator" is not
going to be used to generate real orbits for NASA spacecraft, and if it
was, I would build it to higher software engineering standards. The
suggestion that I put as much "care and quality" into a toy for my 13
year old daughter as I would for a piece of code used to calculate space
shuttle launch parameters strikes me as bizarre.

Yes, I can tell that from this exchange. Unfortunately, I don't find your
own philosophy "bizarre" so much as just depressingly typical. I've seen
it far too often. But I definitely don't agree with it.

If something's worth doing, it's worth doing right. Even if it is just
for your kid.
You continually make two allegations that are incorrect:

1. I ignored your advice. No, I didn't.

Yes, you did. Like I said, my advice definitely did not include the
possibility of suspending the form's message handling, forcing you to
later call DoEvents() as a hack to get your application to work.
I have spent a good part of the last two weeks completely implementing
the suggestion you made above, as I have done with previous suggestions
you have made. As I said, it didn't actually solve my problem, but it
taught me a lot.

You could easily have spent those two weeks implementing your application
_correctly_. In this case, it has been just as hard to do it wrong as
right. Where's the value in that?
2. My app is shit because it is missing basic functionality such as the
ability to stop and pause animations, exit the program, etc. Again, this
is not correct.

There's two parts to that assertion. One has to do with the "missing
basic functionality", and I have already acknowledged that your hack of
calling DoEvents() most likely has resolved that. So you're wrong about
me "continually" making that "allegation".

The other has to do with the quality of your application, and I never said
anything about the application as a whole. So you're wrong when you say
that I "continually make" that "allegation". I haven't even made it once.

I did say it about a specific part of your application and the fact that
you have to call DoEvents() just to get some basic functionality working
is clear evidence proving that statement. So even if you narrow your
claim to that "allegation", you're wrong to say that it's an incorrect
one, even if it is an "allegation" I make repeatedly.

Which is a long way of saying that your allegation of me making incorrect
allegations is itself incorrect.
[...]
I don't know why you have to go out of your way to "invent" further
limitations of my program just to prove what a bad program it is, and
what a bad programmer I am. As I said before, I know its shit, and I
know I am not a good C# programmer.

I have made no statements at all regarding your quality or ability as a
programmer. If you choose to infer something, don't put that on me.

So, how about whether or not the program itself is "bad"? I'm making what
I feel are reasonably objective statements about a _specific part_ of the
program itself. In my frustration I have used what some would call
"undiplomatic language", but other than that it would be hard to overstate
how poorly implemented I feel that part of your program is. And I never
said anything about the program as a whole.

As far as me "inventing" limitations...the facts are clear here: in the
process of handling a window message, your code never returns from the
code that's supposed to handle that window message. Do I know what
exactly could go wrong? No, I admit that I don't, not off the top of my
head. But it is a horrible design choice, and one that can easily cause
problems. In the chain of handling a window message, lots of things
happen, some of them before your code gets called and some of them after.
With your design, any of the "after" stuff just doesn't happen.

I haven't "invented" anything.
Does your job involve "mentoring" less experienced staff than yourself ?

I actually do have a fair amount of experience mentoring and teaching over
the years. But I have the luxury of only having to help people who are
receptive to the advice offered and of defining the terms under which my
advice is offered. I would never, for example, let one of the high school
students I've worked with turn in a programming assignment in which they
failed to adhere to the standard Windows messaging model in the way you've
done here.
I bet they just love your motivational tactics, and your ability to
publicly criticise the functionality of applications you haven't even
seen.

Well, aside from the fact that my personal interactions are practically
never public, I have in fact used strong words to describe code that I've
seen. Most people I deal with don't invest their own sense of personal
worth in the code they write, especially when they know already that the
code isn't good. So it doesn't concern them at all when I describe the
code in ways that they already know are true, even if I'm not diplomatic
about it.

I've offended the occasional person, yes. And I do know a number of
people who are _much_ better at dealing with their frustrations than I
am. But most of the time, there's no conflict at all; most of the people
I'm dealing with accept and implement my advice just as I've suggested it,
without leaving me with any frustration at all. I get along just fine
with those people and they keep coming back for more.
Of course, you don't need to see the program, the fact that I am writing
my first program in 30 years is immaterial, and just because its a
Christmas present for my 13 year old daughter doesn't excuse me from not
building it to the highest possible engineering standards. You don't
even need to know anything about what my program actually does, and what
it is for, to tell me it is shit.

Frankly, this isn't about "the highest possible engineering standards".
It's about the fact that the part of the program I commented on meets
practically the lowest possible engineering standards possible with a .NET
application that actually does something. That fact is demonstrably
correct.

I'm sorry you're taking it so personally. I'm sorry you've made the
incorrect inference that I'm commenting on the application as a whole.
I'm especially sorry that you don't see the value in putting care into
something done even on a whim. That reaction and that attitude don't bode
well for the chances of you putting real care into your programming at any
time. Would that make you unusual? No, I doubt it. But I don't make any
apologies for my own frustration in the matter; my only active
contribution to that situation was my own attempt to help, and I don't
think that was a bad thing.

Pete
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Back
Top