Close button w TabSheet/PageControl

0

Witam serdecznie.
Może ktoś podrzucić rozwiązanie następującego problemu?
Chciałbym stworzyć na TabSheecie przycisk umożliwiający jego zamknięcie (vide FF 2.0 ;) ).
Nie chodzi mi o kod zamykający TS. Chciałbym się dowiedzieć, w jaki sposób wygenerować button umieszczony w lewym rogu każdej karty. Będę bardzo wdzięczny za pomoc.

0

Cóż, ja mam koncepcję trochę prymitywną, ale może to wystarczy. Ogólna idea jest taka, żeby samodzielnie rysować zakładki. A więc ustalamy rozmiar zakładek na sztywno (TabWidth), żeby oprócz napisu było również miejsce na "przycisk". Żeby samemu rysować, ustawiamy OwnerDraw na true i obsługujemy zdarzenie OnDrawTab. W zdarzeniu będziemy pisać tytuł i rysować bitmapę, która będzie udawać przycisk. Zależnie od właściwości Tag danej zakładki rysowany będzie przycisk zwykły albo wciśnięty. Bitmapki z grafiką przechowujemy sobie gdziekolwiek i jakkolwiek. Żeby wykrywać, że użytkownik wcisnął przycisk napiszemy obsługę zdarzeń OnMouseDown i OnMouseUp.

Szkielet kodu wygląda tak. Komponent PageControl nazwałem pc. Używam dwóch zmiennych btnUp i btnDn przechowujących bitmapy z wyglądem przycisku. We właściwości Tag komponentu przechowuję nr wciśniętej zakładki. Na początku żadna nie jest wciśnięta, więc w inspektorze obiektów ustawiamy Tag na -1.

W zdarzeniu OnDrawTab komponentu PageControl:

begin
// wypisujemy Caption
Control.Canvas.Brush.Color := clBtnFace;
Control.Canvas.FillRect(Rect);
Control.Canvas.TextOut(Rect.Left+3,Rect.Top+3,pc.Pages[TabIndex].Caption);

// sprawdzamy, czy przycisk na zakładce jest wciśnięty...
if pc.Pages[TabIndex].Tag=0 then
   // rysujemy przycisk zwykły
   Control.Canvas.Draw(Rect.Right-btnUp.Width-2,Rect.Top+3,btnUp)
else
   // albo wciśnięty
   Control.Canvas.Draw(Rect.Right-btnDn.Width-2,Rect.Top+3,btnDn);
end;

W zdarzeniu OnMouseDown komponentu PageControl

var tab:integer;   
begin
// pobieramy indeks klikniętej zakładki
tab := pc.IndexOfTabAt(X,Y);
// sprawdzamy, czy kliknięto zakładkę w odległości mniejszej niż 16px od prawego brzegu
if (tab<>-1) and (pc.TabRect(tab).Right-X<16) then begin
   // zapisuję indeks zakładki z wciśniętym przyciskiem
   pc.Tag:=tab;
   // ustawiam w zakładce informację potrzebną podczas rysowania (przycisk wciśnięty)
   pc.Pages[tab].Tag:=1;
   // przerysowuję
   pc.Repaint;
end;

W zdarzeniu OnMouseUp komponentu PageControl

var tab:integer;
begin
// jeśli wcześniej nie wciśnięto przycisku to zignoruj zdarzenie
if pc.Tag<>-1 then begin
   // poprzednio wciśnięty przycisk wraca do normalne pozycji
   pc.Pages[pc.Tag].Tag:=0;
   pc.Repaint;
   // na której zakładce puszczono przycisk
   tab := pc.IndexOfTabAt(X,Y);
   // jeśli na tej samej zakładce wciśnięto i puszczono klawisz myszy
   // w odległości mniejszej niż 16px od prawego brzegu...
   if (tab=pc.Tag) and (pc.TabRect(tab).Right-X < 16) then begin
      // to reagujemy na kliknięcie - tutaj umieść kod zamykania zakładki
      ShowMessage('Zamykam!');
   end;
0

Witam
Dziękuję za odpowiedź, masz ciekawą koncepcję.
Wieczorem zobaczę czy się uda ;)

Pozdrawiam

0

Dzięki wielkie, to.. działa ;)
pozdrawiam ;)

0

Nie, nie, nie ;) To ja dziękuję - jeszcze kilka dni na tym forum i może w końcu się Delphi nauczę, bo w tej chwili pisanie kodu Pascalowego idzie mi jak krew z nosa i co chwilę muszę zaglądać do dokumentacji języka ;-)

0

Może i głupie pytanie ale w jaki sposób przechować obrazek w zmiennej btnUp i btnDn?

0

gdzieś w module:

var btnUp : TBitmap;

w OnCreate formy:

btnUp := TBitmap.Create;
btnUp.LoadFromFile( 'file.bmp' );

w OnDestroy formy:

btnUp.Destroy; // a może btnUp.Free ?

Niech się ludzie od Delphi wypowiedzą, bo nie pisałem nic sensownego w Delphi od ponad dwóch lat - a to piszę z pamięci, bez kompilatora i dokumentacji.

0
Ranides napisał(a)
btnUp := TBitmap.Create;
btnUp.LoadFromFile( 'file.bmp' );

Sypnęło błędami. :-/ Za namową debuggera zmieniłem ten kod na:

btnUp := TImage.Create(btnUp);
btnUp.Picture.LoadFromFile('1.bmp');
btnDn := TImage.Create(btnDn);
btnDn.Picture.LoadFromFile('2.bmp');

Ale jedynie zmniejszyło to nieco liczbę błędów. W liniach:

Control.Canvas.Draw(Rect.Right-btnUp.Width-2,Rect.Top+3,btnUp)
Control.Canvas.Draw(Rect.Right-btnDn.Width-2,Rect.Top+3,btnDn)

wciąż wywoływany jest błąd:
[Error] Unit1.pas(): Incompatible types: 'TGraphic' and 'TImage'

0

A to fascynujące, bo aż się zdziwiłem, siadłem do kompa z kompilatorem, i nie sypie żadnymi błędami elementarny kod:

procedure TForm1.Button1Click(Sender: TObject);
var
  btn : TBitmap;
begin
  btn := TBitmap.Create;
  btn.LoadFromFile('c:\test.bmp');
  Form1.Canvas.Draw(5,5, btn);
  btn.Destroy;
end;

Na pewno nie można zamieniać bitmapy na komponent wizualny typu TImage :| No bez jaj.

0

Hm, rzuciłem jeszcze raz okiem na kod w programie, który chce skompilować i jest on identyczny z twoim, a wciąż występuje błąd:

[Error] Unit1.pas(456): Incompatible types: 'TImage' and 'TBitmap'
[Error] Unit1.pas(457): Undeclared identifier: 'LoadFromFile'

Z ciekawości sprawdziłem kod, który podałeś przed chwilą w nowym projekcie i ten chodzi idealnie, mimo iż są identyczne...

Wiem, że może być ciężko w to uwierzyć, dlatego w załączniku zamieszczam mój kod: http://[już nieważne ;)] Będę wdzięczny jeśli rzucisz okiem.

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0