Screen capture utility

I have reworked the code a bit so a demo can have multiple screen captures and clean up the code a bit.

But, I am still not happy with this as there are demo's I can't make play nicely, hoping that someone will have some insights/ideas on how to improve on this.

- aui.notebook - screen is not correctly sized before capture is done
- aboutbox - How to capture a modal dialog, which I think this basically is
- agw.aui - need to make the MDIAUI demo a bit nicer
- agw.ballontip - haven't figured out how to show a tip

Attached is a patch file with for a few demo files (check out from this morning) and the script to do the capture.

The capture script assumes to be in a new folder "tools" in the demo folder, if it is elsewhere it needs adjustment. The screen captures will be written to "demo/tools/screencaptures", which will be created if it doesn't exist.

Each demo will need to get a "runScreenCapture" method, with is similar to the existing "runTest". Sometimes the way the demo is written needs to be adjusted, e.g. move the stuff from the 'button' handler into a 'doButton' method. The few patches to demo files included show the basics.

If someone has some better ideas on how to adjust the demo files to be able to capture the screen I am all ears!

Werner

P.S. If someone want to play with this on Linux and/or Mac that would be great.

P.S. Note that I have problems running it within a VM, i.e. the screen shots are messed up when I did run it in Win7 which was in an Ubuntu VirtualBox VM.

sampledemopatches.patch (5.32 KB)

demoscreencapture.py (6.11 KB)

Hi,

I think I am getting closer, the attached patch has 44 modified demo's and most of them capture correctly, I am still fighting with "aboutbox", "dialogunits" and with "agw.ballontip".

The code to be inserted into the demo is a little simpler for most cases.

Will keep updating the other demos, either over the weekend of next week.

It would still be great if Mac/Linux user could review and try this to make sure it works on those platforms.

Werner

demoscreencapture.py (7.06 KB)

sampledemopatches2.patch (29.7 KB)

What should be done about demos like the following?

- sizers.py, should it have a screen capture at all?
- Layout*.py, should they have a screen capture?
- grid.py, currently I capture all of the grid demos, not sure it makes sense, i.e. one is probably enough, if yes, which one is prefered

Werner

Here is the latest version of the script.

I takes over 160 screen captures in the main demo folder, most of them are great but there are still some which have some "stuff" which should not be there.

what stuff:
- sometimes partial image of the previous demo
- incomplete data, e.g. staticText not shown,

I had lots of these and in most cases I can get rid with doing things like window.Update/window.Raise/window.Show/wx.Sleep/ws.SafeYield type additions, some you can see in the script some I needed to add to the demo file before screen capture call back is called.

This feels like a big hack and there must be something I am missing. I.e. how can I force wx to ensure that the window is fully updated before I proceed with taking doing the screen capture?

Anyone has some tips on this?

Werner

demoscreencapture.py (10.5 KB)

Hi Werner,

Here is the latest version of the script.

I takes over 160 screen captures in the main demo folder, most of them are
great but there are still some which have some "stuff" which should not be
there.

what stuff:
- sometimes partial image of the previous demo
- incomplete data, e.g. staticText not shown,

I had lots of these and in most cases I can get rid with doing things like
window.Update/window.Raise/window.Show/wx.Sleep/ws.SafeYield type additions,
some you can see in the script some I needed to add to the demo file before
screen capture call back is called.

This feels like a big hack and there must be something I am missing. I.e.
how can I force wx to ensure that the window is fully updated before I
proceed with taking doing the screen capture?

Anyone has some tips on this?

Have you tried deferring the screen capturing stuff with
wx.CallAfter/wx.CallLater? I remember having similar issues with the
AGW docs to grab the SVN updates screenshots. and I solved it by using
a wx.CallLater(1000, TakeScreenShot) call. I believe this will get the
job done, at least on Windows. You may want to leave in a call to
wx.SafeYield for all the demos though.

BTW, very nice job on the screen capture stuff. I hope Robin will soon
find the time to apply your patch, so we can all start generating
screenshots on all platforms :slight_smile:

Andrea.

"Imagination Is The Only Weapon In The War Against Reality."
http://xoomer.alice.it/infinity77/

···

On 19 March 2012 16:30, werner wrote:

Here is the latest version of the script.

I also attach a huge patch showing the changes in the individual demo files for the main demo folder, note that it includes changes unrelated to the capture stuff which I have mentioned in other threads over the last few days.

A simple demo now has this code in the demo file:

def runScreenCapture(scparent, nb, log, captcallback, imgpath, imgname):
     win = runTest(scparent, nb, log)
     captcallback(win, imgpath, imgname)

If a button needs to be pressed then the demo needs to change to have a DoButton method and then we do this, e.g. for the FloatCanvas demo:

     def runScreenCapture(scparent, nb, log, captcallback, imgpath, imgname):
         win = runTest(scparent, nb, log)
         win1 = win.DoButton()
         captcallback(win1, imgpath, imgname, addwin=win)

the 'addwin' param is needed so the captcallback can close both windows.

To adapt the file name, assuming we use what Andrea proposed a while ago we would do in the FloatCanvas demo:

     def runScreenCapture(scparent, nb, log, captcallback, imgpath, imgname):
         win = runTest(scparent, nb, log)
         win1 = win.DoButton()
         imgname = "lib.floatcanvas"
         captcallback(win1, imgpath, imgname, addwin=win)

Currently it generates over 170 images in the main demo without any artifacts (got rid of them by re-organizing the code a little, without need for CallAfter or CallLater, instead it is basically a wx.Sleep(n) and window.Update()).

There are some demos which still don't play nicely, see the list "excluProblems" in the script.

There is also a strange issue with FindReplaceDialog, the w/h of it are not reported correctly, they seem to be reversed and a bit underestimated - hacked around it.

This is still only tested on Windows and I do sometimes see a hang/crash at the end of it, i.e. when it tries to do the OnClose method after it printed the totals which I will try and find.

This uses a wx.ScreenDC (as I couldn't get it to work with wx.WindowsDC), this means you have to let it run and not switch to another window as otherwise it will capture the wrong window, there are a few demos which have a longish sleep (3 seconds or so), which gives the impression as nothing is happening for a moment - so be patient if you try it out;-) .

Werner

sampledemopatches3.patch (135 KB)

demoscreencapture.py (11.1 KB)

Hi,

Attached an initial patch for the demo/agw demos.

A few issues:

- had to change the import of the demo/agw.infobar, didn't find the installed wx.lib.agw.infobar - it is in the patch
- getting an exception with the XLSGrid (using the 0.7.3 version of xlrd) - see below
- XLSGrid doesn't find the .xls file when run by the capture script, probably some current dir issue
- PyBusyInfo - doesn't have a Show method, any chance this could be added or ...?
- SuperToolTip - doesn't have a Show method, any chance this could be added or ...?

Werner

Traceback (most recent call last):
   File "agw\XLSGrid.py", line 195, in OnStart
     comments, texts = XG.ReadExcelCOM(filename, sheetname, rows, cols)
   File "C:\Python27\lib\site-packages\wx-2.9.3-msw\wx\lib\agw\xlsgrid.py", line
497, in ReadExcelCOM
     workbook = Excel(filename, sheetname)
   File "C:\Python27\lib\site-packages\wx-2.9.3-msw\wx\lib\agw\xlsgrid.py", line
543, in __init__
     self.xlApp = Dispatch('Excel.Application')
   File "C:\Python27\lib\site-packages\win32com\client\__init__.py", line 95, in
Dispatch
     dispatch, userName = dynamic._GetGoodDispatchAndUserName(dispatch,userName,c
lsctx)
   File "C:\Python27\lib\site-packages\win32com\client\dynamic.py", line 108, in
_GetGoodDispatchAndUserName
     return (_GetGoodDispatch(IDispatch, clsctx), userName)
   File "C:\Python27\lib\site-packages\win32com\client\dynamic.py", line 85, in _
GetGoodDispatch
     IDispatch = pythoncom.CoCreateInstance(IDispatch, None, clsctx, pythoncom.II
D_IDispatch)
pywintypes.com_error: (-2147221005, 'Cha\xeene de classe incorrecte', None, None
)

sampledemopatchesAGW.patch (33.3 KB)

Last line in English is:

pywintypes.com_error: (-2147221005, 'Invalid class string', None, None
)
If I read this correctly it assumes in lib.agw.xlsgrid that if I have win32com it also assumes
that I have Excel which I don't have or use.
Werner

I

···

On 20/03/2012 16:48, werner wrote:

  Traceback (most recent call last):


  � File "agw\XLSGrid.py", line 195, in OnStart


  ��� comments, texts = XG.ReadExcelCOM(filename, sheetname, rows,

cols)

  � File

“C:\Python27\lib\site-packages\wx-2.9.3-msw\wx\lib\agw\xlsgrid.py”,
line

  497, in ReadExcelCOM


  ��� workbook = Excel(filename, sheetname)


  � File

“C:\Python27\lib\site-packages\wx-2.9.3-msw\wx\lib\agw\xlsgrid.py”,
line

  543, in __init__


  ��� self.xlApp = Dispatch('Excel.Application')


  � File

“C:\Python27\lib\site-packages\win32com\client_init_.py”, line
95, in

  Dispatch


  ��� dispatch, userName =

dynamic._GetGoodDispatchAndUserName(dispatch,userName,c

  lsctx)


  � File "C:\Python27\lib\site-packages\win32com\client\dynamic.py",

line 108, in

  _GetGoodDispatchAndUserName


  ��� return (_GetGoodDispatch(IDispatch, clsctx), userName)


  � File "C:\Python27\lib\site-packages\win32com\client\dynamic.py",

line 85, in _

  GetGoodDispatch


  ��� IDispatch = pythoncom.CoCreateInstance(IDispatch, None,

clsctx, pythoncom.II

  D_IDispatch)


  pywintypes.com_error: (-2147221005, 'Cha\xeene de classe

incorrecte’, None, None

  )

Hi Werner,

Hi,

Attached an initial patch for the demo/agw demos.

A few issues:

- had to change the import of the demo/agw.infobar, didn't find the
installed wx.lib.agw.infobar - it is in the patch

Thank you, fixed in SVN.

- getting an exception with the XLSGrid (using the 0.7.3 version of xlrd) -
see below

Should (hopefully) be fixed in SVN now.

- XLSGrid doesn't find the .xls file when run by the capture script,
probably some current dir issue

Should (hopefully) be fixed in SVN now.

- PyBusyInfo - doesn't have a Show method, any chance this could be added or
...?

Added in SVN.

- SuperToolTip - doesn't have a Show method, any chance this could be added
or ...?

Added in SVN.

Would it be possible for you to re-generate the patch against the
latest SVN? I have committed some large changes (mostly docstrings,
but also some bug fixes). If it is too much of a hassle I'll try and
rework your patch against the current AGW SVN and try to apply it.

Thank you!

Andrea.

"Imagination Is The Only Weapon In The War Against Reality."
http://xoomer.alice.it/infinity77/

···

On 20 March 2012 16:48, werner wrote:

Hi Andrea,

...

Would it be possible for you to re-generate the patch against the latest SVN? I have committed some large changes (mostly docstrings, but also some bug fixes). If it is too much of a hassle I'll try and rework your patch against the current AGW SVN and try to apply it.

Don't bother, will do a new one later today or tomorrow after getting the latest SVN.

Werner

···

On 20/03/2012 19:14, Andrea Gavana wrote:

Hi Andrea,

...

- getting an exception with the XLSGrid (using the 0.7.3 version of xlrd) -
see below
Should (hopefully) be fixed in SVN now.

fixed

- XLSGrid doesn't find the .xls file when run by the capture script,
probably some current dir issue

Should (hopefully) be fixed in SVN now.

fixed, but I think it was on my side, I had a os.chdir on line 197 (commented as I can't remember why I had it in the first place, will remove it after I run a full run).

- PyBusyInfo - doesn't have a Show method, any chance this could be added or
...?

Added in SVN.

- SuperToolTip - doesn't have a Show method, any chance this could be added
or ...?

Added in SVN.

Thanks, would also need an Update, but before you do this I am not sure it will be enough to actually capture the tip or the busy window. If it is not too be a thing please add it, then I can chase it further.

Would it be possible for you to re-generate the patch against the
latest SVN? I have committed some large changes (mostly docstrings,
but also some bug fixes). If it is too much of a hassle I'll try and
rework your patch against the current AGW SVN and try to apply it.

Attached, with the current version of the script, which only generates a few files see lines 126-136 and lines 31 and 32, i.e. if you want all agw stuff then uncomment 32 and comment 31 and 126-136.

Werner

sampledemopatchesAGW2.patch (34.9 KB)

demoscreencapture.py (12.1 KB)

···

On 20/03/2012 19:14, Andrea Gavana wrote:

Hi Werner,

Hi Andrea,

...

- getting an exception with the XLSGrid (using the 0.7.3 version of xlrd)
-

see below
Should (hopefully) be fixed in SVN now.

fixed

- XLSGrid doesn't find the .xls file when run by the capture script,
probably some current dir issue

Should (hopefully) be fixed in SVN now.

fixed, but I think it was on my side, I had a os.chdir on line 197
(commented as I can't remember why I had it in the first place, will remove
it after I run a full run).

- PyBusyInfo - doesn't have a Show method, any chance this could be added
or
...?

Added in SVN.

- SuperToolTip - doesn't have a Show method, any chance this could be
added
or ...?

Added in SVN.

Thanks, would also need an Update, but before you do this I am not sure it
will be enough to actually capture the tip or the busy window. If it is not
too be a thing please add it, then I can chase it further.

Done, I have added the Update method for both PyBusyInfo and
SuperToolTip in the latest SVN revision.

Would it be possible for you to re-generate the patch against the
latest SVN? I have committed some large changes (mostly docstrings,
but also some bug fixes). If it is too much of a hassle I'll try and
rework your patch against the current AGW SVN and try to apply it.

Attached, with the current version of the script, which only generates a few
files see lines 126-136 and lines 31 and 32, i.e. if you want all agw stuff
then uncomment 32 and comment 31 and 126-136.

I'll take a run at it later (when my sweet little monster goes to sleep :smiley: )

Andrea.

"Imagination Is The Only Weapon In The War Against Reality."
http://xoomer.alice.it/infinity77/

···

On 20 March 2012 20:13, werner wrote:

On 20/03/2012 19:14, Andrea Gavana wrote:

Hi Andrea,

pybusyinfo is fine now after changing the capture code in the demo to this:

def runScreenCapture(scparent, nb, log, captcallback, imgpath, imgname):
     win = runTest(scparent, nb, log)
     imgname = "lib.agw.pybusyinfo"
     win1 = win.DoButton()
     captcallback(win1._infoFrame, imgpath, imgname, addwin=win)

Supertooltip is not working yet. I tried two things:

Changed line 228 in the SuperToolTip demo from:

         mainSizer.Add(toolTipSizer, 1, wx.ALL|wx.EXPAND, 5)
to:
         mainSizer.Insert(0, toolTipSizer, 1, wx.ALL|wx.EXPAND, 5)

I.e. move the two buttons to the top and then do:

def runScreenCapture(scparent, nb, log, captcallback, imgpath, imgname):
     win = runTest(scparent, nb, log)
     imgname = "lib.agw.supertooltip"
     win1 = win.DoButton()
     win1.DoGenerateTip()
     win1.tip.DoShowNow()
     captcallback(win1, imgpath, imgname, addwin=win)

The second try was to pass the tip to the capture tool, i.e.:
def runScreenCapture(scparent, nb, log, captcallback, imgpath, imgname):
     win = runTest(scparent, nb, log)
     imgname = "lib.agw.supertooltip"
     win1 = win.DoButton()
     win1.DoGenerateTip()
     captcallback(win1.tip, imgpath, imgname, addwin=win)

With this I get an exception "window.Raise" is not defined and if I get past that I "window.GetRect" and "window.GetScreenRect" are not defined, probably all due to SuperToolTip being based on "object".

Andrea, do you have another idea on how to capture either just the tip or have the tip show on top of the demo and capture both?

Werner

Hi Werner,

Hi Andrea,

pybusyinfo is fine now after changing the capture code in the demo to this:

def runScreenCapture(scparent, nb, log, captcallback, imgpath, imgname):
win = runTest(scparent, nb, log)
imgname = "lib.agw.pybusyinfo"
win1 = win.DoButton()
captcallback(win1._infoFrame, imgpath, imgname, addwin=win)

Supertooltip is not working yet. I tried two things:

Changed line 228 in the SuperToolTip demo from:

   mainSizer\.Add\(toolTipSizer, 1, wx\.ALL|wx\.EXPAND, 5\)

to:
mainSizer.Insert(0, toolTipSizer, 1, wx.ALL|wx.EXPAND, 5)

I.e. move the two buttons to the top and then do:

def runScreenCapture(scparent, nb, log, captcallback, imgpath, imgname):
win = runTest(scparent, nb, log)
imgname = "lib.agw.supertooltip"
win1 = win.DoButton()
win1.DoGenerateTip()
win1.tip.DoShowNow()
captcallback(win1, imgpath, imgname, addwin=win)

The second try was to pass the tip to the capture tool, i.e.:

def runScreenCapture(scparent, nb, log, captcallback, imgpath, imgname):
win = runTest(scparent, nb, log)
imgname = "lib.agw.supertooltip"
win1 = win.DoButton()
win1.DoGenerateTip()
captcallback(win1.tip, imgpath, imgname, addwin=win)

With this I get an exception "window.Raise" is not defined and if I get past
that I "window.GetRect" and "window.GetScreenRect" are not defined, probably
all due to SuperToolTip being based on "object".

Andrea, do you have another idea on how to capture either just the tip or
have the tip show on top of the demo and capture both?

The simplest thing that comes to my mind is to modify your
runScreenCapture method like this for SuperToolTip only:

def runScreenCapture(scparent, nb, log, captcallback, imgpath, imgname):
   win = runTest(scparent, nb, log)
   imgname = "lib.agw.supertooltip"
   win1 = win.DoButton()
   win1.DoGenerateTip()
   captcallback(win1.tip._superToolTip, imgpath, imgname, addwin=win)

Hopefully it should do it...

Andrea.

"Imagination Is The Only Weapon In The War Against Reality."
http://xoomer.alice.it/infinity77/

···

On 21 March 2012 09:39, werner wrote:

Hi Andrea,

Hi Werner,

...

The simplest thing that comes to my mind is to modify your
runScreenCapture method like this for SuperToolTip only:

def runScreenCapture(scparent, nb, log, captcallback, imgpath, imgname):
    win = runTest(scparent, nb, log)
    imgname = "lib.agw.supertooltip"
    win1 = win.DoButton()
    win1.DoGenerateTip()
    captcallback(win1.tip._superToolTip, imgpath, imgname, addwin=win)

Hopefully it should do it...

Close, needed to add win1.DoShowNow(), and I used the public access to the tip window;-) :

def runScreenCapture(scparent, nb, log, captcallback, imgpath, imgname):
     win = runTest(scparent, nb, log)
     imgname = "lib.agw.supertooltip"
     win1 = win.DoButton()
     win1.DoGenerateTip()
     win1.tip.DoShowNow()
     captcallback(win1.tip.GetTipWindow(), imgpath, imgname, addwin=win)

This captures just the tip.

Werner

···

On 21/03/2012 09:49, Andrea Gavana wrote:

Hi,

attached is the latest version of the script, I think I fixed the issue where it would hang/crash during its close down, the problem had to do with my use of window.Destroy/window.Close for each of the demos.

I can produce updated patches for the main and agw demo folders if/when required.

Werner

demoscreencapture.py (12 KB)

Robin,

···

On 21/03/2012 11:51, werner wrote:

Hi,

attached is the latest version of the script, I think I fixed the issue where it would hang/crash during its close down, the problem had to do with my use of window.Destroy/window.Close for each of the demos.

I can produce updated patches for the main and agw demo folders if/when required.

How would you like to proceed with this screen capture stuff?

Werner

Just to make sure I understand without having to review all the messages, basically you are talking about modifying the samples in the demo to add a runScreenShot (or something like that) function which will set up and run the real sample and provides the info about what needs to be captured, etc. Is that correct? Are there any remaining questions or issues that need to be resolved?

···

On 4/3/12 7:51 AM, werner wrote:

Robin,

On 21/03/2012 11:51, werner wrote:

Hi,

attached is the latest version of the script, I think I fixed the
issue where it would hang/crash during its close down, the problem had
to do with my use of window.Destroy/window.Close for each of the demos.

I can produce updated patches for the main and agw demo folders
if/when required.

How would you like to proceed with this screen capture stuff?

--
Robin Dunn
Software Craftsman

Hi Robin,

Robin,

Hi,

attached is the latest version of the script, I think I fixed the
issue where it would hang/crash during its close down, the problem had
to do with my use of window.Destroy/window.Close for each of the demos.

I can produce updated patches for the main and agw demo folders
if/when required.

How would you like to proceed with this screen capture stuff?

Just to make sure I understand without having to review all the messages, basically you are talking about modifying the samples in the demo to add a runScreenShot (or something like that) function which will set up and run the real sample and provides the info about what needs to be captured, etc. Is that correct?

Yes, so e.g. in demo.agw.aui it would add:

def runScreenCapture(scparent, nb, log, captcallback, imgpath, imgname):
     win = runTest(scparent, nb, log)
     win1 = win.DoButton1()

     imgname = "lib.agw.aui"
     captcallback(win1, imgpath, imgname)
     win2 = win.DoButton2()

     captcallback(win2, imgpath, (imgname + "_1"), addwin=win)

And the two button handlers would be changed along these lines:

     def OnButton1(self, event):
         self.DoButton1(self)

     def DoButton1(self):
         #self.win = MainAUI(self, self.log)
         return MainAUI(self, self.log)

All demos where one needs to click a button, dialogs etc) will need something along these lines.

The last patch I proposed contains all this, but I it also contain the problems (GetMouseState etc), so I wouldn't apply it in its state as I guess you would get conflicts.

  Are there any remaining questions or issues that need to be resolved?

It works for me on Windows, but it is not tested on *nix nor on Mac.

If no one is stepping up to give it a try I will at least try/test it on *nix (but not before next month).

Frankly, at this point I just wanted to know if this is of interest, if no then I stop working on it, if yes then I keep working on it and when it is ready for *nix and Windows I let you know.

Werner

···

On 08/04/2012 01:18, Robin Dunn wrote:

On 4/3/12 7:51 AM, werner wrote:

On 21/03/2012 11:51, werner wrote:

Yes, I think it's a good idea.

I've also been thinking about restructuring the demo a bit, but I expect that will mostly be in Main.py so these changes in the samples for screen captures probably wont interfere at all.

···

On 4/8/12 1:36 AM, Werner wrote:

Frankly, at this point I just wanted to know if this is of interest, if
no then I stop working on it, if yes then I keep working on it and when
it is ready for *nix and Windows I let you know.

--
Robin Dunn
Software Craftsman