0

I've got the following problem: I'm drawing a high-resoultion real-time graph. I fetch a floating-point value in my main loop and I want do draw this value to an existing instance structure (It is the graphics instance of the form).
To do this I must translate the whole graphics content by 1 in x-direction to draw my new point. The problem is, that the translation seems to effect the new points, but not the existing content.

The code (shortened) looks like this:

float oldval = 0;
Graphics gr = this.CreateGraphics();

public void IndependentThread(...)
{
    float h = (float)this.Height;
    Pen p = Pens.Pink;

    while (condition_to_exit_loop)
    {
        float current = 0;

        this.Invoke(new MethodInvoker(() => current = getVal())); //<-- funtion witch fetches the current value

        gr.TranslateTransform(1, 0); //<--- I want to translate the existing content - not the new one
        gr.DrawLine(p, 0, h * current, 1, h * oldval);

        oldval = current;
    }
}
unknown6656
  • 2,765
  • 2
  • 36
  • 52
  • 1
    Sounds as if you believe the `Graphics` class actually __contains__ the graphics. __It does not__. It is just the object you __use__ to draw onto a __bitmap__! (In your example onto `this`, whatever that is, the `form` or a class..) – TaW Jan 11 '15 at 10:17
  • @TaW : Yes - I you're right - I thought, the Graphics class would contain the current graphics information which could be changed :/ Do you know how I could achieve the effect of the existing graphics to be translated? – unknown6656 Jan 11 '15 at 10:31
  • Hm, shifting bitmaps around is not without its own problems. Why do you think you need the translation in the first place? Does it change? Can't you phase it into the Drawing code? – TaW Jan 11 '15 at 10:39
  • 1
    There are a lot of issues. CreateGraphics is wrong: minimizing your form and restoring it will erase everything. You need to override the form's OnPaint method and use the graphic that is provided. There, you either redraw all your points or update a bitmap and draw the results of that to the form. Your thread is going to cause problems with sending too many updates to the form. You are better off using a timer. – LarsTech Jan 11 '15 at 10:57
  • @LarsTech : I used a timer in the first place, but it was not fast enough (even with `.Interval = 1;`). My application runs in fullscreen mode, so minimizing will not be an issue. Even if i override the Paint-method - I will have the same problem as before, won't I? – unknown6656 Jan 11 '15 at 11:07
  • @TaW : I need a translation, because I draw a point `P(1| f(t-1) )`, then translate the whole content to the right and draw my next point at `P(1| f(t) )`. I cannot use bitmaps because they are to slow (I think) – unknown6656 Jan 11 '15 at 11:12
  • 1
    The transform you set on a `Graphics` object affects the drawing commands that come after it, not what has alread been drawn. Turn your logic around and draw your stuff in the right place from the start instead of trying to move it later. Also, since you only seem to drawing single lines, just change the coordinates of those instead of messing with transforms. And drawing from another thread like that seems like a really bad idea. – Chris Jan 11 '15 at 11:21
  • @Chris : my aim is to have something like a graph, which begins on left side of the form and moves to the right over time - If you know what i mean. And therefore I must do some sort of translation/animation over time. – unknown6656 Jan 11 '15 at 11:25
  • @Unknown6656 Instead of thinking of it as a persistent image that you move and add to, think of it like you're drawing what the graph would look like at a specific point of time (when you update). Your way is certainly possible too, but not the way you're doing it. You'd need offscreen buffers and alot of other stuff, and I don't think it will be any faster. – Chris Jan 11 '15 at 11:37
  • 1
    _I used a timer in the first place, but it was not fast enough (even with .Interval = 1;)_ Anything faster than 20ms is too fast, both for display and for perceiving it. - For fastest drawing use optimized drawing code, e.g. collect a few lines and use DrawLines (plural). Also decide if you want live drawing or if you want to draw into a persistent Bitmap. (See [here](http://stackoverflow.com/questions/27337825/picturebox-paintevent-with-other-method/27341797#27341797) for these two options!) – TaW Jan 11 '15 at 11:39
  • 2
    _application runs in fullscreen mode, so minimizing will not be an issue_ Wrong!. There are many other occasions where non-persistent drawing is destroyed, e.g. popups, messageboxes etc.. Always avoid it for anything. (Except for short-lived mouse ornamentations) - _Even if i override the Paint-method - I will have the same problem as before, won't I?_ Right. Therefore you must solve it, either by collecting the drawing data and refreshing the drawing whenever needed or by drawing into a persistet bitmap.. – TaW Jan 11 '15 at 11:45
  • _I need a translation, because I draw a point P(1| f(t-1) )_ Huh??? How does that make sense? Why not increment the x coordinate? Translating the Graphics is most often done to prepare a rotation around a point other than the origin.. – TaW Jan 11 '15 at 11:49
  • @TaW: I updated my code and used a `Queue` to store the values and I let GDI+ draw the lines from the entries in the Queue. I used a timer - but it is not (yet) as fast as i want it to be... I will try to optimize my code. – unknown6656 Jan 11 '15 at 12:56
  • Good. So you traverse the Queue in the Paint event and call Invalidate in the Timer.Tick? Unless you need to remove points a List may be preferrable to a Queue. How and where are those values generated? – TaW Jan 11 '15 at 12:59
  • @TaW : The values are real-time audio values fetched with the audiocore-library in the Tick-event. I remove values after a certain ammount, because these values are outside the client area. I used the Queue because you add the values on one side and remove them on the other side, which is convenient, because I can use `Queue.Enqueue()`/`.Dequeue()` instead of `List.Add()` and `List.RemoveAt(0)`. – unknown6656 Jan 11 '15 at 13:08
  • 1
    Ah, I see. I that case making the Tick fast makes sense (although the real precision possible is much less than 1ms as the Intervall suggests.!!). But don't try to Invalidate faster than one could see it (16-25Hz).. – TaW Jan 11 '15 at 13:19
  • @TaW : I know, that even if the Interval is set to 1 it will have a freq. of about 20Hz – unknown6656 Jan 11 '15 at 13:29
  • 1
    You may want to have a look [here](http://stackoverflow.com/questions/9228313/most-accurate-timer-in-net) as your problem seems to call for a precision timer. Just remember that pulling the data and displaying them are two different issues.. Good luck! – TaW Jan 11 '15 at 13:39

0 Answers0