[x]
Posted via EE Mobile

Search, ask, and monitor your questions on the go with EE Mobile. Visit Experts Exchange from your mobile device and never be out of touch again.

09/16/2005 at 02:45AM PDT, ID: 21563691
[x]
Attachment Details
[x]
The Solution Rating System

With so many solutions, how can you tell which solutions are most likely to help you and which ones are not? To provide you with a tool to use, we rate our solutions based on various elements that most accurately determine if a solution is a quality solution. To explain what factors affect the solution rating, here are the elements we take into consideration when formulating our solution rating.

  • The Grade of the Solution
  • The Zone Rank of the Expert Providing the Solution
  • The Number of Author and Expert Comments
  • The Number of Experts Contributing
  • The Feedback of the Community

Your Input Matters
Because of the way the system is set up, the most important variable in this equation is you. As a member of Experts Exchange, you are able to cast your vote on the quality of the solutions in regard to how complete, accurate, helpful and easy to understand each solution is. When you provide your feedback, each rating is adjusted accordingly. So, if you see a solution that has a poor rating that you think is a good solution, let us know by rating it. As you do, the rating will be adjusted and will become more accurate for other members of our site.

If you have any suggestions that you would like to make for our rating system, please ask a question in the Suggestions Zone of Community Support.

Thank you!

8.8

My WS_EX_TRANSPARENT window does not receive WM_PAINT after the window behind it re-paints.

Asked by rpmccormi77 in Delphi Programming

Tags: ws_ex_transparent

Project:  SKINbedder.  Embeds other programs windows to my TWindowContainer component (CustomControl), then overlays semi-transparent PNG graphics with multiple "Hot-Spot" buttons through a TSkinLayer component(CustomControl).  (mostly used to "skin" iGuidance GPS navigation software)

Problem:  When the embedded window repaints its self, my buttons disappear.  They are not re-drawn because no WM_PAINT message gets received (even though according to MSDN, a WS_EX_TRANSPARENT window should receive a WM_PAINT whenever anything underneath it is re-drawn).  I cannot continually repaint because it ruins the semi-transparency, causes flicker, and eats CPU time.  I cannot use Rgn for a transparency effect because it wouldn't work for semi-transparency plus I want to intercept mouse clicks even on the transparent parts (no click-through).

Question:  I need a way to know when my semi-transparent buttons have been erased by the embedded window repainting its self so I can repaint my buttons.  Basically I need to 1) Intercept all WM_PAINT messages to it (although I'm not sure that would work if it is repainting due to its own internal event), 2) Assign the embedded window an OnPaint or actually a "AfterPaint" event (probably impossible), or 3) Figure out why my component doesn't always receive WM_PAINT whenever anything behind it changes (as WS_EX_TRANSPARENT controls should according to M$)

Quirk / Possible alternate solution:  If you minimize then restore my app, everything is always drawn perfectly.  I guess this is because the embedded window paints first and then I paint.  I have tried to continually repaint but also continually SendMessage(EmbeddedWindowHandle, WM_PAINT, 0, 0) first.  It didn't repaint its self over my buttons though so that did not solve the ruining semi-transparency bug as I had hoped.

Source Code:  Below is the source code to my TSkinLayer.  Any suggestions about any part of the component are welcome ;).  This and TWindowContainer are my first 2 components ever (and are based on TmodderBut which was posted here on experts-exchange for an earlier version of this same program).


[code]

unit SkinLayer;

interface

uses
//  Dialogs,
  Windows, Messages, Classes, Graphics, Controls, Forms, PNGImage;

type
  THotSpots = record
    Top: integer;
    Bottom: integer;
    Left: integer;
    Right: integer;
    OnPressDown: String;
    OnPressUp: String;
    Toggle: Boolean;
   end;

  TSkinLayer = class(TCustomControl)
   private
   protected
    FNorm, FDown: TPNGObject;
    FHotSpots: Array of THotSpots;
    procedure WMEraseBkgnd(var Msg: TWMEraseBkgnd); message WM_ERASEBKGND;
    procedure CreateParams(var Params: TCreateParams); override;
    procedure Paint; override;
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
    procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
   public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure WriteHotSpot(Index: integer; Top, Bottom, Left, Right: integer; OnPressUp, OnPressDown: String);
    function ReadHotSpot(Index: integer; var Top: Integer; var Bottom: Integer; var Left: Integer; var Right: integer; var OnPressUp: String; var OnPressDown: String): Boolean;
    property Canvas;
   published
    property NormalBmp: TPNGObject read FNorm write FNorm;
    property DownBmp: TPNGObject read FDown write FDown;
    property Height default 1;
    property Width default 1;
    property Visible default False;
    property Cursor default crCross;
    property Name;
    property Anchors;
    property Left;
    property Top;
    property OnMouseDown;
    property OnMouseUp;
   end;

procedure Register;

implementation

uses
  SysUtils;

procedure Register;
 begin
  RegisterComponents('RPM', [TSkinLayer]);
 end;

//--- WMEraseBkgnd -----------------------------------------------------------\\
procedure TSkinLayer.WMEraseBkgnd(var Msg: TWMEraseBkgnd);
 begin
  Msg.Result := 1;
 end;
//--- End WMEraseBkgnd -------------------------------------------------------//

//--- CreateParams -----------------------------------------------------------\\
procedure TSkinLayer.CreateParams(var Params: TCreateParams);
 begin
  inherited CreateParams(Params);
  with Params do
   begin
    WindowClass.lpszClassName := 'TSkinLayer';
    WindowClass.hbrBackground := 0;
    WindowClass.style := WindowClass.style OR CS_HREDRAW OR CS_VREDRAW OR CS_OWNDC OR CS_SAVEBITS;
    Style := Style OR WS_CHILD OR WS_CLIPSIBLINGS AND NOT(WS_TABSTOP) AND NOT(WS_VISIBLE);
    ExStyle := ExStyle OR WS_EX_TRANSPARENT;
   end;
 end;
//--- End CreateParams -------------------------------------------------------//

//--- Create -----------------------------------------------------------------\\
constructor TSkinLayer.Create(AOwner: TComponent);
 begin
  inherited Create(AOwner);
  ControlStyle := [csCaptureMouse, csClickEvents, csFixedWidth, csFixedHeight, csReflector];
  Width := 1;
  Height := 1;
  Cursor := crCross;
  Visible := False;
  FNorm := TPNGObject.Create;
  FDown := TPNGObject.Create;
 end;
//--- End Create -------------------------------------------------------------//

//--- Destroy ----------------------------------------------------------------\\
destructor TSkinLayer.Destroy;
 begin
  FreeAndNil(FNorm);
  FreeAndNil(FDown);
  inherited Destroy;
 end;
//--- End Destroy ------------------------------------------------------------//

//--- WriteHotSpot -----------------------------------------------------------\\
procedure TSkinLayer.WriteHotSpot(Index: integer; Top, Bottom, Left, Right: integer; OnPressUp, OnPressDown: String);
 begin
  if (length(FHotSpots) < (Index + 1)) then
    SetLength(FHotSpots, Index + 1);
  FHotSpots[Index].Top := Top;
  FHotSpots[Index].Bottom := Bottom;
  FHotSpots[Index].Left := Left;
  FHotSpots[Index].Right := Right;
  FHotSpots[Index].OnPressUp := OnPressUp;
  FHotSpots[Index].OnPressDown := OnPressDown;
  FHotSpots[Index].Toggle := False;
 end;
//--- End WriteHotSpot -------------------------------------------------------//

//--- ReadHotSpot ------------------------------------------------------------\\
function TSkinLayer.ReadHotSpot(Index: integer; var Top: Integer; var Bottom: Integer; var Left: Integer; var Right: integer; var OnPressUp: String; var OnPressDown: String): Boolean;
 begin
  if Index < length(FHotSpots) then
   begin
    Top := FHotSpots[Index].Top;
    Bottom := FHotSpots[Index].Bottom;
    Left := FHotSpots[Index].Left;
    Right := FHotSpots[Index].Right;
    OnPressUp := FHotSpots[Index].OnPressUp;
    OnPressDown := FHotSpots[Index].OnPressDown;
    Result := True;
   end
  else
    Result := False;
 end;
//--- End ReadHotSpot --------------------------------------------------------//

//--- Paint ------------------------------------------------------------------\\
procedure TSkinLayer.Paint;
var
  Index: Integer;
 begin
  Parent.Update;  //Reduces re-draw errors while draging a window in front of us.

  //Draw FNorm and then overlay FDown if button is Toggled (bad method!)
  if not(FNorm.Empty) then
   begin
    FNorm.Draw(Canvas, Rect(0, 0, FNorm.Width, FNorm.Height));
    if not(FDown.Empty) then
     begin
      Index := 0;
      while (Index < length(FHotSpots)) do
       begin
        if (FHotSpots[Index].Toggle) then
          FDown.Draw(Canvas, Rect(FHotSpots[Index].Left, FHotSpots[Index].Top, FHotSpots[Index].Right, FHotSpots[Index].Bottom));
        Index := Index + 1;
       end;
     end;
   end;
 end;
//--- End Paint --------------------------------------------------------------//

//--- MouseDown --------------------------------------------------------------\\
procedure TSkinLayer.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
  Index: Integer;
 begin
  Index := 0;
  while (Index < length(FHotSpots)) do
   begin
    if (X > FHotSpots[Index].Left) and (X < FHotSpots[Index].Right) and (Y > FHotSpots[Index].Top) and (Y < FHotSpots[Index].Bottom) then
     begin
      if (FHotSpots[Index].OnPressDown = '') then
       begin
        //No Down Command: Just paint FDown to HotSpot.
        if (not FDown.Empty) then
          FDown.Draw(Canvas, Rect(FHotSpots[Index].Left, FHotSpots[Index].Top, FHotSpots[Index].Right, FHotSpots[Index].Bottom));
       end
      else if not(FHotSpots[Index].Toggle) then
       begin
        //Non-Toggle or 1st-Click: Run command & paint FDown to HotSpot.
        inherited;  //Command is run in external OnMouseDown Event (assigned in MainForm on create)
        if (not FDown.Empty) then
          FDown.Draw(Canvas, Rect(FHotSpots[Index].Left, FHotSpots[Index].Top, FHotSpots[Index].Right, FHotSpots[Index].Bottom));
        //If Toggle, set flag.
        if (FHotSpots[Index].OnPressUp <> '') then
          FHotSpots[Index].Toggle := True;
       end
      else
        //Toggle-Button 2nd-Click: Do nothing, but handle next up.
        FHotSpots[Index].Toggle := False;
     end;
    Index := Index + 1;
   end;
 end;
//--- End MouseDown ----------------------------------------------------------//

//--- MouseUp ----------------------------------------------------------------\\
procedure TSkinLayer.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
  Index: Integer;
 begin
  Index := 0;
  while (Index < length(FHotSpots)) do
   begin
    if (X > FHotSpots[Index].Left) and (X < FHotSpots[Index].Right) and (Y > FHotSpots[Index].Top) and (Y < FHotSpots[Index].Bottom) then
     begin
      if (FHotSpots[Index].OnPressUp = '') then
       begin
        //No Up Command: Just paint FNorm to HotSpot.
        if not(FNorm.Empty) then
          FNorm.Draw(Canvas, Rect(FHotSpots[Index].Left, FHotSpots[Index].Top, FHotSpots[Index].Right, FHotSpots[Index].Bottom));
       end
      else if not(FHotSpots[Index].Toggle) then
       begin
        //Non-Toggle or 2nd-Click: Run Command and paint FNorm to HotSpot
        inherited;  //Command is run in external OnMouseDown Event (assigned in MainForm on create)
        if not(FNorm.Empty) then
          FNorm.Draw(Canvas, Rect(FHotSpots[Index].Left, FHotSpots[Index].Top, FHotSpots[Index].Right, FHotSpots[Index].Bottom));
       end;
        //If 1st-Click on Toggle-Button, do nothing.
     end;
    Index := Index + 1;
   end;
 end;
//--- End MouseUp ------------------------------------------------------------//

end.

[/code]
[+][-]09/23/05 07:51 AM, ID: 14944736

At Experts Exchange, members can ask their questions to thousands of technology professionals, also known as Experts. Experts compete and collaborate to answer those questions by leaving comments like this one.

Start your 30-day free trial to view this Expert Comment or ask the Experts your question.

 
[+][-]09/23/05 12:15 PM, ID: 14947447

Often, when Experts are collaborating with members who have asked questions, they will request additional information about the problem. Askers respond with an author comment like this one.

Start your 30-day free trial to view this Author Comment or ask the Experts your question.

 
[+][-]09/26/05 11:32 AM, ID: 14961325

View this solution now by starting your 30-day free trial. Setting up your free trial is quick, easy, and secure. We will return you to this solution, unlocked, when you're done.

 

About this solution

Zone: Delphi Programming
Tags: ws_ex_transparent
Sign Up Now!
Solution Provided By: Slick812
Participating Experts: 2
Solution Grade: A
 
 
[+][-]05/06/06 05:07 AM, ID: 16621263

Experts Exchange has a courteous staff of administrators who help members get the most out of the website by means of administrative comments like this one.

Start your 30-day free trial to view this Administrative Comment or ask the Experts your question.

 
[+][-]05/10/06 01:15 AM, ID: 16646479

Experts Exchange has a courteous staff of administrators who help members get the most out of the website by means of administrative comments like this one.

Start your 30-day free trial to view this Administrative Comment or ask the Experts your question.

 
[+][-]05/10/06 05:27 PM, ID: 16654330

Often, when Experts are collaborating with members who have asked questions, they will request additional information about the problem. Askers respond with an author comment like this one.

Start your 30-day free trial to view this Author Comment or ask the Experts your question.

 
[+][-]05/11/06 12:10 AM, ID: 16655824

Experts Exchange has a courteous staff of administrators who help members get the most out of the website by means of administrative comments like this one.

Start your 30-day free trial to view this Administrative Comment or ask the Experts your question.

 
[+][-]05/11/06 01:05 AM, ID: 16656093

Often, when Experts are collaborating with members who have asked questions, they will request additional information about the problem. Askers respond with an author comment like this one.

Start your 30-day free trial to view this Author Comment or ask the Experts your question.

 
[+][-]05/11/06 11:45 AM, ID: 16661533

At Experts Exchange, members can ask their questions to thousands of technology professionals, also known as Experts. Experts compete and collaborate to answer those questions by leaving comments like this one.

Start your 30-day free trial to view this Expert Comment or ask the Experts your question.

 
 
Loading Advertisement...
20090824-EE-VQP-74