0

Alright I'm using a timer with a 50 ms elapse time to animate some moving text (technically its scrolling between text).
Problem is, if you look closely, you can see the text flickering, and id like it not to flicker..

So i'm not that good with animation but is there something I can do to reduce flickering? Maybe a faster elapse time? Or should I even be using a timer for this at all?

EDIT:
So i've tried to implement double buffering, and i'm obviously doing something.

Here is the code without double buffering, this works fine but flickers a little.

void PaintScrollingText(ScrollingText *Settings, WPARAM wParam)
{
    HDC hdc;
    PAINTSTRUCT ps;
    HANDLE hOldFont;
    RECT rect;

    hdc = wParam ? (HDC)wParam : BeginPaint(Settings->hWnd, &ps);

    hOldFont = SelectObject(hdc, Settings->hFont);

    SetTextColor(hdc, Settings->crForeGnd);
    SetBkColor(hdc, Settings->crBackGnd);

    GetClientRect(Settings->hWnd, &rect);

    rect.right -= Settings->txt1XOffset;
    DrawText(hdc, Settings->szText1, -1, &rect, DT_RIGHT);

    rect.right += Settings->txt1XOffset - Settings->txt2XOffset;
    DrawText(hdc, Settings->szText2, -1, &rect, DT_RIGHT);

    SelectObject(hdc, hOldFont);

    if (!wParam) EndPaint(Settings->hWnd, &ps);
}

And this is my code, with double buffering.

void PaintScrollingText(ScrollingText *Settings, WPARAM wParam)
{
    HDC hdc;
    PAINTSTRUCT ps;
    RECT rect;

    GetClientRect(Settings->hWnd, &rect);

    hdc = wParam ? (HDC)wParam : BeginPaint(Settings->hWnd, &ps);

    // Create off-screen DC
    HDC hdcMem = CreateCompatibleDC(hdc);

    // Create a bitmap to draw on
    HBITMAP MemBitmap = CreateCompatibleBitmap(hdc, rect.right - rect.left, rect.bottom - rect.top);

    // Select bitmap into off-screen DC
    HGDIOBJ OldBitmap = SelectObject(hdcMem, MemBitmap);

    // Erase background
    HBRUSH hbrBkGnd = CreateSolidBrush(0x000000);
    FillRect(hdcMem, &rect, hbrBkGnd);
    DeleteObject(hbrBkGnd);

    // Set font and color
    HGDIOBJ hOldFont = SelectObject(hdcMem, Settings->hFont);
    SetTextColor(hdcMem, Settings->crForeGnd);
    SetBkColor(hdcMem, Settings->crBackGnd);

    // Draw text
    rect.right -= Settings->txt1XOffset;
    DrawText(hdcMem, Settings->szText1, -1, &rect, DT_RIGHT);

    rect.right += Settings->txt1XOffset - Settings->txt2XOffset;
    DrawText(hdcMem, Settings->szText2, -1, &rect, DT_RIGHT);

    // Blt the changes to the screen DC.
    BitBlt(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, hdcMem, 0, 0, SRCCOPY);

    // Select old font
    SelectObject(hdcMem, hOldFont);

    // Done with offscreen DC and bitmap
    SelectObject(hdcMem, OldBitmap);
    DeleteObject(MemBitmap);
    DeleteDC(hdcMem);

    if (!wParam) EndPaint(Settings->hWnd, &ps);
}

The first text is printed fine, but the second one looks like this:

And here is the complete code without the double buffering: http://dl.dropbox.com/u/35314071/ScrollingTextClass.zip
And here is the complete code with the double buffering: http://dl.dropbox.com/u/35314071/ScrollingTextClass2.zip

Josh
  • 6,046
  • 11
  • 52
  • 83
  • 2
    how are you displaying the text. Show us the code. – David Heffernan Oct 06 '11 at 21:42
  • 6
    The most common problem arises from re-drawing the background, then drawing new text over it -- the background without text creates something like looks a lot like a small flash. Obvious cures include double buffering, and ScrollWindow to scroll the text that's already on-screen and only new draw enough to "fill in" the parts that aren't yet on screen. – Jerry Coffin Oct 06 '11 at 21:57
  • 1
    Tearing is hard to fix with scrolling text. The effect is perceived as flicker, even though it has nothing to do with it. – Hans Passant Oct 06 '11 at 23:46
  • @Jerry - that's an answer, not a comment. OK, it could be padded out a bit. – Skizz Oct 07 '11 at 08:20
  • Regarding your latest edit, I'd say your `Settings->szText2` is not null terminated. – Mark Ransom Oct 07 '11 at 16:48
  • @MarkRansom but if I use the original code, without the double buffering, there is no problems. So there is some problem with my double buffering implementation. – Josh Oct 07 '11 at 22:31
  • @Josh, you haven't shown us your code without the double buffering so there's no way we can compare. You have two nearly identical calls to `DrawText`, and you say one works and the other doesn't. The only explanation I can think of, and one that matches the symptoms nicely, is that by using `-1` for the string length it's going past the end of what you believe to be the string. Running it in a debugger should point to the problem immediately. – Mark Ransom Oct 07 '11 at 22:44
  • @MarkRansom In my first edit I provided a link to the full code, it's not that much so finding the `PaintScrollingText` function should not be hard. EDIT: Added the code – Josh Oct 10 '11 at 03:29
  • 2
    Since you specified a black brush for your background, and you did not override WM_ERASEBKGND, there is a flicker between the time the window manager erases your background and the time you draw the text. – Raymond Chen Oct 10 '11 at 22:00
  • @RaymondChen I returned 1 on `WM_ERASEBKGND` in my code, forgot to mention that. – Josh Oct 10 '11 at 22:11
  • 1
    @Josh, in which case please update the code in the zip file. The code in the zip file does not handle `WM_ERASEBKGND`. – Raymond Chen Oct 10 '11 at 22:51
  • @RaymondChen Updated. http://dl.dropbox.com/u/35314071/ScrollingTextClass2.zip – Josh Oct 10 '11 at 22:59

1 Answers1

6

Okay, I debugged the program (it's amazing what you can find if you just step through the code line by line), and at the point where you call BitBlt, you pass the parameters

BitBlt(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, hdcMem, 0, 0, SRCCOPY); 

Inspection of the values in the debugger shows that rect.right - rect.left is not the full size of the window but only part of it because you still have the value in rect.right left over from the line

rect.right += Settings->txt1XOffset - Settings->txt2XOffset;  

You forgot to set rect.right back to its original value.

rect.right += Settings->txt2XOffset;
Raymond Chen
  • 44,448
  • 11
  • 96
  • 135
  • 1
    Another bug is your `FillRect` and `DrawText` calls are all assuming that `rect.left` and `rect.top` are both zero. Fortunately, they are, but if you're going to assume that they are always zero, then you don't need to subtract them all the time. – Raymond Chen Oct 11 '11 at 02:55