Closed GoogleCodeExporter closed 9 years ago
Another repo case:
What steps will reproduce the problem?
1. bring up a layout
2. scroll window
3. press L (the menu command for doing a layout)
What is the expected output? What do you see instead?
Expect perfect redraw/refresh of the screen during animated layout.
Instead partially drawn and clipped shapes are drawn during the layout.
Its only when layout is completely finished, does the rendering correct itself.
<---- CLUE?
Original comment by abu...@gmail.com
on 15 Jul 2012 at 12:52
Another repo case:
Scroll the workspace and move a shape so that it overlaps. The resulting move
and draw will not be properly drawn. Select refresh from the menu and the
situation corrects itself.
Original comment by abu...@gmail.com
on 15 Jul 2012 at 12:53
THIS MAY OR MAY NOT BE RELEVANT:
Dunn in http://osdir.com/ml/wxpython-users/2010-06/msg00587.html says
First, a Refresh() by default will erase the background before sending the
paint event (although setting the BG style or catching the erase event would
have taken care of that.) The second and probably most visible problem in this
case is that in your on_motion handler you are not offsetting the ClientDC by
the scroll offsets, just the position in the buffer that you are drawing the
line segment at. So when the buffer is flushed out to the client DC it is drawn
at the physical (0,0), not the virtual (0,0). In other words, the flicker you
are seeing is coming from drawing the buffer at the wrong position after every
mouse drag event, and then it immediately being drawn again at the right
position in the on_paint triggered by the Refresh().
You should be able to fix this by calling PrepareDC on the client DC before
using it, like this:
cdc = wx.CLientDC(self)
self.PrepareDC(cdc)
dc = wx.BufferedDC(cdc, self.buffer)
However since you are doing a Refresh or RefreshRect? anyway, there is no need
to use a client DC here at all, just let the flushing of the buffer to the
screen be done in on_paint instead:
dc = wx.BufferedDC(None, self.buffer)
Original comment by abu...@gmail.com
on 15 Jul 2012 at 12:55
Perhaps the error is where I try to be smarter and only do a prepare dc etc.
style refresh - this needs to more correctly take into account the scrollbars?
Original comment by abu...@gmail.com
on 15 Jul 2012 at 12:55
Latest thoughts: Perhaps do a full on redraw of everything WHEN I detect the
window is scrolled. This would be a sort of a workaround, though it would slow
things down, as a full on redraw is, and looks, slower.
Original comment by abu...@gmail.com
on 15 Jul 2012 at 12:56
Reproduced problem with attached simplified example. Scroll the window and
repeatedly tap 'm' to move the nodes. Note the bad screen redraw. Doesn't
happen if window is non scrolled.
Original comment by abu...@gmail.com
on 24 Jul 2012 at 8:38
Attachments:
This issue was updated by revision r443.
Initial simplified repro examples. ogl_scroll1.py demos the problem nicely.
Original comment by abu...@gmail.com
on 24 Jul 2012 at 8:49
This issue was updated by revision r444.
The solution seems to be to use canvas.Refresh instead of the diagram clear +
redraw combo. The problem with
self.GetDiagram().Clear(dc)
self.GetDiagram().Redraw(dc)
is that the clear() only clears the physical visible area and the scrolled off
area still has content, so that when you scroll to it you get old rubbish
there. e.g. if the shape that was moved was in the scrolled off area, you will
see double - the old position and the new.
Original comment by abu...@gmail.com
on 25 Jul 2012 at 8:18
This issue was updated by revision r445.
Research demos related to draw, refresh and scrolling. Note that
ogl_redraw_f_logic.py has USEFUL comments as to various drawing techniques and
their strengths and weaknesses.
Original comment by abu...@gmail.com
on 25 Jul 2012 at 8:20
This issue was updated by revision r447.
Ogl official demo from the big fat demo app as standalone app - with my draw
code injected in a modular way. Hit 'm' to move a shape. Hit 'r' to refresh.
Hit '1-7' to change redraw/refresh technique.
Original comment by abu...@gmail.com
on 25 Jul 2012 at 8:33
NOTE: shape.move (which does a shape.draw) and diagram.redraw (which just loops
and calls shape.draw on everything) is all about drawing to the screen, and
works with a scrolled canvas.
The problem is one of clearing. The diagram.Clear() only handles the physical
area. shape.Erase() only handles the shape area.
However frame.Refresh and canvas.Refresh seem to clear everything including the
offscreen scrolled area, and repaints everything cleanly. Yey. But a bit
flickery and possibly there are smarter ways to do this?
Original comment by abu...@gmail.com
on 25 Jul 2012 at 8:36
Need to work out the scrollbars and canvas sizes etc. next. See diagram of the
difference between size and virtualsize.
Some possibly helpful notes being gathered from googling in
http://pynsource.googlecode.com/svn/trunk/Research/ogl%20tests%2001/ogl%20notes.
txt
Original comment by abu...@gmail.com
on 25 Jul 2012 at 8:40
Attachments:
This person seems to have had the exact same problem as me in 2008. His
question wasn't answered.
http://wxpython-users.1045709.n5.nabble.com/dc-Clear-is-this-a-bug-or-am-I-doing
-something-wrong-td2368313.html
Original comment by abu...@gmail.com
on 25 Jul 2012 at 11:40
This issue was updated by revision r448.
Created standalone example for the mailing list.
https://groups.google.com/forum/?hl=en&fromgroups#!searchin/wxpython-users/dc.Cl
ear():$20is$20this$20a$20bug$20or$20am$20I$20doing$20something$20wrong?/wxpython
-users/X840K1bA5R4/kf29SKR5X40J
Original comment by abu...@gmail.com
on 25 Jul 2012 at 1:11
This issue was updated by revision r449.
The current redraw breakthrough of
shape.Move(dc, x, y) # handles shape.MoveLinks(dc) internally too
canvas.Refresh() # or canvas.frame.Refresh()
leaves me with an OUTSTANDING QUESTION: Why isn't an eventual shape.draw() or
diagram.redraw() needed
anymore. DOES canvas.Refresh() SOMEHOW TRIGGER AN ACTUAL DRAW?
Original comment by abu...@gmail.com
on 25 Jul 2012 at 2:01
This issue was updated by revision r450.
Re Refresh(). Tip: a Refresh() by default will erase the background before
sending the paint event.
Also re wx.SafeYield() or self.Update() - You need to be yielding or updating
on a regular basis, so that when your OS/window manager sends repaint messages
to your app, it can handle them.
http://stackoverflow.com/questions/10825128/wxpython-how-to-force-ui-refresh
Without this call the nodes don't paint during a "L" layout (edges do!?)
Original comment by abu...@gmail.com
on 25 Jul 2012 at 2:13
This issue was updated by revision r451.
Various experiments confirming that .Refresh() triggers a proper clear over the
virtualsize shapecanvas and then calls paint which then most likely calls Draw
on everything.
Also confirmed that redraw_everything() does nothing. What's really causing
this to repair any smudgy redraw problems, was that a .Refresh() was indirectly
generated via the frame resize scrollbar hack.
Original comment by abu...@gmail.com
on 26 Jul 2012 at 8:07
redraw_everything() removed. :-) See commentary in issue 12 r455
Original comment by abu...@gmail.com
on 28 Jul 2012 at 5:27
Attachments:
This issue was updated by revision r456.
stage2 renamed build_view and the needless rendering it does removed, as later
stateofthenation will do it. This makes build_view nice and clean - and it
just does one thing, build a view (shapes etc) from a model. Used by a file
open and file import - which makes sense as we are building a new view from
persisted or newly built model.
Original comment by abu...@gmail.com
on 28 Jul 2012 at 6:10
This issue was updated by revision r457.
Made another demo for wxpython mailing list discussion re functionality of
canvas.Clear(dc)
Ironically this discussion seems to be leading back to the topic of the
original poster's subject line "dc.Clear(): is this a bug or am I doing
something wrong?". I think there may be a bug in .Clear(dc) not taking into
account of the scroll, even though canvas.PrepareDC(dc) has been called.
Original comment by abu...@gmail.com
on 29 Jul 2012 at 4:27
This issue was updated by revision r458.
Resurrected old clear/redraw technique in my research code. Made mailing list
post:
On Tue, Jul 31, 2012 at 2:40 AM, Robin Dunn <robin@alldunn.com> wrote:
Ok, I see it too. It's not quite expected but I'm not sure it's a bug as from
some perspectives it is probably the correct thing to do... Anyway, a simple
work around is to simply not call PrepareDC in that case. Then it will always
be the physical window area that is cleared.
Thanks - a most fascinating workaround, which opens up all sorts of
possibilities again. Now I have a way to Clear the visible physical window
area regardless of scroll. This now means that I can rework my old code and it
now works e.g.
dc = wx.ClientDC(canvas)
canvas.GetDiagram().Clear(dc) # do not prepare the dc !!
canvas.PrepareDC(dc)
shape.Move(dc, x, y)
canvas.GetDiagram().Redraw(dc)
which is not quite as pithy as the newer .Refresh based solution
shape.Move(dc, x, y, display=False)
canvas.Refresh()
but nevertheless is now a viable option.
Yeah its curious that you must call PrepareDC before drawing operations in
order to take into account scrolling offsets, but must not call PrepareDC
before clearing operations. It does seem inconsistent.
But now that I think about it, it sort of makes sense. I mean, to clear the
current physical screen is a no brainer - its just sitting there in the frame
all the time - from a hardware point of view. On the other hand to clear just
the topmost window area that has possibly scrolled out of view - that's the
thing that requires calculation, and thus which requires a call to PrepareDC -
and thus you do get the clever ability to only clear that top windowful of area
and if e.g. there is a slight scroll in place, the Clear will only clear a
portion of the visible screen. As to why anybody would ever want to just clear
the top window-ful of a scrolled canvas - I don't know. But I think I'm at
peace with how this all works now. Thanks!
Original comment by abu...@gmail.com
on 31 Jul 2012 at 8:46
This issue was updated by revision r459.
Created a Move2 method to inject into shape. Refactored the coord_utils.py
stateofthenation() simplified to use Move2() followed by a .Refresh().
Original comment by abu...@gmail.com
on 5 Aug 2012 at 12:46
This issue was updated by revision r460.
stage2 removed. All stage2() did was overlap removal. So a new shape canvas
method remove_overlaps() created which people can call explicitly. And then a
subsequent stateofthenation can also be called explicityly. This simplifies
everything.
So now we basically have
.remove_overlaps
.stateofthenation
and when doing a CmdLayout or CmdFileImportBase.execute
.layout_and_position_shapes
Original comment by abu...@gmail.com
on 5 Aug 2012 at 1:28
This issue was updated by revision r461.
Changing shape canvas size more accurately.
Now getting a bug when zoom scale with scroll wheel to min size and then scale
up again - this never happened before. Prevent by holding SHIFT down whilst
scrolling or by doing layout first.
Also need to expand canvas when move shapes out of bounds.
Also need to handle frame resizing better.
Original comment by abu...@gmail.com
on 5 Aug 2012 at 2:01
This issue was updated by revision r462.
Fixed canvas resizing problems by ensuring word size passed in is correct
during boot up phase.
Delayed creation of umlwin sub objects till frame is up and running and has the
right size. New method InitSizeAndObjs created which is now called when that is
all done.
Tip2: No need to call self.resize_virtual_canvas_tofit() every time the frame
is resized since the bounds of the shapes area doesn't change when resizing a
frame, so you would end up calling it with the same values again and again.
Original comment by abu...@gmail.com
on 6 Aug 2012 at 1:17
This issue was updated by revision r463.
Expand canvas when move shapes out of bounds.
Original comment by abu...@gmail.com
on 6 Aug 2012 at 3:22
This issue was updated by revision r464.
Changed scroll to be normal scroll. CTRL scroll is not resize scale. Scale
logic now always preserves layout.
Virtualsize canvas trimming better. Responds to frame resizes. Responds to
node movement out of bounds.
Trick is to make the canvas virtual size == bounds of all the shapes.
You change virtual size by calling SetScrollbars()
SCROLLBAR BEHAVIOUR TIP
As you resize the frame, the canvas virtual size stays the same as what
you set it to using SetScrollbars() - up until the point at which the
scrollbars exhaust themselves and disappear - which means the that you
have finally made frame == virtualsize. After which point virtual size
auto-grows as the frame continues to grow. If you shrink the frame
again, then virtualsize will reduce until it hits the old original value
of virtualsize set by SetScrollbars(). If you continue to reduce the
frame then the scrollbars appear, but the virtualsize remains the same.
ALGORITHM:
IF its a programmatic change of bounds e.g. via stateofthenation:
set canvas virtualsize to match bounds taking account % leeway when compacting
ELSE is_frame_resize i.e. its a call from resize of frame event:
if frame > bounds then must be in virtualsize autogrow mode
and we should not attempt to alter virtualsize
else: set canvas virtualsize to match bounds, not taking into account any % leeway.
Note: repeated calls to frame resize shouldn't be a problem because
canvas virtualsize should == bounds after the first time its done.
Making frame smaller won't affect bounds or canvas virtualsize. Making
frame bigger ditto. Making frame bigger than bounds will result in
nothing happening cos we do nothing in "autogrow mode".
Rule: virtual size must be >= bounds
Rule: virtual size must be no more than n% bigger than the bounds else
virtualsize will be trimmed/compacted down. The purpose of this is to
relax the rules and not have it so strict - after all it doesn't hurt to
have a slightly larger workspace - better than a trim workspace
jumping/flickering around all the time. Plus if you manually drag resize
the frame it will trim perfectly.
Original comment by abu...@gmail.com
on 6 Aug 2012 at 11:33
This issue was updated by revision r465.
Switched to a time based approach to calling
resize_virtual_canvas_tofit_bounds() from FRAME resize event. Seems to work
better - user experience wise.
Original comment by abu...@gmail.com
on 6 Aug 2012 at 1:20
A bit of a post Mortem on all this resizing of virtual canvas to match the
bounds of all shapes:
You can theoretically resize virtual canvas using setscrollbars() anytime -
even when in my so called 'auto virtual size mode' - its not going to hurt
because you are setting it accurately to the size of the shapes bounds.
The problem is how do you avoid calling this expensive (and screen draw flashy)
setscrollbars() operation unnecessarily? In particular when it's being called
repeatedly from the frame resize event.
I thought that detecting my so called 'auto virtual size mode' would be a time
NOT to do it. I think in the end this turned out to be a not so useful
optimization. Sure I got less calls to setscrollbars() but I didn't get the
functionality of setscrollbars() at all in that 'mode'. The 'time' based
approach on the other hand let one through every 5 seconds whilst resizing. A
bit hacky but works and delivers functionality.
Note that the 'resize virtual canvas to fit' method either expands the virtual
size to meet the needs of the bounds of all shapes, or it shrinks the virtual
size to the bounds.
If its expanding the virtual size, then once that is done, the virtual size
should be OK for the foreseeable future, it will either match the bounds or be
bigger than the bounds, due to a frame resize stretch auto mode thing - thus
the need to want to expand the virtual size will be quenched.
If on the other hand its compacting the virtual size then once that is done, we
are NOT OK for the future because whilst the virtual size may have successfully
been set, next time we read the value of canvas virtual size we may get the
temporarily stretched value, due to the frame resize stretch auto mode thing -
hence the algorithm will not be quenched and another attempt will be made again
and again to compact - esp. when this is being called from a frame resize
event. Performance and flashy city ensues. So actually there sort of IS a point
to not doing any compacting whilst in the funny stretched mode where we can't
rely on virtual size shrinking when we ask it to shrink - because the frame is
bigger than the bounds and in a sense the virtual size cannot physically shrink
- its constrained by the size of the real frame and cannot get smaller when we
ask it to.
Original comment by abu...@gmail.com
on 6 Aug 2012 at 2:33
This issue was updated by revision r466.
Moved the virtual canvas resizing to a new non time based algorithm. Basically
the solution is to remember the overall shapes bounds whenever we set the
virtual canvas size to = bounds. That way we only do the painful flashy
resizing operation when bounds have truly changed.
This (I think) gets us around the previously mentioned issue that virtualsize
may be a temporarily stretched value, due to the frame resize stretch auto mode
thing.
Original comment by abu...@gmail.com
on 7 Aug 2012 at 2:39
This issue was updated by revision r467.
Added some caching to GetBoundsAllShapes() calculation. Some refactoring. We
now use a allshapes_bounds and an allshapes_bounds_dirty flag.
Also set virtualsize using SetScrollBars() call with extra parameters which
avoid the flashing! :-)
Original comment by abu...@gmail.com
on 7 Aug 2012 at 5:37
This issue was updated by revision r468.
Refactored canvas virtual size resizing logic, got rid of dirty flag and now
its a parameter to resize_virtual_canvas_tofit_bounds(). Now only have
self.allshapes_bounds_cached
self.allshapes_bounds_last
Nice debugging statements on in this version.
Original comment by abu...@gmail.com
on 7 Aug 2012 at 8:33
This issue was updated by revision r469.
Moved canvas resizing and associated functionality into separate class in
canvas_resizer.py
Class CanvasResizer
Original comment by abu...@gmail.com
on 7 Aug 2012 at 11:54
This issue was updated by revision r470.
Refactoring and cleanup of canvas_resizer.py
Debugging info still present.
Original comment by abu...@gmail.com
on 7 Aug 2012 at 1:04
This issue was updated by revision r471.
Turned off most debugging in canvas_resizer.py
Still need to figure out why canvas resizing sometimes happens repeatedly
during a layout. e.g.
Setting virtual size to 970,1022
Setting virtual size to 970,1022
Original comment by abu...@gmail.com
on 7 Aug 2012 at 1:14
This issue was updated by revision r472.
Optimised canvas_resizer.py to reduce number of virtual canvas resizings.
Also note the use of the new whoscalling2() diagnostic which dumps the call
stack in a nice way.
Original comment by abu...@gmail.com
on 8 Aug 2012 at 2:21
At this point the screen is drawing correctly and also the scrollbars (and
virtual canvas size) is resizing nicely.
Any leeway in canvas size is due to the 40% leeway I have in place to prevent
overly aggressive compacting of the virtual canvas size. A manual resize of the
frame will always correct this.
Original comment by abu...@gmail.com
on 8 Aug 2012 at 2:28
Original issue reported on code.google.com by
abu...@gmail.com
on 15 Jul 2012 at 12:46