When a new TImage is created it is transparent. After drawing objects to this image I would like to clear them. Note that I need to keep the image transparent as the TImage is being used as an overlay to another image.
Some sort of "clear" function for the TImage would be best. I think I'm missing something simple here, I just could not find any clear function within the TImage menu.
You're not really meant to draw things on a TImage control. You're meant to assign its Picture property and leave it alone. In fact, when you draw on a TImage, you're either drawing transiently by drawing on its Canvas property, or you're modifying the underlying Picture object by drawing on its canvas.
To clear a TImage, simply unassign the Picture property.
Image.Picture := nil;
To draw transient images — something you'll need to repaint whenever the window gets obscured and revealed — use a TPaintBox.
Related
I try to make use of a TImage32 to combine several layers with positions and transparency etc. So I create in runtime a TImage32, set parent to nil, load from file a bitmap and load from file a layer on top of that bitmap. Now I want to save the result, but I seem to be unable to find where the actual result is. If I do the same with creating the TImage32 in designtime, make it visible, the result of the combined bitmaps is in the Buffer field of TImage32, and I can save the result using Image32.Buffer.SaveToFile('test.bmp'). If the component is not visible, the Buffer is an empty bitmap and the combined bitmap seem to be not created.
Can someone shed light on this? How do I combine bitmaps with GR32, save them, but with invisible components?
Thanks a lot!
Willem
You don't need to use visual controls like TImage.
The library you're using graphics32 has all the methods you need.
Use TBitmap32: The Bitmap can be displayed and scaled using its DrawMode, MasterAlpha and StretchFilter properties.
You simply use the MyBitmap.LoadFromFile method to get it.
I suggest you then store your bitmaps in a TObjectList.
Combine them using TBitmap32.Draw{To}, note that you can use the DrawMode to modify the behavior of Draw.
And use the SaveToFile method as usual when done manipulating the bitmap.
How can change alphablend of a form without affect on control in form?
Delphi XE7
One solution to this problem is to use Multi-Device Application (if using VCL is not possible).
If you need to leave a transparent TForm just changing a property Transparency = True.
If you need to leave a semi-transparent component, all components have the Opacity property that can be assigned a more transparent value between 0 and 1, where 0 is closer to that component.
For example you could put the controls within a TLayout and change the Opacity of it as you see fit, and have no effect on the other components, or vice versa.
Actually the answer to this might be pretty simple...(for windows only)
The JEDI VCL library has a component (TJvTransparentForm) that allows you to take an Alpha blended PNG image (ie the gray background shown in your picture above) and use it to make a form control. The picture is actually stored in a TImage and you would need to place your "Icons" on the image itself. Then just respond to the mouse clicks on the TImage.
You have what your asking for (maybe?).
If you were tricky enough you could probably even track the mouse movement and change the Image to glow the correct "button" that the mouse was over.
The question relates to: Drawing on a paintbox - How to keep up with mouse movements without delay?
I was going to at some point ask the question of how to repaint only part of a paintbox without invalidating the whole paintbox, which is slow when there is a lot of drawing going on or in my case when there are a lot of tiles drawn on screen.
From the link above Peter Kostov did touch on the subject briefly in one of his comments:
you can partly BitBlt the offscreen bitmap (only regions where it is changed). This will improve the performance dramatically.
I have limited graphic skills and have never really used BitBlt before but I will be reading more about it after I post this question.
With that said, I wanted to know how exactly could you determine if regions of a bitmap have changed? Does this involve something simple or is there more magic so to speak involved in determining which regions have changed?
Right now I am still painting directly to the paintbox but once I draw to the offscreen buffer bitmap my next step is to optimise the painting and the above comments sound exactly like what I need, only the determining regions that have changed has confused me slightly.
Of course if there are other ways of doing this please feel free to comment.
Thanks.
You don't have to use BitBlt() directly if you draw to an offscreen TBitmap, you can use TCanvas.CopyRect() instead (which uses StretchBlt() internally). But either way, when you need to invalidate just a portion of the TPaintBox (the portion corresponding to the section of the offscreen bitmap that you drew on), you can use InvalidateRect() directly to specify the appropriate rectangle of the TPaintBox, instead of calling TControl.Invalidate() (which calls InvalidateRect() with the lpRect parameter set to NULL). Whenever the TPaintBox.OnPaint event is triggered, InvalidateRect() will have established a clipping rectangle within the canvas, any drawing you do outside of that rectangle will be ignored. If you want to manually optimize your drawing beyond that, you can use the TCanvas.ClipRect property to determine the rectangle of the TPaintBox that needs to be drawn, and just copy that portion from your onscreen bitmap.
The only gotcha is that TPaintBox is a TGraphicControl descendant, so it does not have its own HWND that you can pass to InvalidateRect(). You would have to use its Parent.Handle HWND instead. Which means you would have to translate TPaintBox-relative coordinates into Parent-relative coordinates and vice versa when needed.
You need to take charge of the painting in order to do this:
Call InvalidateRect to invalidate portions of a window.
When handling WM_PAINT you call BeginPaint which yields a paint struct containing the rect to be painted.
All of this requires a window, and unfortunately for you, TPaintBox is not windowed. So you could use the parent control's window handle, but frankly it would be cleaner to use a windowed control.
You could use my windowed paint control from this question as a starting point: How could I fade in/out a TImage? Use the ClipRect of the control's canvas when painting to determine the part of the canvas that needs re-painting.
I have a Image list assigned to a listview to display transparent images.
There is a slight issue with this regarding some transparent images that are added, and that is they are sometimes hard to see/find in the listview.
See this example image:
You will notice that the images (noticeably the mouse) is barely viewable, infact if a empty image was added you would not even see it, the number captions come to the rescue here to show there is something actually there.
But I would like to make the images visually easier to see. I thought maybe having another image underneath the transparent images would work - of course though it could not affect the actual image.
So with that in mind, I made a bitmap of a chessboard grid:
I feel this would be the most suitable way of representing transparent areas of the images just like Paint.NET etc does.
To further illustrate this example I have modified the original image to show how it would look, if we had the chessboard bitmap as the underlay image:
Having the chessboard there would indicate there is a list item there in the first place, and the bitmap of the chessboard grid could be darker or an altogether different kind of image. As I said earlier if there was no image you would see nothing at all, so better to show an empty chess grid or other bitmap than nothing.
So, how can I display a second image underneath the original images using a imagelist to give a result similar to the example above? The underneath image could be anything - just another loaded bitmap for example.
If you store the chessboard as the first image (with index 0) and make the overlay image from the current image in the OnGetImageIndex event handler, it will do what you want to. However I'm not sure how efficient is to make the overlay image every time the event is fired.
procedure TForm1.ListView1GetImageIndex(Sender: TObject; Item: TListItem);
begin
// make the overlay (with overlay index 1) from the
// image with index Item.Index + 1
ImageList1.Overlay(Item.Index + 1, 1);
// use the first image from the list as a background
Item.ImageIndex := 0;
// and assign just created overlay index for overlay
Item.OverlayIndex := 1;
end;
I seems that what you need is a TImageList with extra capabilities.
As a starting point, I suggests you to consider TImageListEx described in the book Inside Delphi 2006
Excerpt:
The TImageListEx component is a TImageList descendant that can use the
images from another image list to generate disabled images, which can
be used on toolbars and other user interface elements.
The TImageListEx component is a TImageList descendant that can use the
images from another image list to generate disabled images, which can
be used on toolbars and other user interface elements.
There are several benefits of the TImageListEx component:
It eliminates the need for creating disabled glyphs.
It eliminates the need for adding the disabled glyphs to an additional TImageList component at design time.
It can drastically reduce the size of the .dfm file and of the entire application, especially in large applications that use a lot of
glyphs.
It's extremely fast, taking only milliseconds to disable all images in an image list, even when there are number of images.
It's extremely lightweight. (If you add it to an application that already uses the standard TImageList component, it won't increase the
size of the executable at all, and if you add it to an application
that doesn't use the standard TImageList component, the overhead is
only 2 KB.)
It's far from your requirements but yet detailed enough to show how to extend TImageList.
I am deriving a custom control from TVirtualDrawTree and I am overriding the DoPaintBackground event to draw a background gradient effect for the tree view.
I am also overriding the DoBeforeItemPaint function so I can custom draw the tree view items. However, I can't quite manage to get the items to paint with a transparent background.
Looking into the source for TVirtualDrawTree, it looks as though the item is copied to a TBitmap image and then copied onto the canvas, however, I have tried editing the source and setting the transparency options on the bitmap itself and it still doesn't seem to be working.
I have also tried clearing the canvas before drawing e.g. Canvas.Brush.Style := bsClear and filling the item rect but no joy.
Don't do transparency, cheat!
Drawing the gradient sounds like a lot of work: draw it to a temporary bitmap so you don't need to re-generate it every time DoPaintBackgrdound() is called. Once you have the background in a bitmap you can BitBlt the relevant portion into the Canvas when you handle DoBeforeItemPaint, and you can BitBlt the bitmap to the whole virtual tree when you need the whole background.
This way you don't need to deal with expensive transparency yet for the end user it looks like your items had been painted using transparency. It's a win:win situation.