Tak na prawdę chodzi mi o to, żeby stworzyć przycisk, ale nie o standardowym kształcie, prostokąta, czy okrągu, a np. z prawej strony jest zwykła linia, z lewej u góry jest róg zaokrąglony, a na dole ten zaokrąglony róg jest połączony z dolną linią, linią skośną. Do tej pory jako przycisk wstawiałem TImage, ale po prostu był to prostokąt, więc i tak reagował jak powinien. Teraz też mógłbym zrobić jakiś plik graficzny z przezroczystością, ale TImage wstawia się jako prostokąt i tą przezroczystość traktował by jako część obrazka.
- Rejestracja:prawie 20 lat
- Ostatnio:około 5 godzin
- Lokalizacja:Gorlice
lucasp17 napisał(a):
Teraz też mógłbym zrobić jakiś plik graficzny z przezroczystością, ale TImage wstawia się jako prostokąt i tą przezroczystość traktował by jako część obrazka.
No to czemu tego nie zrobisz? Podstawa to funkcja tworząca region z obrazka (możesz znaleźć w Google ja w przykładzie też używam pierwszej znalezionej). Ponieważ TImage nie ma uchwytu więc nie można bezpośrednio nadać mu kształtu funkcją SetWindowRgn ale raczej nic nie stoi na przeszkodzie aby sprawdzać czy kliknięto obszar o którym nam chodzi przy zdarzeniu OnMouseDown (i ew. OnMouseUp) całość moze wyglądać np. tak:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls;
type
TRGBArray = array[0..32767] of TRGBTriple;
PRGBArray = ^TRGBArray;
TForm1 = class(TForm)
Image1: TImage;
procedure Image1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ Private declarations }
function CreateRegion(Bmp: TBitmap): THandle;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
function TForm1.CreateRegion(Bmp: TBitmap): THandle;
var
X, Y, StartX:Integer;
Excl: THandle;
Row: PRGBArray;
TransparentColor: TRGBTriple;
begin
// Change the format so we know how to compare
// the colors
Bmp.PixelFormat := pf24Bit;
// Create a region of the whole bitmap
// later we will take the transparent
// bits away
Result := CreateRectRGN(0, 0, Bmp.Width, Bmp.Height);
// Loop down the bitmap
for Y := 0 to Bmp.Height - 1 do
begin
// Get the current row of pixels
Row := Bmp.Scanline[Y];
// If its the first get the transparent
// color, it must be the top left pixel
if Y = 0 then
begin
TransparentColor := Row[0];
end;
// Reset StartX (-1) to indicate we have
// not found a transparent area yet
StartX := -1;
// Loop across the row
for X := 0 to Bmp.Width do
begin
// Check for transparency by comparing the color
if(X <> Bmp.Width) and
(Row[X].rgbtRed = TransparentColor.rgbtRed) and
(Row[X].rgbtGreen = TransparentColor.rgbtGreen) and
(Row[X].rgbtBlue = TransparentColor.rgbtBlue) then
begin
// We have (X <> Bmp.Width) in the clause so that
// when we go past the end of the row we we can
// exclude the remaining transparent area (if any)
// If its transparent and the previous wasn't
// remember were the transparency started
if StartX = -1 then
begin
StartX := X;
end;
end
else
begin
// Its not transparent
if StartX > -1 then
begin
// If previous pixels were transparent we
// can now exclude the from the region
Excl := CreateRectRGN(StartX, Y, X, Y + 1);
try
// Remove the exclusion from our original region
CombineRGN(Result, Result, Excl, RGN_DIFF);
// Reset StartX so we can start searching
// for the next transparent area
StartX := -1;
finally
DeleteObject(Excl);
end;
end;
end;
end;
end;
end;
procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
if PtInRegion(Image1.Tag, X, Y) then
ShowMessage('dziala');
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Image1.Tag:= CreateRegion(Image1.Picture.Bitmap);
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
DeleteObject(Image1.Tag);
end;
end.
Image1 to oczywiście "przycisk" i znajduje się w nim bitmapa i ma ustawiony Transparent na True.

- Rejestracja:ponad 12 lat
- Ostatnio:7 miesięcy
- Postów:6610
Każdą kontrolkę dziedziczącą po TWinControl (posiadającą uchwyt) możesz przyciąć do dowolnego kształtu używając SetWindowRgn
(niestety TImage się nie łapie). Po takiej operacji nie trzeba już sprawdzać czy się kliknęło w "narysowaną" część czy w "schowaną".
Dokładnie tak - każdy koponent, który dziedziczy po klasie TWinControl
, czyli de facto posiada swój uchwyt, bo jego m.in. trzeba podać w funkcji SetWindowRgn; Tę funkcję można wykorzystać z dowolnymi komponentami posiadającymi uchwyt, a także z formularzami;
Niestety TImage
dziedziczy z klasy TGraphicControl
, a ta z TControl
, więc nie ma uchwytu i zastosować wymienionej funkcji nie można; Sprawdź rozwiązanie kAzka oraz poczytaj materiały z sieci.

- Rejestracja:ponad 19 lat
- Ostatnio:2 miesiące
abrakadaber napisał(a):
... niestety TImage się nie łapie ...
Owszem, ale łapie sięTPanel
na którym umieszczono tenTImage
.
- Rejestracja:prawie 20 lat
- Ostatnio:około 5 godzin
- Lokalizacja:Gorlice
Ale czego tu można nie rozumieć? Dałem gotowca @_13th_Dragon dodał że nawet nie trzeba sprawdzać funkcją PtInRegion czy kliknięto narysowany obszar przycisku tylko wystarczy że Image będzie na Panelu (a więc Panel będzie jego rodzicem) wtedy można dostosować kształt Panelu funkcją SetWindowRgn a leżący na nim Image automatycznie będzie miał ten sam kształt. Wszystko jak w moim poprzednim kodzie podaję tylko co się zmieniło:
procedure TForm1.FormCreate(Sender: TObject);
begin
Panel1.Tag:= CreateRegion(Image1.Picture.Bitmap);
SetWindowRgn(Panel1.Handle, Panel1.Tag, True);
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
DeleteObject(Panel1.Tag);
end;
procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
ShowMessage('działa');
end;
- Rejestracja:ponad 12 lat
- Ostatnio:ponad 2 lata
- Postów:131
Panel1.Handle
To było problemem. Teraz na pewno zadziała. Po prostu ja nie wiedziałem skąd mam wziąć ten uchwyt dla poszczególnych komponentów. Szukałem jakichś funkcji które by to robiły. Nie wiedziałem, że wystarczy to zrobić w ten sposób.
Uchwyt to nic innego jak unikalna liczba naturalna, nadawana zapewne przez systemowe mechanizmy, za pomocą której identyfikuje się okna w systemie; Pod pojęciem okien rozumie się wszelkie formularze oraz komponenty posiadające uchwyt (czyli tak jak napisałem wcześniej, dziedziczące po klasie TWinControl
w VCL, a pod WinAPI wszelkie komponenty tworzone np. za pomocą CreateWindow);
Takie komponenty oraz wszelkie formularze posiadają odpowiednie właściwości, zwracające uchwyty np. typu THandle
(HWND
z WinAPI); Dodatkowo, systemowe biblioteki zawierają i udostępniają szereg funkcji do pobierania wszelkich uchwytów, jak np. FindWindow, GetActiveWindow czy GetDesktopWindow;
Jak widzisz jest sporo rzeczy do poznania.
- Rejestracja:ponad 12 lat
- Ostatnio:ponad 2 lata
- Postów:131
Jest sporo i z czasem je poznaję. Za tego posta bardzo dziękuję po dużo mi wyjaśnił. Ja czytałem na temat uchwytów, ale tak na prawdę w 100% nie byłem pewien czym one są. Ale i tak największy problem miałem właśnie z jego znalezieniem.
Nie opowiadaj... Wpisz sobie w wyszukiwarce Wikipedii słówko uchwyt, a zobaczysz listę artykułów, w której na pierwszej pozycji (są dwie) masz artykuł Uchwyt (informatyka); Oczywiście w polskiej wersji niewiele ktoś napisał, ale już w angielskiej jest więcej i sensowniej - Handle (computing);
Jak widzisz znaleźć coś jest łatwo - trzeba tylko wiedzieć jak zapytać o to Google/Wikipedię;
A jeśli chodzi o same uchwyty, to nie służą one tylko i wyłącznie do identyfikowania okien czy komponentów; Są jeszcze np. uchwyty do bibliotek (Lazarusowy specjalny typ LibHandle
), uchwyty do bitmap (HBITMAP
), ikon (HICON
), palet (HPALETTE
), kursorów (HCURSOR
), kontekstów urządzeń (HDC
), plików (HFILE
), fontów (HFONT
) i mnóstwa, mnóstwa innych rzeczy, których uchwyty zawierają prefiks H
;
To tylko liczby, więc równie dobrze mógłby być jeden typ liczb naturalnych dla ich wszystkich, ale ze względu na czytelność jest ich aż tyle (i dobrze).

.Handle
, bo nie wszystko ma uchwyty; Musisz wiedzieć co je ma, a co nie, a jeśli coś ma uchwyt to jak go pobrać; Zapisanie .Handle
oznacza skorzystanie z właściwości zwracającej uchwyt, najczęściej z pola FHandle
w klasie, które jest niewidoczne, bo prywatne; A nie wszystkie klasy komponentów mają tę właściwość, dlatego nie wystarczy wiedzieć co dopisać;
abrakadaber