Solved

Bitblt Chart in Hidden Window

Posted on 2001-08-04
18
554 Views
Last Modified: 2007-10-18
I want to make a flicker-free chart that is updated rapidly.  I was able to make a chart side-by side with a picture box.  The chart is updated and flickers and I used Bitblt to copy the contents of the chart window to the picture box and it looked great.  I thought I had it but then when I try to hide the chart control, it doesn't work any more.  The bitblt copies the contents of the screen "under" my invisible chart rather than the chart itself.  I'm not sure if this whole idea makes sense but I sure would love to get it working.  Can anyone help me on this?
0
Comment
Question by:tomapo
  • 8
  • 5
  • 3
  • +2
18 Comments
 
LVL 38

Expert Comment

by:PaulHews
ID: 6352672
Have you tried putting the chart way off screen without hiding it?  Set the left property to a very large value. (30000)
0
 
LVL 27

Expert Comment

by:Ark
ID: 6352697
Hi
.Visible = False
.Autoredraw = True

And in BitBlit try to use not Picture1.hDC, but GetDC(Picture1.hWnd) - they are different.

Cheers
0
 

Author Comment

by:tomapo
ID: 6352739
Both good ideas but I had no luck. When I tried moving mschart1 left to 30000 it was the same as when mschart1 is invisible. When I moved it to 5000 it copied a rectangle from my screen into the picturebox. Also I tried the other suggestions. Here is my test program which maybe can show what I did.  Maybe I need to somehow get the chart to write to a different device context. Maybe I can use SetParent to do that?  Or probably I need a different idea.  Thank you.  

Option Explicit
Private Declare Function BitBlt Lib "gdi32" _
    (ByVal hDestDC As Long, ByVal x As Long, ByVal y As Long, _
    ByVal nWidth As Long, ByVal nHeight As Long, _
    ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, _
    ByVal dwRop As Long) As Long
Private Declare Function GetDC Lib "user32" _
    (ByVal hwnd As Long) As Long
Private Sub cmdCopy_Click()
    BitBlt GetDC(Picture1.hwnd), 0, 0, _
        Picture1.Width / Screen.TwipsPerPixelX, _
        Picture1.Height / Screen.TwipsPerPixelY, _
        GetDC(MSChart1.hwnd), 0, 0, vbSrcCopy
End Sub
Private Sub cmdHide_Click()
    MSChart1.Visible = Not MSChart1.Visible
    MSChart1.Repaint = True
    Picture1.AutoRedraw = True
End Sub
Private Sub Form_Resize()
    cmdHide.Top = ScaleHeight - cmdHide.Height - 100
    cmdCopy.Top = ScaleHeight - cmdCopy.Height - 100
    MSChart1.Move 0, 0, ScaleWidth / 2, ScaleHeight - cmdHide.Height - 200
    Picture1.Move ScaleWidth / 2, 0, ScaleWidth / 2, ScaleHeight - cmdHide.Height - 200
End Sub
0
 
LVL 22

Expert Comment

by:CJ_S
ID: 6352826
Might be a pretty stupid suggestion, but it helped me in the past. How about a second form with the MSChart control on it. All you do is Load the form, but not show it. On that form you keep the control visible... That did work for me in the past.

Some code:
Dim x as thenewform
Set x = new thenewform
Load x

of couse you need to have a reference to the MSChart control, you can either expose that through a property which returns you the hDC.

Public Property Set ChartHDC() as hDC
    Set ChartHDC = GetDC(MSChart1)
End Property

Not sure if you need Set for an hDC though...:-/

Regards,
CJ

0
 

Author Comment

by:tomapo
ID: 6352847
Not a stupid suggestion at all. I appreciate your thinking about it.  But I just tried it and it doesn't seem to work.  I've been reading up and what I think is happening is that the device context of the mschart window is tied into the physical screen.  Whatever is showing on the screen seems to be what is picked up. I think I have to get the chart to draw using a different (memory) device context and then use that as the source of by bitblt.  But I don't know how to do this.  I also appreciate other ideas.  That is just my current idea.  
0
 
LVL 22

Expert Comment

by:CJ_S
ID: 6352976
Doesn't make sense. Every control is a seperate window (in windows, underlying the programming language), and thus it should not be tied to the main form.

Your thought about creating a memory dc is a pretty good one. The following is the approach of creating a memory device context:

HDC hMemDC = CreateCompatibleDC(0)

If you want to write to that dc as if it were a bitmap you will need to create device independ bitmap (DIB). You can do that using the CreateDIBSection API function. Once you have established the DIB section you can select the bitmap into the memory dc using the SelectBitmap API function. Then it is all a matter of BitBlt.

If you need additional help, just ask.

regards,
CJ
0
 

Author Comment

by:tomapo
ID: 6353770
Thanks for taking the time to help me. I think I've made some progress but I'm still stuck.  I added the following to the test program:

    Dim hdcMem As Long, hbmMem As Long, hbmOld As Long
    hdcMem = CreateCompatibleDC(GetDC(MSChart1.hWnd))
    hbmMem = CreateCompatibleBitmap(GetDC(MSChart1.hWnd), MSChart1.Width / Screen.TwipsPerPixelX, MSChart1.Height / Screen.TwipsPerPixelY)
    hbmOld = SelectObject(hdcMem, hbmMem)
    Dim ucA As UserControl
    Set ucA = MSChart1
    ucA.hdc = hdcMem   **** FAILS - READ ONLY PROPERTY

I think I've created the memory DC OK but how do I convince MSChart to use it?  Maybe I should create a window that somehow refers to my new memory DC.  Then I can use the setparent API call to move the control into that window.  But how can I create a window that uses my new DC? Is there someway to change the device context of a user control?  
0
 
LVL 22

Expert Comment

by:CJ_S
ID: 6354027
I'm sorry, but you cannot assign a device context to any control. And thus that idea is not going to work out.

I am somewhat lost in what exactly should be done. Could you perhaps tell me exactly (in steps) what you want to achieve. I cannot get a full grasp on it...

Regards,
CJ
0
 

Author Comment

by:tomapo
ID: 6354981
Well, I'm trying to get a chart control to create a chart in the background where the user can't see it.  Then I want to use Bitblt to copy that chart to a visible window.  All the other stuff I mentioned was just different half-formed ideas on possible ways to do that.  
0
Better Security Awareness With Threat Intelligence

See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

 

Author Comment

by:tomapo
ID: 6354989
I'll offer an additional 150 points (under another question) for a total of 400 if I can get this working.  
0
 
LVL 22

Expert Comment

by:CJ_S
ID: 6355005
Will see what I can do here to test in about an hour or so.
0
 
LVL 30

Accepted Solution

by:
Zoppo earned 250 total points
ID: 6355432
Hi tomapo,

maybe it works to send the control a WM_PRINT message with handle to your memDC as wParam...

ZOPPO
0
 

Author Comment

by:tomapo
ID: 6356780
Zoppo, that is a great idea!  I just ran a quick test using visible picture boxes and have not been able to get it to work yet but I'm going to try it with a memory DC. Do you have an example in VB or C?  Here is what I tried so far.

Private Declare Function SendMessage _
    Lib "user32" Alias "SendMessageA" _
    (ByVal hwnd As Long, ByVal wMsg As Long, _
    ByVal wParam As Long, lParam As Any) As Long
Private Declare Function GetDC _
    Lib "user32" (ByVal hwnd As Long) As Long
Private Const WM_PRINT = &H317
Private Const PRF_CHECKVISIBLE = &H1
Private Const PRF_NONCLIENT = &H2
Private Const PRF_CLIENT = &H4
Private Const PRF_ERASEBKGND = &H8
Private Const PRF_CHILDREN = &H10
Private Const PRF_OWNED = &H20
Private Sub Form_Resize()
    Picture1.Move 0, 0, ScaleWidth / 2, ScaleHeight
    Picture2.Move ScaleWidth / 2, 0, ScaleWidth / 2, ScaleHeight
End Sub
Private Sub Picture2_Click()
    SendMessage Picture1.hwnd, WM_PRINT, GetDC(Picture2.hwnd), PRF_ERASEBKGND
End Sub
0
 

Author Comment

by:tomapo
ID: 6357919
Zoppo, thanks for the shove in the right direction. What group do you want the other 150 points in? CJ and others - thanks very much for your assistance too.  Here is my working test program for anyone interested.

Private Const WM_PAINT = &HF
Private Const WM_PRINT = &H317
Private Const PRF_CLIENT = &H4&
Private Const PRF_CHILDREN = &H10&
Private Const PRF_OWNED = &H20&
Private Declare Function SendMessage Lib "user32" Alias _
   "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, _
   ByVal wParam As Long, ByVal lParam As Long) As Long
Private Sub Form_Resize()
    Me.Caption = "Click Below To See Chart"
    MSChart1.Visible = False
    MSChart1.Move 0, 0, ScaleWidth, ScaleHeight
    Picture1.Move 0, 0, ScaleWidth, ScaleHeight
End Sub
Private Sub Picture1_Click()
    With MSChart1
        .AutoIncrement = True
        .chartType = VtChChartType2dLine
        .DoSetCursor = False
        .Plot.Axis(VtChAxisIdX).AxisGrid.MajorPen.Style = VtPenStyleNull
        .Plot.Axis(VtChAxisIdX).Tick.Style = VtChAxisTickStyleNone
        .Plot.Axis(VtChAxisIdY).ValueScale.Auto = False
        .Plot.Axis(VtChAxisIdY).ValueScale.Maximum = 1
    End With
    Dim r As Double
    For r = 1 To 4 Step 0.05
        DrawChart 100, r, 0.2
    Next r
End Sub
Private Sub DrawChart(n As Integer, r As Double, ByVal x As Double)
    With MSChart1
        .ColumnCount = 1
        .RowCount = n
    End With
    Dim k As Integer
    For k = 1 To n
       MSChart1.Data = x
        x = r * x * (1 - x)
        DoEvents
    Next k
    Picture1.AutoRedraw = True
    SendMessage MSChart1.hwnd, WM_PAINT, Picture1.hDC, 0
    SendMessage MSChart1.hwnd, WM_PRINT, Picture1.hDC, PRF_CHILDREN + PRF_CLIENT + PRF_OWNED
    Picture1.Picture = Picture1.Image
End Sub
0
 
LVL 30

Expert Comment

by:Zoppo
ID: 6358389
You're welcome, tomapo, but there's not really a need to offer me more points for
such a one-line-'maybe...'-comment ... I'm glad I could help you.

have a nice day,

regards,

ZOPPO


(PS: If this can't get you off from giving me points then please do it in MFC topic area)
0
 
LVL 22

Expert Comment

by:CJ_S
ID: 6358440
The question is related to VB, and therefore the points should also be given in the VB area.

I'm just glad you got it to work, I haven't had the time yesterday to try it out anyway...:-/

Regards,
CJ
0
 
LVL 30

Expert Comment

by:Zoppo
ID: 6358504
>The question is related to VB
Well, I think this is more a general windows-programming related question
since MSFlexGrid and WM_PRIN message somehow related to VB only ... this
solution as I suggested is available for most other language too.

But, BTW, it doesn't matter for me since as I told I don't think I deserved these
points.

ZOPPO
0
 

Author Comment

by:tomapo
ID: 6358902
Well, thanks to you both.   It was important to me to get this worked out.  And CJ, I really do appreciate your help and the service people like you and Zoppo freely offer. I know the points are just a token of the help you've given to others on this site.

Thanks again!
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

This article describes some techniques which will make your VBA or Visual Basic Classic code easier to understand and maintain, whether by you, your replacement, or another Experts-Exchange expert.
You can of course define an array to hold data that is of a particular type like an array of Strings to hold customer names or an array of Doubles to hold customer sales, but what do you do if you want to coordinate that data? This article describes…
Get people started with the process of using Access VBA to control Excel using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Excel. Using automation, an Access application can laun…
Get people started with the utilization of class modules. Class modules can be a powerful tool in Microsoft Access. They allow you to create self-contained objects that encapsulate functionality. They can easily hide the complexity of a process from…

706 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now