Comments (13)
Thanks. I'll investigate later.
Until then you can use TImage32.ForceFullInvalidate
. That should work.
from graphics32.
P.S. The test application works correctly on the release/2.0 branch.
The repaint mechanism was pretty broken in earlier versions so my guess is that it just repainted everything every time something changed. Now it works as designed but unfortunately that also means that a lot of code that did things incorrectly no longer work as it did before.
Anyway, as I explained earlier, TCustomLayer.Changed
does nothing. The layers doesn't know which area it should invalidate. Only you know that.
Do like this instead (I changed the event to MouseMove
instead of MouseDown
just so there's more action):
procedure TMainForm.imgMainMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
procedure InvalidateCross(const p: TPoint);
begin
// Vertical
imgMain.Invalidate(Rect(p.x, 0, p.x+1, imgMain.Buffer.Height));
// Horizontal
imgMain.Invalidate(Rect(0, p.y, imgMain.Buffer.Width, p.y+1));
end;
begin
// Invalidate old position so it gets erased
InvalidateCross(FCurrent);
FCurrent := Point(X, Y);
// Invalidate new position so it gets drawn
InvalidateCross(FCurrent);
end;
If you want to see what get's invalidated and repainted, define UPDATERECT_DEBUGDRAW
in GR32_Image.pas
There are some similar options for the repaint optimizer in GR32_MicroTiles.pas
You might also want to look at the examples in Examples\General\Optimized repaint
from graphics32.
In the real application, it is not so easy to manually invalidate everything. It would be great if the library took care of everything itself, as before. Now I will probably have to use Invalidate
without specifying a TRect.
from graphics32.
Now I will probably have to use Invalidate without specifying a TRect.
Yes, it's unfortunate but there really isn't any way for the layer to know what and where you are drawing, before you are drawing it.
Btw, here's your example with the cross painted as marching ants (stippled).
Issue 311 - Repaint TCustomLayer and draw TBitmapLayer at the same time.zip
2024-04-22_22-16-52.mp4
from graphics32.
I still think there is a bug somewhere in the caching/notification/messaging mechanism in GR32. If I change my original code like this:
procedure TMainForm.imgMainMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
begin
FCurrent := Point(X, Y);
imgMain.Invalidate;
//FCustomLayer.Changed;
FBitmapLayer.Bitmap.Clear(SetAlpha(clLightGreen32, 100));
end;
The code still doesn't work correctly. The only way to fix this is to call Changed
and Invalidate
together:
imgMain.Invalidate;
FCustomLayer.Changed;
FBitmapLayer.Bitmap.Clear(SetAlpha(clLightGreen32, 100));
BUT there is no any visible problem when I call Changed
(or single Invalidate
) and draw TBitmapLayer from different notification events (e.g. from OnTimer and OnMouseDown):
procedure TMainForm.imgMainMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
begin
FCurrent := Point(X, Y);
FBitmapLayer.Bitmap.Clear(SetAlpha(clLightGreen32, 100));
end;
procedure TMainForm.tmr1Timer(Sender: TObject); // interval = 50 ms
begin
imgMain.Invalidate;
end;
CustomLayerTest_rjuFDSWXSD.mp4
from graphics32.
This works:
procedure TMainForm.imgMainMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
begin
FCurrent := Point(X, Y);
imgMain.Invalidate;
Application.ProcessMessages;
FBitmapLayer.Bitmap.Clear(SetAlpha(clLightGreen32, 100));
end;
from graphics32.
Application.ProcessMessages
can be removed if you disable repaint optimizations: imgMain.RepaintMode := rmFull
from graphics32.
I still think there is a bug somewhere in the caching/notification/messaging mechanism in GR32. If I change my original code like this: [...] The code still doesn't work correctly.
I can't reproduce any problem with that so there must be difference in our test code somewhere
I can't rule out that there's a bug somewhere but from what I've seen so far everything works as designed.
Application.ProcessMessages can be removed if you disable repaint optimization
In this case the ProcessMessages just processes WM_PAINT messages so you could replace it with Update which does the same without any of the nasty side-effects of ProvcessMessages.
from graphics32.
Yes, Invalidate
+ Update
or Invalidate
with TRect fix the problem. Single Invalidate
doesn't work.
procedure TMainForm.imgMainMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer;
Layer: TCustomLayer);
begin
FCurrent := Point(X, Y);
// 1. Invalidate + Update
imgMain.Invalidate;
imgMain.Update;
// 2. Invalidate with TRect
//imgMain.Invalidate(Rect(0, 0, imgMain.Width, imgMain.Height));
FBitmapLayer.Bitmap.Clear(SetAlpha(clLightGreen32, 100));
end;
Which is the preferred way 1 or 2? Or are they doing the same thing at the same speed?
from graphics32.
Number 1 is is probably the most efficient. There's also TImage32.ForceFullInvalidate
which might be even more efficient as it disables repaint optimization for the current paint cycle.
For a full invalidation TImage32.Invalidate
, without the call to Update
, should work.
Update
simply processes WM_PAINT messages which should happen automatically anyway unless you are doing all this in a tight loop where Windows doesn't get a chance to process the message queue.
If you take the code I posted above and change InvalidateCross
to simply call Invalidate
it should work (it does for me):
procedure TMainForm.InvalidateCross(const p: TPoint);
begin
imgMain.Invalidate;
end;
If that doesn't work then there's something else going on and we need to look at what Delphi version, Windows etc. you are using.
from graphics32.
If you take the code I posted above and change InvalidateCross to simply call Invalidate it should work (it does for me)
Yes, as I wrote before, it works from a different event, but doesn't from the same one. It's important to me.
My modified test app: CustomLayerTest.zip
from graphics32.
Until then you can use TImage32.ForceFullInvalidate. That should work.
Yes, this function works.
from graphics32.
Okay, now I understand what's going on.
The problem is that you are using optimized repaint and drawing on the buffer without notifying the repaint optimizer what it needs to repaint.
Invalidate
does a general invalidation of the buffer and asks Windows to repaint the control (i.e. generate a WM_PAINT message).
When the WM_PAINT message is processed and the buffer is being updated, the internal logic examines the "dirty" areas that needs to be repainted. If there are zero areas then everything is repainted, otherwise each area is repainted.
So when you have no visible layers, and have not invalidated any specific areas, then there are no dirty areas and everything is repainted. When you have a single visible layer, then the area covered by that layer is repainted. This matches what you are seeing exactly.
The solution is to disable the repaint optimizer, which you might as well do since you aren't using its features, by setting RepaintMode=rmFull
. The other solution is to use ForceFullInvalidate
, but it would be better to use rmFull
and avoid the overhead of the repaint optimizer.
from graphics32.
Related Issues (20)
- Repaint Optimizer "forgets" to update the bitmap HOT 2
- Repaint Optimizer "forgets" to update the bitmap 2 HOT 7
- Polygon grow using Clipper2 very very slow HOT 43
- Delphi 12 incompatibility HOT 1
- Polygon draw result looks strange HOT 18
- GR32_LowLevel.Mirror PUREPASCAL does not produce expected values HOT 11
- Revive jsRoundEx? HOT 1
- Lazarus design time support broken HOT 21
- TBitmap32.Textout interesting behavior HOT 12
- PNG support broken on 32-bit FPC HOT 4
- LF Line Endings in the .DPKs Cause File Corruption HOT 18
- Access Violation with color picker controls on Lazarus HOT 2
- BuildPolyLine produces concave curves that are unsuitable for polylines HOT 13
- TColorPickerGTK not displayed correctely after copy/paste HOT 4
- NeoLemmix / SuperLemmix pull request
- Commit "Fix for AV with tiled draw" breaks my code HOT 7
- Bug with layes visibility change HOT 15
- TGaussianKernel is broken HOT 1
- GAMMA_ENCODING_TABLE mayhem HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from graphics32.