0

My user-control is intended to operate as a smooth vertical text scroller. It renders the text (to be scrolled) to control's surface only once, using TextRenderer.DrawText. It then starts a timer, which upon each of its ticks, Bit-Blits (BitBlt) the entire client-rectangle one pixel up. control's device-context is both the source and the destination of the BitBlt operation, as follows:

Protected Sub handleTimerTick(ByVal sender As System.Object, ByVal e As System.EventArgs)
    Dim oG As Graphics = Me.CreateGraphics()
    Dim sHdc As IntPtr = oG.GetHdc()
    Dim iRes As Integer = BitBlt(sHdc, 0, 0, Me.ClientRectangle.Size.Width, Me.ClientRectangle.Size.Height, sHdc, 0, 1, SRCCOPY)
    oG.ReleaseHdc(sHdc)
    oG.Dispose()
End Sub

This successfully accomplishes the desired scroll effect, BUT only if my control's background is a solid-color (e.g. Me.BackColor = Color.Gray).

If I set a picture as control's background, BitBlt scrolls the background along with the text displayed over it. Ofcourse, I'd like only the text to be scrolled, and the background image to remain static.

I have found the following thread, which suggests using TransparentBlt instead of BitBlt where the background is a solid uniform color to be ignored : How to copy with BitBlt?

The solution suggested there would not be suitable to the case on hand, in which a colorful background is used.

Please note that the text itself is of a solid uniform color.

Your advice would be much appreciated. If it is of any matter, I'm using VB.NET 2005.

Cœur
  • 37,241
  • 25
  • 195
  • 267
Bliss
  • 426
  • 2
  • 5
  • 19
  • 1
    Though it's separate from the question you're asking, you're likely to run into problems using the same DC as both the source and the destination. This is like trying to move memory within a buffer, as you have to be very careful about what order you overwrite in order to avoid smearing in the overlapping region. You probably should render the text to a memory DC once, and then blit it to the control's DC as needed. – Adrian McCarthy Jul 07 '13 at 14:57

1 Answers1

1

If the background is supposed to stay fixed while the text moves around on it, I would suggest that you maintain two separate bitmaps: one that contains the background image, and a second one that contain the text on a transparent background.

Then, on each timer tick, you draw the background bitmap first and then draw the text bitmap at the desired offset position.

I don't understand why you need to P/Invoke the BitBlt function for this. What's wrong with the equivalent GDI+ function, wrapped by the .NET Framework already as Graphics.DrawImage?

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
  • Thanks much Cody for your answer. `Graphics.DrawImage` seems to consume much more CPU cycles. I assume it does not use Hardware-acceleration (i.e. it uses the CPU instead of the GPU). Besides, `TextRenderer.DrawText` has different performance when target-DC is a control-surface and a bitmap, so I must render the text directly to a surface rather than to a bitmap. Could you please elaborate a little about your 1st suggestion? I've tried bit-blitting from a bitmap to control's surface, but a black rectangle is drawn... – Bliss Jul 07 '13 at 11:01
  • I'm pretty sure all of those problems come from mixing GDI and GDI+. I've never seen `TextRenderer.DrawText` exhibit different behavior whether it's drawing onto a control surface or a bitmap. If anything, drawing onto a off-screen bitmap should be faster. – Cody Gray - on strike Jul 07 '13 at 11:10
  • Thanks Cody. The only GDI/GDI+ function I'm using is TextRenderer.DrawText, and no other. By "different performance" I was referring to difference in rendered text's quality. I indeed implemented the scroller using TextRenderer.DrawText, rendering the text directly to control's surface, and it works very well, but consumes rather much CPU time. – Bliss Jul 08 '13 at 16:30
  • I've implemented the solution you suggested, bit-blitting 2 separate bitmaps onto control's surface - one background bitmap, and another - rendered-text bitmap. Bit-blitting is performed within ticker's tick-handling-function and **not** within the `OnPaint` event-handler (which draws nothing). This indeed works (text is scrolled over the desired background image), **but the *text* flickers frequently**. Can you tell why? – Bliss Jul 09 '13 at 12:57
  • @Bliss Probably because you're drawing directly onto the control. The typical way of solving flicker is to add a second off-screen bitmap to use as a buffer. You draw the intermediate items into this buffer to build the image, and then blit that entire buffer onto your control. It's called "double buffering", perhaps you've heard of it? You say that this is slower. I can't imagine how, but I can't argue with that. – Cody Gray - on strike Jul 10 '13 at 01:46