GRAPHICS

  • Thread starter Thread starter ZGALUS
  • Start date Start date
Z

ZGALUS

Hello,

I'm using VBA Forms in a VB program to design graphs. The
purpose is to make a kind of slide show with dynamically
generated graphs.
VB Form uses Application OLE« Graphic Microsoft Graph 97 »
with a class object « MSGraph.Chart.8 ».
« GRAPH8.EXE » a process handles the generation and
projection of the graph into the open active FORM.
The image of the graph appears only when the VB program
monitoring the execution ends.

It means that in a loop if I generate successive images
they do not appear unless I quit all programs with the
last instruction done.
Then I can see all the images that start filling the empty
FORMs generated in a loop.
My question is:
How to make the images (graphs) appear successively one by
one in a loop?
As a matter of fact if in a VB program I open a FORM with
a generated graphic, delay a little bit and close it
afterwards I never see the image unless the program stops.
The process « GRAPH8.EXE » even doesn't start.

I've tested it on Windows 98, Windows XP and WINDOWS NT
with VB ACCESS

Your help will be of great use for me
Sincerely
Zbigniew GALUS ([email protected])
 
Hi,


Do you have a DoEvents in your loop? Painting messages are generally
delayed to a time where there is nothing else left, to be done, with timers,
at a given priority.


Private Sub Command1_Click()
Dim i As Long
For i = 1 To 100
Me.Label0.Caption = i
' DoEvents
Next i

End Sub



will just display 100. Uncomment the DoEvents line, and the numbers 1 to
100 should appear, quite fast, but each should (unless you move the mouse
too fast, or some high priority process suddenly occur). DoEvents "help" to
be in a state where the computer would find nothing more to be done, at a
moment, and so, the painting message on the monitor would be considered.

When there is something else to be done and a painting message occur,
the "painting area to be modified" is merged with whatever "painting area"
is already pending. Note that just the message to paint, and the rectangle
to paint, NOT WHAT to paint is remembered. Without DoEvents, there is
something else to do, like running the VBA code, so the 100 paintings are
merged in just one, and we get only the final message ( the 99 others having
been "lost", merged) and the "dirty" area is finally asked to repaint
itself. At THAT moment, the WHAT to display is found to be to be display
"100".


Could be the same for your graph.


Hoping it may help,
Vanderghast, Access MVP


Hello,

I'm using VBA Forms in a VB program to design graphs. The
purpose is to make a kind of slide show with dynamically
generated graphs.
VB Form uses Application OLE« Graphic Microsoft Graph 97 »
with a class object « MSGraph.Chart.8 ».
« GRAPH8.EXE » a process handles the generation and
projection of the graph into the open active FORM.
The image of the graph appears only when the VB program
monitoring the execution ends.

It means that in a loop if I generate successive images
they do not appear unless I quit all programs with the
last instruction done.
Then I can see all the images that start filling the empty
FORMs generated in a loop.
My question is:
How to make the images (graphs) appear successively one by
one in a loop?
As a matter of fact if in a VB program I open a FORM with
a generated graphic, delay a little bit and close it
afterwards I never see the image unless the program stops.
The process « GRAPH8.EXE » even doesn't start.

I've tested it on Windows 98, Windows XP and WINDOWS NT
with VB ACCESS

Your help will be of great use for me
Sincerely
Zbigniew GALUS ([email protected])
 
hi,
"DoEvents" is ignored by XP. So there aws no effect on
display.
I used a delay (through timer) to "give" the program
necessary time to show the graph into the form with no
result.
You just see the forms with no graphs.
GRAPH8.EXE is a seperate process and it starts only when
VB is done with its last line.
So in a loop if I
(1)open a form with a graph,
(2) delay five second (or use DoEvents to let it have done)
(3) close the form
..... iterate through other forms with graphics
I never ses a graphic but empty forms sliding one by one

DoEvents worked properly with Windows 3.1
and when we migarted to NT4 we had to remove it from the
programs as the behaviour was very unexpected.
Likein your example we had :
"Me.Label0.Caption = i"
appear in anunexpected moment.
I'm lucky to talk to you and I hope to fine the way
Sincerely

Zbigniew GALUS (zgalus)
 
Hi,


DoEvents is not necessary to insure multi-tasking but it is NOT ignored.

Timer and Painting are BOTH delayed unless there are nothing else to be
done. Adding a Timer won't solve anything since it is also "pushed back",
like the paint message. That is what I meant by "delayed to a time where
there is nothing else left, to be done, with timers, at a given priority"
(which is poorly formulated, now that I reread it). So, putting something in
a timer won't help at all in that case. A SLEEP won't help either, since it
is the whole VBA thread that goes to sleep.

DoEvents in WFW3.11 has not the same notion. Here, since VBA is single
thread, DoEvents "pause" the VBA thread so that other messages (with the
same priority) can be handled. In WFW3.11 DoEvents is required to insure
other tasks (not threads) can have a CPU time execution.


Sure DoEvents can be some "evil" since it adds uncertainty for the
thread-flow of execution, but here, for immediate painting, it is required.
It is also far less "evil" than under WFW3.11 since you can be sure to get
CPU attention "back" to you under W9x and NT (while you can be starve
indefinitely, after you use a DoEvents, under WFW 3.11). In fact, if you
add a timer you add even more problems, since the two "low" messages, Timer
and Paint, may interact in a very poor manner.


Have you do something like "trying" it? I am running XP Pro and, on an
Intel 2.6MHz HT, YES, there IS a MAJOR difference in the code I posted with
and without the DoEvents.

Ideally, we would launch a thread with a higher priority than the one
for the code launching the thread, and in that higher priority thread, make
the painting job, but VB/VBA can't handle launching new thread, so, we are
left with DoEvents.



Hoping it may help,
Vanderghast, Access MVP


hi,
"DoEvents" is ignored by XP. So there aws no effect on
display.
I used a delay (through timer) to "give" the program
necessary time to show the graph into the form with no
result.
You just see the forms with no graphs.
GRAPH8.EXE is a seperate process and it starts only when
VB is done with its last line.
So in a loop if I
(1)open a form with a graph,
(2) delay five second (or use DoEvents to let it have done)
(3) close the form
..... iterate through other forms with graphics
I never ses a graphic but empty forms sliding one by one

DoEvents worked properly with Windows 3.1
and when we migarted to NT4 we had to remove it from the
programs as the behaviour was very unexpected.
Likein your example we had :
"Me.Label0.Caption = i"
appear in anunexpected moment.
I'm lucky to talk to you and I hope to fine the way
Sincerely

Zbigniew GALUS (zgalus)
 
Hi,

I would try anything you suggest but I just don't know how.
On my XP family Edition (that I acquired one month ago)
and Access 97 (that I inherited from my previous WINDOWS
98) I do no multi-treading. I just run Access and what I
see through the widows task windows is only one ACCESS
process and all « GRAPH8.EXE » processes associated with
generated graphics. If I could make execute « GRAPH8.EXE »
before I quit the loop I would be all joyful. By the way
what's "WFW3.11" ?
Anyway you explained plenty of things and I appreciate it.
Still searching and waiting your suggestion on "how to try"

Zbigniew GALUS (zgalus)
 
Hi,


WFW3.11 is Windows For Workgroup, version 3.11, an application over DOS
that went just before Windows 95.


A simple and easy way to be sure each graph is generated is to insert a
Message Box in the loop.


For i = 1 to n
' do something here...
MsgBox "Click OK to continue.", vbOKOnly, "myTitle."
Next i


You can also use a timed-message box (see
http://www.clikear.com/webs4/juanmafan/codigo.asp?Id='wsh0006es').


The message box being modal, it is likely that your graph will be
repainted and visible.



Hoping it may help,
Vanderghast, Access MVP



Hi,

I would try anything you suggest but I just don't know how.
On my XP family Edition (that I acquired one month ago)
and Access 97 (that I inherited from my previous WINDOWS
98) I do no multi-treading. I just run Access and what I
see through the widows task windows is only one ACCESS
process and all « GRAPH8.EXE » processes associated with
generated graphics. If I could make execute « GRAPH8.EXE »
before I quit the loop I would be all joyful. By the way
what's "WFW3.11" ?
Anyway you explained plenty of things and I appreciate it.
Still searching and waiting your suggestion on "how to try"

Zbigniew GALUS (zgalus)
 
Hello Michel ,

I've tested with all these boxes in a loop and added some
extra to it but the result is always the same.
I can see my graphs when VB is done with everything.
It looks much unexpected because the box prompts me to key
in an answer and with the very special and beautiful way as
indicated on:
http://www.clikear.com/webs4/juanmafan/codigo.asp?Id='wsh0006es')
my graphs are still looming behind.
Anyway it's great that you show that vigor.
I'm not used to that kind of engagement and professional
approach. At the same time I went throuhg some other
questions and responses and I'm grately relieved that there
are very active people bilding things.
I'm using Access every day for seven years now and though I
went through most of data bases on application level I have
my personal reason to say that all what I did and what I'm
doing now with access is beyond my initial imagination.
I spent twenty years having great time with APL.
On the contrary with Access I discovered rapid data mining.
Zbigniew GALUS
 
Hi,


So, it is a handshaking between two "ex"-APL developers. On the
graphs problem, on the other hand, I can't say much more... I may ask
directly to other MVP if one have a suggestion...


Vanderghast, Access MVP
 
Hello,
thanks a lot.
I'm generating sometimes 160 graphics and with
ScreenHunter I capture them into <gif> files. They are
integrated into my web pages (financial).
That's why I'm looking for an automatic way of doing it.
I hate being a click-man.
I inserted your name into my personal data base.
Glad to get to know you
Zbigniew
 
You could use a combination of 2 solutions on my site:
http://www.lebans.com/imageclass.htm
This vbPictureBox class contains a method for Screen/Form capture.

http://www.lebans.com/pictureboxtogif.htm
PictureBoxToGif.Zip is a class that allows the user to save the contents
of a PictureBox to a disk based Gif file. This is a standard Gif file
with compression so please read the Unisys document below. Full Gif
patent info is included in the ZIP file you will be downloading.
--

HTH
Stephen Lebans
http://www.lebans.com
Access Code, Tips and Tricks
Please respond only to the newsgroups so everyone can benefit.
 
Hi,



Stephen "forgot" to suggest you to try a form Repaint (inside the loop). And
if this does not repaint your graph timewisely, in your form, try to
invalidate the hWnd of the form directly (see the API function RedrawWindow
at www.allapi.net, as example).



Hoping it may help,
Vanderghast, Access MVP
 
it's great to have that excellent feedback. There is much
to learn from www.allapi.net and http://www.lebans.com.
I will investigate the issue as far as I can because I can
see now that Stephen managed to produce the snapshots with
a method that I will try to reuse. I will probably have
some questions
Zbigniew GALUS (zgalus)
 
Hello,
I downloaded "PictureBoxToGif.Zip" and I think I should
invest in VB class programming. Anyway before I start, is
there a way to test what you did with image capture in a
standard VB Access structural programming ? All my codes
are in Modules and I've not used classes in VB Access.
If it's not possible I could buy a book for my two weeks
winter holidays to jump into VB classes programming.
I'm leaving tonight.
For practical reasons I would prefer to stay with Access
as direct access to data is very well adapted to my data
mining approach. Where should I start to implement your
classes ?
I download "A97WindowToBitmapver11.mdb" as well but in
my "NT" context it got stuck when I
launched "PrintRelationShips" form I had a "project or
library not found" message on the line "strPath = Left
(strPath, lngRet) & Chr(0)" of the function <Public
Function fSaveFile() As Boolean>. Another message that I
got was:
on the line "blTemp = Rel.WindowtoDisk()" from <Private
Sub cmdRTF1_Click()> stating that a "object or variable is
not defined".
Zbigniew GALUS (zgalus)
 
Zbigniew GALUS said:
Hello, (...)

All my codes
are in Modules and I've not used classes in VB Access.
If it's not possible I could buy a book for my two weeks
winter holidays to jump into VB classes programming.


================
Hi,


If we start with a "structure", a collection of related data, like a window
which can be described by its top-left and bottom-right position, we can see
the structure as a new kind of "data type". In general, we have more than
just that, we want, indeed, work with that data, so, there are methods that
somehow "belong" to that data. If we glue that data and the methods (code)
together, in a single package, we have the starting idea of what is a basic
class. There are advantages, indeed. Without classes, assume you have to
describe a window, you would probably say:


Dim PositionTop As Long
Dim PositionLeft As Long
Dim PositionRight As Long
Dim PositionBottom As Long


and that would work fine, as example, you can say:

-------------------------------------
Public Property Get WindowWidth( ) As Long
WindowWidth = PopsitionRight-PositionLeft
Exit Property
-------------------------------------


That works fine as far as you have just one window, but if you want two
windows... you are left to either add:

Dim PositionTop2 As Long
Dim PositionLeft2 As Long
Dim PositionRight2 As Long
Dim PositionBottom2 As Long

or to use array notation, and change all your existing code, like:

Public Property Get WindowWidth(Optional ByVal Who As Long=0) As Long
' without argument, return the width of the first window
' to match, as close as possible, the previous behavior
WindowWidth = PopsitionRight(Who)-PositionLeft(who)
Exit Property



If you use a class concept, you would move your data and your code in a
class (that is the blue print) and use object:


Dim myFirstWindow As classWindow
Dim mySecondWindow As classWindow

Dim arrayOfWindows( ) As classWindow



And your class, classWindow, may got its data AND its code like:

Public PositionTop As Long
Public PositionLeft as Long
Public PositionRight as Long
Public PositionBottom As Long

Public Property Get WindowWidth( ) As Long
WindowWidth = PositionRight-PositionLeft
End Property



With that simple modification, now, each object ( myFirstWindow,
mySecondWindow) has its OWN data, form the class, but also share the code.
Back in the module:


Dim myFirstWindow As classWindow
Dim mySecondWindow As classWindow
Set myFirstWindow = New classWindow
myFirstWindow.PositionTop = ....

...
Set mySecondWindow = New classWindow
mySecondWindow .PositionTop = ....
...


Most of the time, we would NOT expose the data stored in the class, for
practical reasons. As example, if we want to store the PositionTop,
PositionLeft, WindowHeight and WindowWidth, instead of the four previous,
and implement as property the PositionRight ( and PositionBottom), why not?
After all, maybe it is more efficient, for us, to have the Width, and
Height, than the bottom-right position? Doing so, we can use:

Private mTop As Long
Private mLeft As Long
Private mWidth As Long
Private mHeight As Long

Public Property Let Top( ByVal newTopValue As Long )
If newTopValue < 0 then exit property
' won't allow a position outside the screen

' can make other checks, if we want

mTop=newTopValue
End Property

Public Property Get Top( ) As Long
Top=mTop
End Property

....
Public Property Get Bottom( ) as Long
Bottom=mTop+mHeight
End Property
....


So, not only we are free to really make the implementation independent of
the way we use the object, and its methods, but we can also make additional
checks. In fact, an object can "contain" other objects. Some authors call
that "inheritance by containment", or "by delegation" since, say, a car
contains four wheel, and to move the car forward, the car-class would
delegate the order to move forward to each of its powered wheels! :

'from car class
Private FLwheel As wheel ' front left
Private FRwheel As wheel ' front right
Private RLwheel As wheel
Private RRwheel As wheel
....
Public Sub MoveForward( xMeter As Long)
'.. check if there is an obstable
...
'so far so good, delegate the action
FLwheel.MoveForwardLinear x
FRwheel.MoveForwardLinear x
...
' display the end result
Me.Repaint ' Me == me, my code + my data

End Sub


You observe that the dot syntax become involved, and thus, can be cascaded.
Assume the FLwheel is public, rather than private, so, someone outside the
class can call it, through the car object. In a module:



Dim x As car
...

x.FLwheel.MoveForwardLinear xMeter


and thus, you get a notion about where a multiple dot syntax can come from.


Anyhow, having the possibility to "own" an object, we have the possibility
to call (call back, delegate) its method, but if it has events, we can
answer to them when the object internally raised ( events are not necessary
synchronous, callback are synchronous). As example, if the front left wheel
find it has a flat, it may raise an event, telling to the car that something
is wrong. Not all car models necessary handle that "signal", not a problem,
if the car has no "code" about the event, nothing would occur, but if the
our car "model" is fancy enough, we would "dim" the wheel object as being
WITH EVENTS, which, for a short story, allows us to then use the special
syntax



Private Sub ObjectName_EventName ( list_of_arguments )
...
End Sub


if we choose to "do something" in cases the said ObjectName (we own it) ever
"raise" the mentioned event. If we do not supply code, nothing would be done
either. We could use and interface, instead of an event, if we would be
obliged by an answer, or want be synchronized.



That is by no mean complete, but too much may be an overkill. I don't know
if the books are still available, but Peter Wright's "Beginning Visual Basic
6 Objects", at WROX (ISBN 1-861001-72-X) is not bad, neither, but more
oriented about COM, "Visual Basic Object & Component Handbook", by Peter
Vogel ( ISBN 0-13-023073-1 ), and definitively, "Microsoft Visual Basic 6.0
Component Tools Guide", more advanced, Microsoft Press (ISBN 1-57231-864-3),
also available on MSDN Library CDs shipped with (Classical) Visual Studio
6.0 (not with Visual Studio 7.0) . Sure, COM is not rumored to be the
future, so, some dot-Net book could be of your interest, in the future...
but that is not applicable for actual VBA code, and no book about VB.Net...
I have read so far... is good enough in my opinion to deserve my
recommendation (note the exit door I have kept open, I said "none I have
read so far", and "about VB-Net", and I won't tell which book I have read so
far, because, sure, I haven't read ALL of them ... :-) ).


Hoping it may help,
Vanderghast, Access MVP
 
Thanks a lot,

I take it as my introductory reading and now I go skiing
Zbigniew
-----Original Message-----




================
Hi,


If we start with a "structure", a collection of related data, like a window
which can be described by its top-left and bottom-right position, we can see
the structure as a new kind of "data type". In general, we have more than
just that, we want, indeed, work with that data, so, there are methods that
somehow "belong" to that data. If we glue that data and the methods (code)
together, in a single package, we have the starting idea of what is a basic
class. There are advantages, indeed. Without classes, assume you have to
describe a window, you would probably say:


Dim PositionTop As Long
Dim PositionLeft As Long
Dim PositionRight As Long
Dim PositionBottom As Long


and that would work fine, as example, you can say:

-------------------------------------
Public Property Get WindowWidth( ) As Long
WindowWidth = PopsitionRight-PositionLeft
Exit Property
-------------------------------------


That works fine as far as you have just one window, but if you want two
windows... you are left to either add:

Dim PositionTop2 As Long
Dim PositionLeft2 As Long
Dim PositionRight2 As Long
Dim PositionBottom2 As Long

or to use array notation, and change all your existing code, like:

Public Property Get WindowWidth(Optional ByVal Who As Long=0) As Long
' without argument, return the width of the first window
' to match, as close as possible, the previous behavior
WindowWidth = PopsitionRight(Who)-PositionLeft(who)
Exit Property



If you use a class concept, you would move your data and your code in a
class (that is the blue print) and use object:


Dim myFirstWindow As classWindow
Dim mySecondWindow As classWindow

Dim arrayOfWindows( ) As classWindow



And your class, classWindow, may got its data AND its code like:

Public PositionTop As Long
Public PositionLeft as Long
Public PositionRight as Long
Public PositionBottom As Long

Public Property Get WindowWidth( ) As Long
WindowWidth = PositionRight-PositionLeft
End Property



With that simple modification, now, each object ( myFirstWindow,
mySecondWindow) has its OWN data, form the class, but also share the code.
Back in the module:


Dim myFirstWindow As classWindow
Dim mySecondWindow As classWindow
Set myFirstWindow = New classWindow
myFirstWindow.PositionTop = ....

...
Set mySecondWindow = New classWindow
mySecondWindow .PositionTop = ....
...


Most of the time, we would NOT expose the data stored in the class, for
practical reasons. As example, if we want to store the PositionTop,
PositionLeft, WindowHeight and WindowWidth, instead of the four previous,
and implement as property the PositionRight ( and PositionBottom), why not?
After all, maybe it is more efficient, for us, to have the Width, and
Height, than the bottom-right position? Doing so, we can use:

Private mTop As Long
Private mLeft As Long
Private mWidth As Long
Private mHeight As Long

Public Property Let Top( ByVal newTopValue As Long )
If newTopValue < 0 then exit property
' won't allow a position outside the screen

' can make other checks, if we want

mTop=newTopValue
End Property

Public Property Get Top( ) As Long
Top=mTop
End Property

....
Public Property Get Bottom( ) as Long
Bottom=mTop+mHeight
End Property
....


So, not only we are free to really make the implementation independent of
the way we use the object, and its methods, but we can also make additional
checks. In fact, an object can "contain" other objects. Some authors call
that "inheritance by containment", or "by delegation" since, say, a car
contains four wheel, and to move the car forward, the car- class would
delegate the order to move forward to each of its powered wheels! :

'from car class
Private FLwheel As wheel ' front left
Private FRwheel As wheel ' front right
Private RLwheel As wheel
Private RRwheel As wheel
....
Public Sub MoveForward( xMeter As Long)
'.. check if there is an obstable
...
'so far so good, delegate the action
FLwheel.MoveForwardLinear x
FRwheel.MoveForwardLinear x
...
' display the end result
Me.Repaint ' Me == me, my code + my data

End Sub


You observe that the dot syntax become involved, and thus, can be cascaded.
Assume the FLwheel is public, rather than private, so, someone outside the
class can call it, through the car object. In a module:



Dim x As car
...

x.FLwheel.MoveForwardLinear xMeter


and thus, you get a notion about where a multiple dot syntax can come from.


Anyhow, having the possibility to "own" an object, we have the possibility
to call (call back, delegate) its method, but if it has events, we can
answer to them when the object internally raised ( events are not necessary
synchronous, callback are synchronous). As example, if the front left wheel
find it has a flat, it may raise an event, telling to the car that something
is wrong. Not all car models necessary handle that "signal", not a problem,
if the car has no "code" about the event, nothing would occur, but if the
our car "model" is fancy enough, we would "dim" the wheel object as being
WITH EVENTS, which, for a short story, allows us to then use the special
syntax



Private Sub ObjectName_EventName ( list_of_arguments )
...
End Sub


if we choose to "do something" in cases the said ObjectName (we own it) ever
"raise" the mentioned event. If we do not supply code, nothing would be done
either. We could use and interface, instead of an event, if we would be
obliged by an answer, or want be synchronized.



That is by no mean complete, but too much may be an overkill. I don't know
if the books are still available, but Peter
Wright's "Beginning Visual Basic
6 Objects", at WROX (ISBN 1-861001-72-X) is not bad, neither, but more
oriented about COM, "Visual Basic Object & Component Handbook", by Peter
Vogel ( ISBN 0-13-023073-1 ), and
definitively, "Microsoft Visual Basic 6.0
 
Back
Top