Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi Transparentes Bild soll nur an bestimmten stellen angeklickt (https://www.delphipraxis.net/51791-transparentes-bild-soll-nur-bestimmten-stellen-angeklickt.html)

Hallo_Thomas 18. Aug 2005 21:39


Transparentes Bild soll nur an bestimmten stellen angeklickt
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo,

Ich wollte das angehängte Bild(Die farbe weiss soll transparnet sein) als Button darstellen, dabei soll er nur reagieren, wenn er auf dem Haus ist!

TheMiller 18. Aug 2005 21:43

Re: Transparentes Bild soll nur an bestimmten stellen angekl
 
Überprüfe doch beim Klick auf das Bild, welche Farbe "unter" dem Mauszeiger liegt. Wenn es weiss ist, dann lass das Programm nicht reagieren...

Hallo_Thomas 18. Aug 2005 22:59

Re: Transparentes Bild soll nur an bestimmten stellen angekl
 
Welche Componente meinst Du?, Ich hab das Bild mal als Image, Speedbutton und BitBtn dargestellt, habs aber irgendwie nich geschafft?

faux 18. Aug 2005 23:34

Re: Transparentes Bild soll nur an bestimmten stellen angekl
 
Es geht auch ganz simpel:
Mal zwei Shapes draus. Ein Dreieck und drunter eine Rechteck....

Hallo_Thomas 19. Aug 2005 00:33

Re: Transparentes Bild soll nur an bestimmten stellen angekl
 
Ich bin da noch nich ganz so bewandert in den sachen, wie mach ich ein Dreieck?

Luckie 19. Aug 2005 00:48

Re: Transparentes Bild soll nur an bestimmten stellen angekl
 
Zitat:

Zitat von Hallo_Thomas
Welche Componente meinst Du?, Ich hab das Bild mal als Image, Speedbutton und BitBtn dargestellt, habs aber irgendwie nich geschafft?

Mit einer Schaltfläche lässt sich das natürlich nicht so einfach realisieren, aber mit einem TImage ist das ganze kein Problem, wie es DJ-SPM gesagt hat.

Robert Marquardt 19. Aug 2005 07:04

Re: Transparentes Bild soll nur an bestimmten stellen angekl
 
Man kann Tricks mit der VCL-internen Message CM_HITTEST treiben.
Man behandelt diese Message und liefert nur bei nicht transparenten Pixeln eine 1 sonst eine 0 in Msg.Result.
Die Position des Klicks ist in Msg.LParam enthalten.

Hallo_Thomas 19. Aug 2005 20:30

Re: Transparentes Bild soll nur an bestimmten stellen angekl
 
Ich bin den sachen wohl noch recht unbelesen, und auch nicht wirklich viel Literatur zu CM_HITTEST gefunden, wieverbinde ich den Befehl mit TImage, damits funktioniert?

Puhbaehr 20. Aug 2005 04:27

Re: Transparentes Bild soll nur an bestimmten stellen angekl
 
Hallo Hallo_Thomas *g*,

also, da ich selbst noch am Experimentieren bin was Delphi betrifft konnte ich mit dem oben genannten Vorschlägen wenig Anfangen. Bis eben wusste ich nicht einmal wie man die Farbe hinter der Maus ausliest usw..

Ich habe auch nach z.B. CM_HITTEST gesucht und habe einiges damit zusammen gebastelt.
Aber es hat nicht richtig bzw. überhaupt nicht funktioniert, weil ich
a) vielleicht nicht das nötige Wissen habe oder/und
b) es so einfach nicht funktioniert

Aber ich habe mal für dich und einfach weil mich dieses Thema selbst sehr interessiert etwas weiter rumgesucht und bin zu folgendem Ergebnis gekommen: *erklär*

Du benötigst im Prinzip nichts weiter als die aktuelle Position der Maus ausgehend vom TImage-Objekt.
Diese erfährst du z.B. mit dem Ereignis OnMouseMove:

Delphi-Quellcode:
procedure TForm1.Image1MouseMove (Sender: TObject; Shift: TShiftState; X, Y: Integer);
 begin
  // x, y = Mausposition im TImage
 end;
Ähnliches Ergebnis bringt folgende Funktion:
Delphi-Quellcode:
Mouse.CursorPos.X;
Mouse.CursorPos.Y;
Allerdings mit dem Nachteil das du damit die absolute Position am Bildschrim zurück bekommst.
Du müsstest von diesem Wert noch die Fensterposition und die Position des TImage im Fenster abrechnen was nicht einfach wird da (zumindest ist mir keine Funktion bekannt) Höhe der Titelleiste, Rahmenbreite und ähnliches nicht bekannt sind.
Da du aber sowieso die aktuelle Position von deinem TImage-Objekt ausgehend haben willst ist erstens die bessere Wahl.

Nun benötigst du nur noch die Farbe an der Position.
Das machen wir mit:
Delphi-Quellcode:
Image1.Canvas.Pixels [X, Y];
Zurück erhalten wir die Farbe als Hexadezimalwert.

Schrauben wir beides zusammen erhalten wir das hier:
Delphi-Quellcode:
procedure TForm1.Image1MouseMove (Sender: TObject; Shift: TShiftState; X, Y: Integer);
 begin
  if (Image1.Canvas.Pixels[x, y] = $FFFFFF) then
   begin
    MausDarfKlicken := false;
   end
  else
   begin
    MausDarfKlicken := true;
   end;
 end;
Nun kann der so gewonnene Wert gespeichert und in einem OnClick-Ereignis ausgewertet werden:
Delphi-Quellcode:
procedure TForm1.Image1Click(Sender: TObject);
 begin                                    
  if MausDarfKlicken then
   begin
    // mache irgendetwas z.B.
    showmessage ('Ins schwarze Getroffen! ;)');
   end;
 end;
Fertig sieht das ganze z.B. so aus:

Delphi-Quellcode:
unit UForm;

interface

uses
  Classes,
  Graphics,
  Controls,
  Forms,
  Dialogs,
  ExtCtrls;

type
  TForm1 = class(TForm)
    Image1 : TImage;
    procedure Image1Click (Sender: TObject);
    procedure Image1MouseMove (Sender: TObject; Shift: TShiftState; X, Y: Integer);
    private MausDarfKlicken : boolean;
   end;

var
  Form1 : TForm1;

implementation

{$R *.DFM}

procedure TForm1.Image1Click(Sender: TObject);
 begin                                    
  if MausDarfKlicken then
   begin
    // mache irgendetwas z.B.
    showmessage ('Ins schwarze Getroffen! ;)');
   end;
 end;

procedure TForm1.Image1MouseMove (Sender: TObject; Shift: TShiftState; X, Y: Integer);
 begin                            // $FFFFFF = clWhite = entspricht weiß
  if (Image1.Canvas.Pixels[x, y] = $FFFFFF) then
   begin
    MausDarfKlicken := false;
   end
  else
   begin
    MausDarfKlicken := true;
   end;
 end;

end.
Sicherlich nicht sehr elegant aber für den Zweck und zur Erklärung reicht es.

Robert Marquardt hatte sicherlich vor für MouseMove und OnClick eigene Behandlungsroutinen zu schreiben.
Wie schon oben erwähnt versuchte ich selbiges ebenfalls was mir nur Teilweise gelang.

Ich hoffe das Problem ist nun geklärt?

Bei Fragen stehen ich und auch andere sicherlich gerne zur Verfügung.

Bis dann!

Gruß, Robert (ja, so heiß ich auch ;))


PS: An einen Mod: Kann ich auch Textformatierungen innerhalb der Codeformatierung anwenden? (z.B. Hervorheben durch Fettschrift oder farblich hervorheben)

Edit: Delphiformatierung statt Codeformatierung verwendet ([code] durch [delphi] ersetzt)

Puhbaehr 20. Aug 2005 05:03

Re: Transparentes Bild soll nur an bestimmten stellen angekl
 
Ergänzend zum obigem:

cm_hittest ist eine Konstante die u.a. bei der Behandlung von Botschaften (Nachrichten --> Hier im Forum suchenMessage) gebraucht wird. Sobald eine Nachricht dieses "Typs" eintrifft wird darauf die definierte Prozedur aufgerufen.
Es ist Möglich z.B. eine OnClick-Behandlungsroutine selbst zu bauen die dann gleich die Mauskoordinaten mitliefert.
So wird nicht ständig beim Überfahren mit der Maus über die TImage die Koordinaten und die Farbe ausgewertet sondern erst beim Klick (spart Ressorcen).

Bei mir hatte das aber nicht wirklich geklappt da ich es nicht geschafft habe das Ereignis nur auf das TImage-Objekt anzuwenden.

Wenn du das selbst nocheinmal versuchen möchtest:
Stichwörter: Hier im Forum suchenMessage, Hier im Forum suchenTMessage und Hier im Forum suchenMsg, Hier im Forum suchenTMsg und vorallem z.B. Hier im Forum suchencm_mouseenter (gefunden hier)

Nebenbei: Schöne Grüße nach Dresden ;)

Robert Marquardt 20. Aug 2005 05:57

Re: Transparentes Bild soll nur an bestimmten stellen angekl
 
Eigentlich geht es um eine Ableitung von TImage. Dort ueberschreibt man die Message CM_HITTEST und liefert im Result der TMessage-Struktur
je nachdem ob die Maus ueber einem transparenten Pixel ist 0 oder 1. Die Mausposition ist im LParam der Struktur kodiert.
Danach fuehlt sich die Komponente nur angeklickt wenn sie auf einem nicht-transparenten Pixel getroffen wird.
Genaugenommen ist sie jetzt auch fuer Klicks transparent.
TJvImage der JVCL hat das bereits implementiert.

turboPASCAL 20. Aug 2005 06:14

Re: Transparentes Bild soll nur an bestimmten stellen angekl
 
@Robert Marquardt JVCL Schleichwerbung ? :wink:

@Puhbaehr Warum nicht einfach das MousUp- bzw. MouseDown-Ereignis des Images verwenden ?

Delphi-Quellcode:
procedure TForm1.Image1MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  if (Shift = [ssRight]) and (Image1.Canvas.Pixels[X, Y] <> clWhite) then
  begin
    // Was dann gemacht werden Soll...
    // ...
  end;
end;
Ich verwende meistens die Farbe clFuchsia (RGB = 255, 0, 255) für Transparenz, da clFuchsia nicht so oft vorkommt. IMHO ist clWhite ist nicht immer die beste Wahl.

// Edit:

Zitat:

Zitat von Puhbaehr
PS: An einen Mod: Kann ich auch Textformatierungen innerhalb der Codeformatierung anwenden? (z.B. Hervorheben durch Fettschrift oder farblich hervorheben)

Ich nix Mod, aber : [color] innerhalb [code]/[delphi]

Robert Marquardt 20. Aug 2005 06:22

Re: Transparentes Bild soll nur an bestimmten stellen angekl
 
Weil das die Komponente nicht fuer Klicks durchsichtig macht.

Puhbaehr 20. Aug 2005 12:26

Re: Transparentes Bild soll nur an bestimmten stellen angekl
 
Zitat:

Zitat von turboPASCAL
@Puhbaehr Warum nicht einfach das MousUp- bzw. MouseDown-Ereignis des Images verwenden ?

Stimmt stimmt, daran hatte ich noch gar nicht gedacht ;)

Zitat:

Zitat von turboPASCAL
Zitat:

Zitat von Puhbaehr
PS: An einen Mod: Kann ich auch Textformatierungen innerhalb der Codeformatierung anwenden? (z.B. Hervorheben durch Fettschrift oder farblich hervorheben)

Ich nix Mod, aber : [color] innerhalb [code]/[delphi]

Habe mich mal dem Thema angeschlossen :)

Zitat:

Zitat von turboPASCAL
Ich verwende meistens die Farbe clFuchsia (RGB = 255, 0, 255) für Transparenz, da clFuchsia nicht so oft vorkommt. IMHO ist clWhite ist nicht immer die beste Wahl.

Zudem rate ich auch. Da ich auch bei meinem Bild das ich ins Beispiel eingebunden hatte merkte, dass viele Stellen weiß sind und da die 'Maus' auch nicht reagiert hatte.
Aber wie wäre es statt FF00FF (255, 0, 255) lieber eine eher seltenere Farbe nimmst. Denn kommt deine Freundin und will das Programm in einem pfiffigem Pink dann musst du auch umbauen.
Interessanter wäre da z.B. FE01FE (254, 1, 254) zu verwenden.

Aber nun gut :)

Puhbaehr 20. Aug 2005 12:27

Re: Transparentes Bild soll nur an bestimmten stellen angekl
 
Zitat:

Zitat von Robert Marquardt
Weil das die Komponente nicht fuer Klicks durchsichtig macht.

Zeig uns mal bitte wie wenn du Zeit hast (etwas Code als Beispiel meine ich) :) Danke

Luckie 20. Aug 2005 12:29

Re: Transparentes Bild soll nur an bestimmten stellen angekl
 
Zitat:

da (zumindest ist mir keine Funktion bekannt) Höhe der Titelleiste, Rahmenbreite und ähnliches nicht bekannt sind.
Nur so am Rande: MSDN-Library durchsuchenGetSystemMetrics. ;)

Khabarakh 20. Aug 2005 12:34

Re: Transparentes Bild soll nur an bestimmten stellen angekl
 
Zitat:

Zitat von Luckie
Zitat:

da (zumindest ist mir keine Funktion bekannt) Höhe der Titelleiste, Rahmenbreite und ähnliches nicht bekannt sind.
Nur so am Rande: MSDN-Library durchsuchenGetSystemMetrics. ;)

Oder gleich Delphi-Referenz durchsuchenTControl.ScreenToClient :wink: .

Robert Marquardt 20. Aug 2005 16:44

Re: Transparentes Bild soll nur an bestimmten stellen angekl
 
Hier eine aeltere Komponente von mir. Die ist nicht ideal konstruiert, aber funktioniert.
Wichtig ist, das PicUp und PicDown sich moeglichst nur in der Farbgebung unterscheiden.
Es ist sehr unangenehm wenn das Bild sich beim Betreten mit der Maus aendert und sich dabei der Hittest veraendert.
Damit ist die Maus wieder draussen und das Bild schaltet zurueck usw usf.

Mit CM_MOUSEENTER und CM_MOUSELEAVE gibt es in Delphi ein paar Macken. Manchmal wird das CM_MOUSELEAVE nicht generiert.
Man kann beispielsweise ueber ein Kontextmenue das man mit ESC abbricht die Komponente heimlich verlassen.
Delphi-Quellcode:
unit MouseImage;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  ExtCtrls;

type
  TOnMouseEvent = procedure(Msg: TWMMouse) of object;

  TMouseImage = class(TImage)
  private
    FOnMouseEnter: TOnMouseEvent;
    FOnMouseLeave: TOnMouseEvent;
    FPicDown: TPicture;
    FPicUp: TPicture;
    FDown: Boolean;
    FEntered: Boolean;
    procedure SetPicDown(Value: TPicture);
    procedure SetPicUp(Value: TPicture);
    procedure SetDown(Value: Boolean);
    procedure SetEntered(Value: Boolean);
  protected
    procedure Loaded; override;
    procedure WMMouseEnter(var Msg: TWMMouse); message CM_MOUSEENTER;
    procedure WMMouseLeave(var Msg: TWMMouse); message CM_MOUSELEAVE;
    procedure CMHitTest(var Msg: TWMMouse); message CM_HITTEST;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    property Down: Boolean read FDown write SetDown;
    property Entered: Boolean read FEntered write SetEntered;
    property PicDown: TPicture read FPicDown write SetPicDown;
    property PicUp: TPicture read FPicUp write SetPicUp;
    property OnMouseEnter: TOnMouseEvent read FOnMouseEnter write FOnMouseEnter;
    property OnMouseLeave: TOnMouseEvent read FOnMouseLeave write FOnMouseLeave;
  end;

procedure Register;

implementation

{$R *.RES}

(*******************************************************************************)

procedure Register;
begin
  RegisterComponents('3rdParty', [TMouseImage]);
end;

(*******************************************************************************)

constructor TMouseImage.Create;
begin
  inherited;
  FPicDown := TPicture.Create;
  FPicUp  := TPicture.Create;
  FDown   := False;
  FEntered := False;
end;

(*******************************************************************************)

destructor TMouseImage.Destroy;
begin
  FreeAndNil(FPicDown);
  FreeAndNil(FPicUp);
  inherited;
end;

(*******************************************************************************)

procedure TMouseImage.Loaded;
begin
  Picture.Assign(PicUp);
end;

(*******************************************************************************)

procedure TMouseImage.WMMouseEnter(var Msg: TWMMouse);
var
 P: TControl;
begin
  inherited;
  P := Self;
  repeat
    P := P.Parent;
  until (P = nil) or (P is TForm);
  if (P = nil) or TForm(P).Active then
  begin
    Entered := True;
    if Assigned(FOnMouseEnter) then
      FOnMouseEnter(Msg);
  end;
end;

(*******************************************************************************)

procedure TMouseImage.WMMouseLeave(var Msg: TWMMouse);
var
 P: TControl;
begin
  inherited;
  P := Self;
  repeat
    P := P.Parent;
  until (P = nil) or (P is TForm);
  if (P = nil) or TForm(P).Active then
  begin
    Entered := False;
    if Assigned(FOnMouseLeave) then
      FOnMouseLeave(Msg);
  end;
end;

(*******************************************************************************)

procedure TMouseImage.CMHitTest(var Msg: TWMMouse);
begin
  inherited;
  if Assigned(PicUp) and Assigned(PicUp.Bitmap) and Transparent and
    (Msg.XPos < PicUp.Bitmap.Width) and (Msg.YPos < PicUp.Bitmap.Height) and
    (PicUp.Bitmap.Canvas.Pixels[Msg.XPos, Msg.YPos] = (Picture.Bitmap.TransparentColor and $FFFFFF)) then
    Msg.Result := 0;
end;

(*******************************************************************************)

procedure TMouseImage.SetPicUp(Value: TPicture);
begin
  FPicUp.Assign(Value);
end;

(*******************************************************************************)

procedure TMouseImage.SetPicDown(Value: TPicture);
begin
  FPicDown.Assign(Value);
end;

(*******************************************************************************)

procedure TMouseImage.SetDown(Value: Boolean);
begin
  FDown  := Value;
  Entered := Value;
end;

(*******************************************************************************)

procedure TMouseImage.SetEntered(Value: Boolean);
begin
  FEntered := Value;
  if Down or Entered then
    Picture.Assign(PicDown)
  else
    Picture.Assign(PicUp);
end;

end.
Die Tests in WMMouseEnter und WMMouseLeave stellen sicher das die Komponente nur auf die Maus reagiert wenn sie auf der aktiven Form ist.
Es ist selten gewuenscht das die komponente reagiert, wenn sie auf einer im Hintergrund liegenden Form liegt.
CMHitTest ist das Herz der Komponente. Es wird getestet ob die Maus wirklich ueber dem Komponentenrechteck liegt und ob der Pixel unter dem Cursor transparent ist.
inherited; hat bereits dafuer gesorgt, das Msg.Result 1 ist, da dies die Standardantwort eines TImage ist.
Die Konsequenz ist, das die Komponente jetzt auch fuer Klicks transparent ist.

Hallo_Thomas 22. Aug 2005 14:57

Re: Transparentes Bild soll nur an bestimmten stellen angekl
 
Liste der Anhänge anzeigen (Anzahl: 1)
@Robert Marquardt
Toll, hab mich jetzt in den letzten Tagen damit beschäftigt, da ich mit den selbstgemachten Komponenten noch nich so auskenne, vom Grundgerüst her, würdch sagen, isses genau das was ich suche.

Nun zu meiner Frage
wie schon gesagt, mein wissen über eigene Komonenten ist noch nicht so gross.Also hab ich sie wie folft verucht einzubinden:


Delphi-Quellcode:
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure FormShow(Sender: TObject);
  private
    { Private-Deklarationen }
    Haus:          TBitmap;
    Bild:              TMouseImage;
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  Haus := TBitmap.create;
  Haus.LoadFromFile(ExtractFilePath(ParamStr(0)) + '\Bilder\aktiv.bmp');
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  Haus.Free;
end;

procedure TForm1.FormShow(Sender: TObject);
begin
  Bild := TMouseImage.create(self);
  Bild.parent := self;
  Bild.Autosize := True;
  Bild.Transparent := True;
  Bild.Picture.Assign(Haus);
  Bild.Top := 10;
  Bild.Left := 10;
  Bild.PicUp.create;
  Bild.PicDown.create;
  Bild.PicUp.Assign(Haus);
  Bild.PicDown.LoadFromFile(ExtractFilePath(ParamStr(0)) + '\Bilder\unten.bmp');
end;
end.
Das klappt auch so weit, nur leider soll das Bildchen ja nicht beim darüberfahren nach unten gedrückt werden, sondern nur so ne Art OnMouseDown Eigenschaft.


Alle Zeitangaben in WEZ +1. Es ist jetzt 06:44 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz