Czy można ustalić Caption Labela np. 5 px od krawędzi Labela?

0

Chodzi o to, że chciałbym ustawić pod sobą 10 Labeli. Ale żeby napis był odsunięty od krawędzi od kilka pikseli. Każdemu Labelowi chce nadać kolor, dlatego przesunięcie samego Labela nie jest rozwiązaniem.

0

Co ma wspólnego położenie Labela z jego kolorem?

0

Chce malować tło napisu. Konkretnie chodzi mi o to, żeby napis był 5 px od krawędzi rodzica. Jeśli nie zmieniałbym koloru, to mógłbym przesunąć wszystkie Labele w prawo o te 5 px. Ale ja chce żeby kolor był zmieniony przy samej krawędzi rodzica a napis był dalej.

2

Nadpisz metodę Paint z klasy TLabel i maluj co chcesz i jak chcesz:

type
  TLabel = class(StdCtrls.TLabel)
  protected
    procedure Paint(); override;
  end;

type
  TForm1 = class(TForm)
    Label1: TLabel;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TLabel.Paint();
begin
  with Self.Canvas do
  begin
    Brush.Color := clBlack;
    FillRect(ClientRect);

    Font.Color := clWhite;
    TextOut(5, 0, Self.Caption);
  end;
end;

end.

Zwróć uwagę na zawartość metody Paint - za pomocą Self.Canvas uzyskujesz dostęp do płótna komponentu i możesz już malować tak, jak w przypadku każdego innego płótna; Przy czym pamiętaj, że punkt [0,0] to lewy górny róg komponentu, a nie formularza;

Efekt użycia powyższego kodu poniżej; Z lewej jest zrzut formularza podczas projektowania, a po prawej po uruchominiu skompilowanego programu:

label.png

Jak widać działa prawidłowo; Co prawda odstęp od prawej wynosi 6px, ale to zasługa wielkiej litery L, która w tym foncie posiada offset 1px od lewej; W przypadku innych liter czy znaków, offsetu może nie być, albo może być większy - to zasługa użycia standardowych fotnów.

0

Ale w tym przypadku to zadziała do wszystkich Labeli, prawda? Na razie nie mam dostępu do Lazarusa i nie mogę tego przetestować. Żeby nie było, ze was wykorzystuje, sam nie myśląc chciałbym zapytać czy rozwiązanie o którym myślę może być prawidłowe?

type
  WlasnyLabel = class(StdCtrls.TLabel)
  protected
    procedure Paint(); override;
  end;
 
type
  TForm1 = class(TForm)
    Label1: WlasnyLabel;
  end;
 

Albo inne pytanie. Bo tutaj parametry są nadane z góry. A czy jest możliwość przekazania w jakiś sposób koloru czy rozmiaru czcionki albo punktu w którym ma być tekst rysowany?

1

Rozumiem, że dział Newbie. Ale na pewno powinieneś najpierw zacząć od kursu z podstawami obiektowego Pascala. A dopiero później chcieć zmieniać działanie domyślne i rysowanie TLabel czy każdego innego komponentu. To co podał poprzednik to przecież tylko przykład.

Możesz sobie przecież utworzyć tak jak pokazał klasę - przykładowo TMojZajebistyLabelKtoryMaPiecioPixelowyMarginesOdLewej i zadeklarować tylko część lub tylko jedną kontrolkę tego typu. Dodanie dodatkowych własności to też nie problem. Trzeba tylko myśleć co się robi. Ponieważ żeby używać własnej klasy tak jak pokazałeś, należało by przygotować moduł z kodem z procedurą rejestrującą taki komponent na palecie. Następnie taki komponent zainstalować. Robiłem to raczej głównie pod Delphi 7, ale myślę, że również pod Lazarusem nie sprawi to większych problemów.

unit Unit1;

interface

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

type
  TWlasnyLabel = class(StdCtrls.TLabel)
  private
    FTBrainWasUsed : boolean;
  protected
    procedure Paint(); override;
  published
    property TBrainWasUsed : boolean read FTBrainWasUsed write FTBrainWasUsed;
  end;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender : TObject);
  private
  public
    Label1 : TWlasnyLabel;
  end;

var
  Form1 : TForm1;

implementation

{$R *.dfm}

procedure TWlasnyLabel.Paint();
begin
  with Self.Canvas do
  begin
    Brush.Color := clBlack;
    FillRect(ClientRect);
    if FTBrainWasUsed then
    begin
      Font.Color := clWhite;
    end
    else
    begin
      Font.Color := clRed;
    end;
    TextOut(5, 0, Self.Caption);
  end;
end;

procedure TForm1.FormCreate(Sender : TObject);
begin
  Label1 := TWlasnyLabel.Create(Self);
  Label1.Caption := 'Use TBrain, Luck';
  Label1.Parent := Self;
end;

end.
0

Kursy czytam na bieżąco, w trakcie pisania tego co potrzebuje. Kiedyś HTML i CSS się próbowałem w ten sposób nauczyć, ale to nic nie dało. Dopiero metodą prób i błędów i analizy szablonów zrozumiałem co jest co.

Tylko jedno pytanie. Czy procedure Paint(); override; musi być w sekcji protected?

1

Nie musi, ale póki nie wiesz jaka jest w tym różnica - pozostaw w tej samej sekcji; Najwyżej dostaniesz podpowiedź o zmianie jej widoczności, w porównaniu do klasy bazowej:

[Hint] Unit1.pas(12): Overriding virtual method 'TLabel.Paint' has lower visibility (private) than base class 'TLabel' (protected)
0

@dani17: no widzisz, uparcie unikasz kursu Delphi, nawet tego w kompendium na 4p. I masz coraz więcej pytań o banalne podstawy. Skorzystaj więc z mojej dobrej rady - nie olewaj kursu jak przy HTMLu. A nauczysz się więcej.

0

Nie tak, że olewam. Staram się czytać, ale nie potrafię tak czytać cały czas. Więc jak czegoś potrzebuje to staram się czytać. Z czasem poznam to wszystko.
Powiem inaczej. Staram się realizować pewien projekt. I po prostu na bieżąco staram się ten kod poprawiać. Na początku był totalny chaos. Teraz zaczyna to wyglądać rozsądniej.

1

@dani17 - jeśli nie wszystkie etykiety mają być malowane inaczej, to zawsze możesz skorzystać z bazowej metody malującej, wywołując ją słówkiem Inherited; Teraz wystarczy sprawdzić która etykieta jest malowana:

type
  TLabel = class(StdCtrls.TLabel)
  protected
    procedure Paint(); override;
  end;

type
  TForm1 = class(TForm)
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TLabel.Paint();
begin
  { jeśli to druga etykieta - malujemy po swojemu... }
  if Self = Form1.Label2 then
    with Self.Canvas do
    begin
      Brush.Color := clBlack;
      FillRect(ClientRect);

      Font.Color := clGray;
      TextOut(5, 0, Self.Caption);
    end
  else
    { ...w przeciwnym razie wywołujemy metodę z bazowej klasy }
    inherited;
end;

end.

Efekt poniżej - z lewej formularz podczas projektowania, z prawej po uruchomieniu programu:

labels.png

0

Za tworzenie własnych komponentów się raczej nie będę brał jeszcze. Więc pewnie skorzystam z tej ostatniej opcji. Spróbowałem zrobić tak jak napisałem tworząc klasę TWlasnyLabel. Wszystko działało tak jak chciałem. Ale rozumie, że nie można tak zrobić?

0

Wskaż gdzie napisaliśmy, że nie wolno?

0
olesio napisał(a):

Ponieważ żeby używać własnej klasy tak jak pokazałeś, należało by przygotować moduł z kodem z procedurą rejestrującą taki komponent na palecie. Następnie taki komponent zainstalować.

0

@dani17 - to zależy; Ty potrzebujesz jedynie innego malowania labelka, więc jedyne co potrzebujesz przerobić to właśnie metodę Paint - reszta może działać standardowo;

Musisz jednak pamiętać, że nadpisując metodę Paint, musisz uwzględnić także zawijanie tekstu; Jeśli tego nie potrzebujesz, to kod który podałem wyżej będzie działał prawidłowo; Natomiast AutoSize odpada, bo trzeba by uwzględnić dodatkowy offset od lewej (5px); Standardowe mechanizmy tego nie uwzględniają, więc i rozmiar zawsze byłby zbyt mały;

Więc jeśli potrzebujesz prostego efektu, jak namalowanie jednolinijkowego tekstu, bez konieczności automatycznego dostosowywania rozmiaru komponentu, to rozwiązanie masz wyżej; W przeciwnym razie trzeba by albo spróbować przedefiniować istniejące mechanizmy w klasie TLabel, albo użyć wygooglowanego gotowego komponentu, albo ostatecznie napisać własny komponent od podstaw; Jednak aby napisać własną etykietę, trzeba posiadać chociaż minimalną wiedzę z zakresu OOP i budowania komponentów; Oczywiście to nie jest aż takie trudne - trzeba tylko trochę poczytać i spróbować, ewentualnie pytać na forum, jeśli coś będzie niejasne.

0

@dani17 może pod Lazarusem nie trzeba. Ale ja sprawdzałem pod Delphi 7. I tak się nie dało bez tworzenia komponentu dynamicznie, jak pokazałem.

0

Żeby nie musieć sprawdzać czy malowana jest konkretna instancja etykiety - trzeba stworzyć osobny komponent, zarejestrować go instrukcją RegisterComponent i przebudować Lazarusa; Wtedy komponent zostanie dodany do palety i będzie go można normalnie wybrać i położyć na formularzu, bez konieczności ingerowania w kod modułu formularza, który z tego komponentu korzysta;

W przeciwnym razie zmiany dotkną wszystkich komponentów tej samej klasy, w obrębie całego formularza; Aby tego uniknąć, trzeba albo dodać warunek w metodzie Paint (dość brzydki sposób), albo napisać osobny komponent i go zainstalować.

0

Właśnie ja tego chciałem użyć do komponentów tworzonych dynamicznie.
W skrócie wygląda to tak:

 
type
  TWlasnyLabel = class(StdCtrls.TLabel)
  protected
    procedure Paint; override;
  end; 

procedure TWlasnyLabel.Paint;
var
  GornyMargines: Integer;
begin
  with Self.Canvas do
  begin
    Brush.Color := Self.Color;
    FillRect(ClientRect);
    GornyMargines := Round((Self.Height - Self.Canvas.TextHeight(Self.Caption)) / 2);
    Font.Color := Self.Font.Color;
    TextOut(10, GornyMargines, Self.Caption);
  end;
end;

for I := 1 to IloscOpcjiUstawien do
    begin
      LabelUstawieniaOpcje[I] := TWlasnyLabel.Create(PanelMG);
      with LabelUstawieniaOpcje[I] do
        begin
          AutoSize := False;
          Parent := PanelMG;
          Font.Size := 13;
          Font.Color := $00340C01;
          Left := 0;
          Height := 27;
          case I of
            1: Caption := UstawieniaJezyka(9);
            2: Caption := 'Tryb Ekranu';
          end;
          case I of
            1: Top := 0;
          else
            Top := LabelUstawieniaOpcje[I - 1].Top + LabelUstawieniaOpcje[I - 1].Height;
          end;
          if (Canvas.TextWidth(LabelUstawieniaOpcje[I].Caption) + 50) > SzerokoscOpcji then
            SzerokoscOpcji := Canvas.TextWidth(LabelhUstawieniaOpcje[I].Caption) + 50;
          case (I mod 2) of
            0: Color := $00FFFFFF;
            1: Color := $00F8F8F8;
          end;
        end;
    end;
  for I := 1 to IloscOpcjiUstawien do
    LabelUstawieniaOpcje[I].Width := SzerokoscOpcji + 50;

I wszystko działa tak jak bym chciał.

Ewentualnie mam pytanie. Czy można to zedytować tak aby po najechaniu na Label napis przesunął się o 5 px w prawo, a po zjechaniu wracał do startowych parametrów?

0

Czy można to zedytować tak aby po najechaniu na Label napis przesunął się o 5 px w prawo, a po zjechaniu wracał do startowych parametrów?

Można, wystarczy dodać jedno pole logiczne i "wpiąć" się w obsługę komunikatów CM_MOUSEENTER i CM_MOUSELEAVE aby móc modyfikować nowe pole; A potem to już wystarczy użyć je przy malowaniu:

type
  TLabel = class(StdCtrls.TLabel)
  private
    FHovered: Boolean;
  protected
    procedure Paint(); override;
  protected
    procedure CMMouseEnter(var AMessage: TMessage); message CM_MOUSEENTER;
    procedure CMMouseLeave(var AMessage: TMessage); message CM_MOUSELEAVE;
  public
    constructor Create(AOwner: TComponent); override;
  end;

type
  TForm1 = class(TForm)
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
  end;

var
  Form1: TForm1;

implementation

uses Math;

{$R *.dfm}

constructor TLabel.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FHovered := False;
end;

procedure TLabel.Paint();
var
  intOffset: Integer;
  clrCaption: TColor;
begin
  intOffset  := IfThen(FHovered, 5, 0);
  clrCaption := IfThen(FHovered, clBlue, clBlack);

  with Self.Canvas do
  begin
    Brush.Color := TForm(Self.Parent).Color;
    FillRect(Self.ClientRect);

    Font.Color := clrCaption;
    TextOut(intOffset, 0, Self.Caption);
  end;
end;

procedure TLabel.CMMouseEnter(var AMessage: TMessage);
begin
  inherited;

  FHovered := True;
  Self.Invalidate();
end;

procedure TLabel.CMMouseLeave(var AMessage: TMessage);
begin
  inherited;

  FHovered := False;
  Self.Invalidate();
end;

end.

Poniżej efekt działania powyższego kodu - z lewej zrzut z edytora formularzy, z prawej zrzut okna po uruchomieniu programu i najechaniu kursorem na środkową etykietę:

labels.png

Testowane pod Delphi, jednak Lazarus także powinien obsługiwać taką konstrukcję.

0

Od kilku dni to próbuję zrobić, ale nawet ten kod od @furious programming nie chce zadziałać. Wyświetla się kilka błędów.

 
unit1.pas(17,50) Error: Identifier not found "TMessage"
unit1.pas(17,74) Error: Identifier not found "CM_MOUSEENTER"
unit1.pas(17,74) Error: Illegal expression after message directive
unit1.pas(18,50) Error: Identifier not found "TMessage"
unit1.pas(18,74) Error: Identifier not found "CM_MOUSELEAVE"
unit1.pas(18,74) Error: Illegal expression after message directive

Nie wiem jak to rozwiązać niestety. Kombinowałem, zmieniałem ten kod kilkanaście razy, próbowałem dopisywać coś co nalazłem na stronach, ale to nic nie dało. Czasami udało się uruchomić program, ale nie było żadnego efektu, wiec było to napisane źle.

0

Musisz dodać odpowiednie moduły do listy Uses, bo tak jak napisane masz w błędach - typy i stałe są nieznane; Dodaj moduł LMessages i wszystko powinno grać.

0

Nie wiem czy zrobiłem dobrze, oprócz LMessages, dodałem jeszcze Messages i StrUtils żeby IfThen mogło zadziałać. Ale wyskoczył jeszcze jeden błąd

clrCaption := IfThen(FHovered, clBlue, clBlack);

unit1.pas(99,51) Error: Incompatible type for arg no. 3: Got "TGraphicsColor", expected "AnsiString"

I Jeszcze jedno pytanie. Chciałbym aby każdy Label miał dwa inne kolory. Np. Label1 będzie miał tekst czatny, a po najechaniu tekst bedzie się robił zielona. Label2 będzie zielony, a po najechaniu czerwony. clrCaption := IfThen(FHovered, clBlue, clBlack); w tym miejscu zapewne wystarczy zamiast stałej wartości podać po prostu Self.Font.Color. Ale problem jest z tym drugim kolorem. Czy można dodać właściwość Font.ColorDodatkowy do TLabel? Czy trzeba tworzyć komponent od podstaw?

0

Nie wiedzieć czemu, ale funkcje IfThen wpakowali do modułu Math (te od liczb) i StrUtils (tę od łańcuchów); Nie wiedziałem, że będziesz chciał z nich skorzystać, więc nic o tym nie pisałem; Ale w przyszłości sam szukaj takich informacji - wystarczy wpisać w Google free pascal ifthen function i masz u samej góry przydatne linki;

Chciałbym aby każdy Label miał dwa inne kolory. Np. Label1 będzie miał tekst czatny, a po najechaniu tekst bedzie się robił zielona.

Żeby każdy label miał możliwość korzystania z innych kolorów, definiowanych w Inspektorze Obiektów? Zrób sobie osobny komponent instalowany normalnie, a nie przez wcześniej podaną magię; Dodaj kilka dodatkowych pól, w których będziesz trzymał pary kolorów (dla fontu i tła) dla stylu normalnego i po najechaniu; Zdefiniuj także właściwości, aby były widoczne w okienku Inspektora oraz użyj ich w metodzie Paint;

Jeżeli nie trafiłem z odpowiedzią, to opisz problem sensowniej i dokładniej;

Czy można dodać właściwość Font.ColorDodatkowy do TLabel? Czy trzeba tworzyć komponent od podstaw?

Nie musisz, jednak jeśli dodasz nowy kolor w taki sposób jak poprzednio - nie będziesz go widział w Inspektorze Obiektów; Pozostanie Ci dynamiczne nadawanie kolorów etykietom (czyli w kodzie programu); Najlepiej jak stworzysz sobie taki komponent, dziedzicząc od TLabel; Dodaj co tak potrzebujesz i go zainstaluj - dzięki temu będziesz mógł wstawiać na formularz pojedyczne komponenty, które nie będą powodowały zmiany wyglądu i zachowania innych etykiet na formularzu, które mają być malowane standardowo.

0

Tak, to rozwiąże moją sytuację ale chciałem na razie uniknąć tworzenia własnych komponentów, jednak może lepiej spróbować już teraz.

1

Tak wiedza na pewno Ci nie zaszkodzi, więc spróbuj; Przyjdzie kiedyś czas, że będziesz potrzebował różnych niestandardowych komponentów i będziesz już wiedział jak je zrobić; Tylko najpierw poczytaj materiały na temat programowania obiektowego, bo bez tego ani rusz.

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