Recent

Author Topic: Is it possible to have a transparent 'form'?  (Read 12152 times)

J-G

  • Hero Member
  • *****
  • Posts: 992
Is it possible to have a transparent 'form'?
« on: October 09, 2016, 02:11:41 am »
I've searched the forum and found out how to make a form transparent using AlphaBlendValue := 0 but that simply makes the form invisible - not transparent. I would like to have a thin line (say - 20 pixels) around the edge of the screen that is visible but the centre still shows the desktop - with the desktop still 'live' ie. usable.

Is this even possible? am I wasting my time looking for method?

I know I can turn off the standard three top right controls and presume I can incorporate a [close] button within the border.
« Last Edit: October 09, 2016, 11:34:58 am by J-G »
FPC 3.0.0 - Lazarus 1.6 &
FPC 3.2.2  - Lazarus 2.2.0 
Win 7 Ult 64

rvk

  • Hero Member
  • *****
  • Posts: 6953
Re: Is it possible to have a transparent 'form'?
« Reply #1 on: October 09, 2016, 02:22:41 pm »
You're not exactly explaining why you want this but here it goes...
Making the form transparent while keeping components visible (if you want that).

Taken from here:
http://lazplanet.blogspot.nl/2013/04/make-your-forms-transparent.html

Code: Pascal  [Select][+][-]
  1. uses Windows;
  2.  
  3. const
  4.   LWA_COLORKEY = 1;
  5.   LWA_ALPHA = 2;
  6.   LWA_BOTH = 3;
  7.   WS_EX_LAYERED = $80000;
  8.   GWL_EXSTYLE = -20;
  9.  
  10. {Function SetLayeredWindowAttributes Lib "user32" (ByVal hWnd As Long, ByVal Color As Long, ByVal X As Byte, ByVal alpha As Long) As Boolean }
  11. function SetLayeredWindowAttributes(hWnd: longint; Color: longint;
  12.   X: byte; alpha: longint): bool stdcall; external 'USER32';
  13.  
  14. {not sure how to alias these functions here ????   alias setwindowlonga!!}
  15. {Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long }
  16. function SetWindowLongA(hWnd: longint; nIndex: longint;
  17.   dwNewLong: longint): longint stdcall; external 'USER32';
  18.  
  19. {Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long) As Long }
  20. function GetWindowLongA(hWnd: longint; nIndex: longint): longint stdcall;
  21.   external 'user32';
  22.  
  23. procedure SetTranslucent(ThehWnd: longint; Color: longint; nTrans: integer);
  24. var
  25.   Attrib: longint;
  26. begin
  27.   {SetWindowLong and SetLayeredWindowAttributes are API functions, see MSDN for details }
  28.   Attrib := GetWindowLongA(ThehWnd, GWL_EXSTYLE);
  29.   SetWindowLongA(ThehWnd, GWL_EXSTYLE, attrib or WS_EX_LAYERED);
  30.   {anything with color value color will completely disappear if flag = 1 or flag = 3  }
  31.   SetLayeredWindowAttributes(ThehWnd, Color, nTrans, 1);
  32. end;
  33.  
  34. procedure TForm1.FormCreate(Sender: TObject);
  35. var
  36.   Transparency: longint;
  37. begin
  38.   Self.Color := clRed;
  39.   Transparency := Self.Color;
  40.   SetTranslucent(Self.Handle, Transparency, 0);
  41. end;

A form with one button will result in attached image.

Fungus

  • Sr. Member
  • ****
  • Posts: 354
Re: Is it possible to have a transparent 'form'?
« Reply #2 on: October 09, 2016, 02:27:33 pm »
There is no cross-platform way of doing what you want. There are Windows ways of using a specific color for transparency, see this:

https://msdn.microsoft.com/en-us/library/windows/desktop/ms633540%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396

This will ensure that only the specified color is transparent - all other colors remain solid / opaque.

If cross-platform is minded, you should look for a way to obtaining a screen dump of whatever is behind your form and paint it onto your form and create the border afterwards.

J-G

  • Hero Member
  • *****
  • Posts: 992
Re: Is it possible to have a transparent 'form'?
« Reply #3 on: October 09, 2016, 02:46:45 pm »
Thanks again RVK.

Yes that seems to be close to what I want  -  essentially I would like to have a full screen clock which is simply a border around the full screen and 'dots' indicating the hour, minute and second. The algorithms for location of the dots is my real interest along with times of moon phases and the like - what horologists term 'Complications' which will be shown in visible components - probably just TLabels though I may also use transparent .PNG images.

As yet I haven't been able to remove the [close] Icon or TIcon but I haven't done much research on this  -  it's obviously not a simple 'untick'.

@Fungus
Your post came in as I was typing, thanks.

I currently have little or no interest in cross-platform, I have far too much to learn about the Windows environment  :D

I will look at both links provided. Can you confirm that the 'Desktop' would still be 'live' ie. Program icons can still be double clicked  ?
 
FPC 3.0.0 - Lazarus 1.6 &
FPC 3.2.2  - Lazarus 2.2.0 
Win 7 Ult 64

Fungus

  • Sr. Member
  • ****
  • Posts: 354
Re: Is it possible to have a transparent 'form'?
« Reply #4 on: October 09, 2016, 02:52:55 pm »
As yet I haven't been able to remove the [close] Icon or TIcon but I haven't done much research on this  -  it's obviously not a simple 'untick'.

Set the forms BorderStyle property to bsNone :)

rvk

  • Hero Member
  • *****
  • Posts: 6953
Re: Is it possible to have a transparent 'form'?
« Reply #5 on: October 09, 2016, 02:53:23 pm »
As yet I haven't been able to remove the [close] Icon or TIcon but I haven't done much research on this  -  it's obviously not a simple 'untick'.
Maybe not a simple "untick" but a simple setting of BorderStyle to bsNone will remove the form-border completely.

You do have to create an option to exit your "program" but you can do that via a button.

If you combine this with the translucent code you can get a image (any shape) transparent on the desktop. Although... the form itself will still be square. So if you need to be able to click something inside (or behind) the form it will require some extra coding.

J-G

  • Hero Member
  • *****
  • Posts: 992
Re: Is it possible to have a transparent 'form'?
« Reply #6 on: October 09, 2016, 06:17:24 pm »
Well, the code pointed to by RVK works perfectly, I have a full screen form with buttons, no border but with a 'frame' onto which I can plot markers, buttons which respond to the action needed and the desktop is visible beneath it......

.... only problem is just that -- the desktop is beneath it and therefore inaccessible.

I've tried all values of FormStyle fsNormal, fsSplash, fsChild etc. (obviusly fsStayOnTop would be quite wrong!) but I can't see a style that puts it at the 'bottom' or 'back'. I've also tried setting DefaultMonitor to 'dmDesktop'.

So it looks as if my initial fears were well grounded - yes it's possible but it is also totally useless except to make a PC dedicated to the one task.


FPC 3.0.0 - Lazarus 1.6 &
FPC 3.2.2  - Lazarus 2.2.0 
Win 7 Ult 64

Fungus

  • Sr. Member
  • ****
  • Posts: 354
Re: Is it possible to have a transparent 'form'?
« Reply #7 on: October 09, 2016, 07:26:39 pm »
I'm not sure that I fully understand what you are trying to achieve. Of course a form will block whatever is beneath it - if it didn't you would have multiple windows reachting to the same events and this would be a plague. Getting about this can be quite a difficult and cumbersome task because you will need to first locate the window (using EnumWindows and EnumChildWindows) and then translate the message from your form to the coords of that window and then post it to the window. It can be done, but there's no two-line sollution to the problem.

So.. If the task is to put some floating buttons on top of all other windows, you should create a borderless, stayontop form for those buttons.

https://msdn.microsoft.com/en-us/library/windows/desktop/ms633497(v=vs.85).aspx
https://msdn.microsoft.com/en-us/library/windows/desktop/ms633494(v=vs.85).aspx

rvk

  • Hero Member
  • *****
  • Posts: 6953
Re: Is it possible to have a transparent 'form'?
« Reply #8 on: October 09, 2016, 07:40:52 pm »
You can easily make your form "click-through" with layered windows.

Do this:
Code: Pascal  [Select][+][-]
  1. type
  2.   TForm1 = class(TForm)
  3.   private
  4.   protected
  5.     procedure CreateParams(var Params: TCreateParams); override;
  6. ...
  7. procedure TForm1.CreateParams(var Params: TCreateParams);
  8. begin
  9.   inherited;
  10.   Params.ExStyle := Params.ExStyle or WS_EX_LAYERED or WS_EX_TRANSPARENT;
  11. end;

If you set the WindowState to wsMaximized and the FormStyle to fsSystemStayOnTop and BorderStyle to bsNone you'll have exactly what you want.

One problem though... you can't interact with your components because they are click through too :)

Complete unit-code (1 form with 1 button and FormCreate-event):

Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, LCLType,
  9.   StdCtrls;
  10.  
  11. type
  12.  
  13.   { TForm1 }
  14.  
  15.   TForm1 = class(TForm)
  16.     Button1: TButton;
  17.     procedure FormCreate(Sender: TObject);
  18.   private
  19.     { private declarations }
  20.   protected
  21.     procedure CreateParams(var Params: TCreateParams); override;
  22.   public
  23.     { public declarations }
  24.   end;
  25.  
  26. var
  27.   Form1: TForm1;
  28.  
  29. implementation
  30.  
  31. {$R *.lfm}
  32.  
  33. const
  34.   LWA_COLORKEY = 1;
  35.   LWA_ALPHA = 2;
  36.   LWA_BOTH = 3;
  37.   WS_EX_LAYERED = $80000;
  38.   GWL_EXSTYLE = -20;
  39.  
  40. {Function SetLayeredWindowAttributes Lib "user32" (ByVal hWnd As Long, ByVal Color As Long, ByVal X As Byte, ByVal alpha As Long) As Boolean }
  41. function SetLayeredWindowAttributes(hWnd: longint; Color: longint;
  42.   X: byte; alpha: longint): bool stdcall; external 'USER32';
  43.  
  44. {not sure how to alias these functions here ????   alias setwindowlonga!!}
  45. {Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long }
  46. function SetWindowLongA(hWnd: longint; nIndex: longint;
  47.   dwNewLong: longint): longint stdcall; external 'USER32';
  48.  
  49. {Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long) As Long }
  50. function GetWindowLongA(hWnd: longint; nIndex: longint): longint stdcall;
  51.   external 'user32';
  52.  
  53. procedure SetTranslucent(ThehWnd: longint; Color: longint; nTrans: integer);
  54. var
  55.   Attrib: longint;
  56. begin
  57.   {SetWindowLong and SetLayeredWindowAttributes are API functions, see MSDN for details }
  58.   Attrib := GetWindowLongA(ThehWnd, GWL_EXSTYLE);
  59.   SetWindowLongA(ThehWnd, GWL_EXSTYLE, attrib or WS_EX_LAYERED);
  60.   {anything with color value color will completely disappear if flag = 1 or flag = 3  }
  61.   SetLayeredWindowAttributes(ThehWnd, Color, nTrans, 1);
  62. end;
  63.  
  64. procedure TForm1.CreateParams(var Params: TCreateParams);
  65. begin
  66.   inherited;
  67.   Params.ExStyle := Params.ExStyle or WS_EX_LAYERED or WS_EX_TRANSPARENT;
  68. end;
  69.  
  70. procedure TForm1.FormCreate(Sender: TObject);
  71. begin
  72.   Self.WindowState := wsMaximized;
  73.   Self.FormStyle := fsSystemStayOnTop;
  74.   Self.BorderStyle := bsNone;
  75.   Self.Color := clRed;
  76.   SetTranslucent(Self.Handle, Self.Color, 0);
  77. end;
  78.  
  79. end.

If you do need interaction with components on the form you'll need to go another route and that's creating a non-square form. I think this is possible in Delphi but I've never done it in Lazarus.
« Last Edit: October 09, 2016, 07:45:07 pm by rvk »

User137

  • Hero Member
  • *****
  • Posts: 1791
    • Nxpascal home
Re: Is it possible to have a transparent 'form'?
« Reply #9 on: October 09, 2016, 10:41:17 pm »
You can also do this kind of app crossplatform without any transparency. You'll need to make 4 thin borderless forms, 1 for each side of the screen.

J-G

  • Hero Member
  • *****
  • Posts: 992
Re: Is it possible to have a transparent 'form'?
« Reply #10 on: October 09, 2016, 11:10:58 pm »
Thanks for your continued interest RVK. Yes, the ability to interact with the components on my form (though they will be few) is imperative.

I've copied your code and compiled it but find that the resulting program isn't transparent. It is borderless and immovable but 'grey'. My program IS transparent but adding the property fsSystemStayOnTop (the others were already in place) doesn't make the underlying desktop icons available but does leave the components available.

It's still been a useful exercise and I've learned a good deal today which will help in my understanding of graphic manipulation.

@fungus
Your post snook in under RVKs so I've only just seen it. I've had a brief look at the information in the links you provide but feel that I need to understand a great deal more about manipulating graphic primitives before I can get my head around EnumWindows  :)   but thanks for your input.

FPC 3.0.0 - Lazarus 1.6 &
FPC 3.2.2  - Lazarus 2.2.0 
Win 7 Ult 64

J-G

  • Hero Member
  • *****
  • Posts: 992
Re: Is it possible to have a transparent 'form'?
« Reply #11 on: October 09, 2016, 11:22:33 pm »
You can also do this kind of app crossplatform without any transparency. You'll need to make 4 thin borderless forms, 1 for each side of the screen.

Oddly enough I did look at doing just that with the image of the dial - I hadn't thought of using 4 forms. There will be interesting maths and manipulation of hour, minute and seconds markers at the screen corners but that is where my real interest lays anyway  :)  Getting another pair of eyes on a problem is always beneficial.

I'll be moving in that direction tomorrow!
FPC 3.0.0 - Lazarus 1.6 &
FPC 3.2.2  - Lazarus 2.2.0 
Win 7 Ult 64

rvk

  • Hero Member
  • *****
  • Posts: 6953
Re: Is it possible to have a transparent 'form'?
« Reply #12 on: October 09, 2016, 11:24:23 pm »
I've copied your code and compiled it but find that the resulting program isn't transparent. It is borderless and immovable but 'grey'.
Maybe you didn't connect the FormCreate-event to the form. Anyway... attached is the same unit but in a working project. See if that works (although like I said the component/button is also click-through so doesn't work).

Yes, the ability to interact with the components on my form (though they will be few) is imperative.
Ok, in that case you really need to go for a variable shaped form. Could you say something about the form of the component you have on your form. Can is be drawn with one line (be it not rectangle).

I'll look into creating a non-rectangle form in Lazarus tomorrow.

rvk

  • Hero Member
  • *****
  • Posts: 6953
Re: Is it possible to have a transparent 'form'?
« Reply #13 on: October 09, 2016, 11:32:49 pm »
A very small example of a circular form (but it can be any shape you want).

Code: Pascal  [Select][+][-]
  1. uses LCLIntf, LCLType;
  2.  
  3. procedure TForm1.FormCreate(Sender: TObject);
  4. var
  5.   MyRegion: HRGN;
  6. begin
  7.   MyRegion := CreateEllipticRgn(8, 27, 324, 341);
  8.   SetWindowRgn(Handle, MyRegion, True);
  9.   // DeleteObject(MyRegion); // woops. Do not free the region handle. Windows will do that.
  10. end;

So if you can create a Region around your component (you can use multiple region commands) it's as simple as above code. You could also set the position in the FormCreate and make the form non-movable (or only movable by your command).

There is also a possibility to create a region/shape by image (but I don't know this by heart so would have to look it up).

Would above method work for you?

Here is a Delphi example of how you could combine it with different components. Only the components are visible while the underlying form doesn't do anything (like it doesn't exist).
http://edn.embarcadero.com/article/26277
« Last Edit: October 09, 2016, 11:48:17 pm by rvk »

J-G

  • Hero Member
  • *****
  • Posts: 992
Re: Is it possible to have a transparent 'form'?
« Reply #14 on: October 10, 2016, 12:24:48 am »
I've copied your code and compiled it but find that the resulting program isn't transparent. It is borderless and immovable but 'grey'.
Maybe you didn't connect the FormCreate-event to the form.
That's certainly a posibility.
Anyway... attached is the same unit but in a working project. See if that works (although like I said the component/button is also click-through so doesn't work).
Yes - that works  and yes the button doesn't  :D
Yes, the ability to interact with the components on my form (though they will be few) is imperative.
Ok, in that case you really need to go for a variable shaped form. Could you say something about the form of the component you have on your form. Can is be drawn with one line (be it not rectangle).
There would only be an active button to close the project  - closing via the Task Manager should not be considered a default state! I haven't yet figured out how to make a program [start] automatically so there might need to be a start button as well.  Other than that, there would be Tlabels to display Day, Date, Moon phase - possibly Easter, Vernal and Autumnal Eqiunox

I'll look into creating a non-rectangle form in Lazarus tomorrow.
I see you have already posted a procedure (I've not had time to investigate it yet) to create an elliptical region - how did you guess that the ellipse is my favourite mathematical figure !!   :D :D

It never occurred to me that anything other than a rectangular form (OK square as well) was even possible.

User 137's suggestion of four forms looks promising but it would actually have to be 5 forms - 4 around the screen edge and one to hold the Day, Date etc. that I've just described and that needn't be transparent, it could be border-less and positioned anywhere I wished. Being border-less would be less important so could just as easily be a 'normal' form with the usual controls.

FPC 3.0.0 - Lazarus 1.6 &
FPC 3.2.2  - Lazarus 2.2.0 
Win 7 Ult 64

 

TinyPortal © 2005-2018