Dwa wiersze Caption na TPanel?

0

Jak w temacie - da sie to jakoś uzyskać ?
+#13+#10+ nie działa
sLineBreak też nie działa

1

Tego nie wiem, ale może połóż po prostu 2 egzemplarze TLabel na TPanelu. Może TLabel ma możliwość, o którą Ci chodzi, nie pamiętam.

0

Napisałeś trochę mało konkretnie, więc to są trochę moje domysły/wariacje na temat tego, o co może Ci chodzić:

  • w przypadku "zwykłego" komponentu TLabel całkowicie działa zapis w postaci label1.Caption := 'linia pierwsza' + #13#10 + 'linia poniżej';.
  • jeśli tego TLabel umieścisz na TPanel - także podany zapis działa
  • raczej nie kojarzę, żeby dało się podzielić Panel1.Caption na 2 linie, zamiast tego skorzystaj z rozwiązania proponowanego przez kolegę wcześniej, czyli wyczyśc caption panelu i umieść na nim osobny komponent TLabel, który możesz sobie rozbić na 2 linie.

P.S. to co napisałem sprawdziłem u mnie na Delphi w wersji 10.2 oraz Lazarusie 2.0 na Win10

3

Daję to jako osobny wpis, żeby nikomu nie umknęło ;)

W sumie to znalazłem rozwiązanie. Wymaga wprawdzie pewnej akrobacji, ale nie jest to nic strasznego, a co istotne - to rozwiązanie działa :)

Oryginalna procedura rysująca TPanel wygląda następująco:

procedure TCustomPanel.Paint;
var
  ARect: TRect;
  TS : TTextStyle;
begin
  ARect := GetClientRect;

  PaintBevel(ARect, BevelOuter);
  InflateRect(ARect, -BorderWidth, -BorderWidth);
  PaintBevel(ARect, BevelInner);

  if Caption <> '' then
  begin
    TS := Canvas.TextStyle;
    TS.Alignment := BidiFlipAlignment(Self.Alignment, UseRightToLeftAlignment);
    if BiDiMode<>bdLeftToRight then
      TS.RightToLeft:= True;
    TS.Layout:= tlCenter;
    TS.Opaque:= false;
    TS.Clipping:= false;
    TS.SystemFont:=Canvas.Font.IsDefault;
    TS.Wordbreak := FWordWrap;
    TS.SingleLine := not FWordwrap;
    if not Enabled then
      if ThemeServices.ThemesEnabled then
        Canvas.Font.Color := clGrayText
      else
      begin
        Canvas.Font.Color := clBtnHighlight;
        OffsetRect(ARect, 1, 1);
        Canvas.TextRect(ARect, ARect.Left, ARect.Top, Caption, TS);
        Canvas.Font.Color := clBtnShadow;
        OffsetRect(ARect, -1, -1);
      end
    else
      Canvas.Font.Color := Font.Color;

    Canvas.TextRect(ARect,ARect.Left,ARect.Top, Caption, TS);
  end;

  inherited Paint;
end;                                          

Zamiana linii 23 pliku custompanel.inc na następującą postać:

TS.SingleLine := FALSE;//not FWordwrap;

powoduje efekt widoczny na poniższym screenie :)
screenshot-20190611095155.png

Przy czym musisz pamiętać/mieć na uwadze, że to jest taka prowizorka/obejście i zasadniczo nie powinno się takich rzeczy robić w kodzie LCL, bo mogą się pojawić różne nietypowe efekty, ponieważ klasy LCL są ze soba powiązane, dziedziczą wielopoziomowo po sobie i możesz w ten sposób rozwalić jakieś zależności. Chciałem jedynie pokazać, że to się da zrobić. Jeśli chcesz z tego rozwiązania skorzystać to zrób jakaś klasę potomną TPanel i w niej wprowadzaj zmiany. Możesz stworzyć nowy komponent, ale nie jest to konieczne, wszystko możesz zrobić w samym kodzie - zrobić klasę dziedziczącą z TPanel, a potem nadpisać dla niej TCustomPanel.Paint swoją treścią.

0

Problem w tym iż to panel(e) generowany na flowpanel.
Czyli musiał bym generować jeszcze labele na generowanym panelu ...
Propozycja z podmianą w bibliotece trochę hardcorowa - wydaje mi się iż przy aktualizacji środowiska lub przenoszeniu projektu można o tym zapomnieć i wszytko wróci do normy.
Ale dzięki za sugestie. To tylko kosmetyka, ale może finalnie wykorzystam pomysł z generowanymi labelami

0

generować jeszcze labele na generowanym panelu ...

Nie no.. ja to widzę inaczej.
To, co podałem - czyli grzebanie w źródłach LCL miało jedynie na celu pokazanie, że jest taka możliwość.
Ty oczywiście nie powinieneś tego tak robić, ale zamiast tego tak, jak pisałem - zrobić sobie jakąś klasę dziedziczącą po TPanel i w niej nadpisać standardową obsługę Paint. Potem po prostu umieszczasz taki panel na formatce i przypisujesz do jego captiona tekst z rozbiciem na dwie linie. Niczego więcej dodawać nie musisz.

Ewentualnie inna opcja, trochę podobna do poprzedniej, ale inna :D Tworzysz sobie potomka TPanel i dodajesz do niego TLabel. W ten sposób każdy obiekt tej klasy będzie miał swojego "wbudowanego" labela, przez co także odpada konieczność dodawania za każdym razem ręcznie napisu.

0

Teraz się przyznam - jestem zdezorientowany obiektowo :) klasa :/ dziedzicząca =O . to za trudne terminy dla mnie :)

0

Klasa TPanel jest niezdolna do natywnego renderowania tekstu wieloliniowego (przynajmniej pod Windows) – zaprogramowana jest w taki sposób, że potrafi malować tylko jedną linię, cholera wie dlaczego. :/

Możesz zrobić inaczej – usuń wartość dla Caption, a do wyświetlenia tekstu użyj TLabel. Ustaw mu Align na alClient, Alignment na taCenter i Layout na tlCenter – dzięki temu komponent zawsze będzie rozciągnięty na całą powierzchnię panelu i będziesz mógł bez problemu ustawić tekst wieloliniowy.

0

Po przemyśleniu potrzebuje dwa TLabel - bo różna wielkość czcionki.
Ale niestety nadal nie wiem jak to ugryść . Jak napisałem - jestem słabo obiektowy.
W tej chwili kod generujący "kafelek" w TPanelFlow wygląda tak :

                    with TPanel.Create(Self) do
                         begin
                              Parent:=panel;
                              Caption:=inttostr(Snr_op);

                              Height:=32;
                              Width:=100;
                              Font.Size:=14;
                              font.Bold:=True;
                              Font.Color:=clBlack;
                              Color:=clGreen;
                              if Sstan=FALSE then
                                 begin
                                 Font.Color:=clWhite;
                                 Color:=clRed;
                                 end;
                              Name:='ID_'+inttostr(Sidcu);
                              onClick:=@BtnSourceClick;
                              Visible:=true;
                         end;                                                        

Jak tego dokonać ?

0

Odnośnie fragmentu TPanel.Create - czy nie powinno być TLabel? Bo Ty tworzysz labela, którego chcesz wsadzić na panel, prawda?

0

Najpierw tworze kafelek - TPanel. I na nim musiał bym umieścić TLabel.
Teraz ten TLabel musiał bym przypisać do rodzica - stworzonego panelu(a?) . I tu nie wiem jak to ugryźć.

with TLabel.Create(Self) do
                         begin
                              Parent:=???????;
1

Nie wiem, czy o to Ci chodziło, ale tak na szybko zrobiłem coś, żeby pokazać Ci jak możesz podejść do tematu. Jest to zrobione raczej brzydko, żeby pokazać sam mechanizm, jak możesz to zrobić:

unit Unit1;

{$mode objfpc}{$H+}

interface

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

type

  TNewPanel = class(TPanel)
    NewCaption: TLabel;
  end;

  { TForm1 }

  TForm1 = class(TForm)
    Panel: TNewPanel;
    procedure FormCreate(Sender: TObject);
  private

  public

  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

{ TForm1 }

procedure TForm1.FormCreate(Sender: TObject);
begin
  Form1.Panel:= TNewPanel.Create(Form1);
  Form1.Panel.Parent:= Form1;
  Form1.Panel.SetBounds(10,10,200, 200);
  Form1.Panel.Color:= clRed;
  Form1.Panel.NewCaption:= TLabel.Create(Form1.Panel);
  Form1.Panel.NewCaption.Parent:= Form1.Panel;
  Form1.Panel.NewCaption.Caption:= 'siakiś napis';
  Form1.Panel.NewCaption.Left:= 30;
  Form1.Panel.NewCaption.Top:= 30;
end;

end.
0

To nie działa :/

1

A to dziwne, bo u mnie działa. Zrobiłem kopiuj-wklej ze swojego Lazarusa.
Napisz może coś więcej, co konkretnie się dzieje, co nie działa, jakie błędy itp. Bo to, co napisałeś w sumie to nic nie wnosi do sprawy :P

0

zrobiłem też copy/paste do nowego proj w lazarusie . Uruchamia się pusta forma.
IDE 2.0.0
FPC 3.0.4
wer. 64-bit (ale na 32 też sprawdziłem)
Win 10 1803

3

Copy/paste to nie jest dobra metoda programowania....

procedure FormCreate(Sender: TObject);

W edytorze obiektów (czy jak to się nazywa w Lazarusie) wybierz dla formatki w zdarzeniach OnCreate -> FormCreate (będzie z liście rozwijanej)

0

No tak teraz działa :D

0

To moja przeróbka - nie wiem jak to zrobić by klik na label było tym samym co klik na utworzony panel

unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls, StdCtrls,
  Buttons;

type

  TNewPanel = class(TPanel)
    NewCaption: TLabel;
    NewCaption2: TLabel;
  end;

  { TForm1 }

  TForm1 = class(TForm)
    Button1: TButton;
    Fpanel: TFlowPanel;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);


  private
    Procedure shownewpanel(nazwa:string;id:integer);
    Procedure ClickOnPanel(Sender: TObject);
  public

  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

{ TForm1 }


procedure TForm1.Button1Click(Sender: TObject);
begin
 shownewpanel('test 1',1);
 shownewpanel('test 2',2);
 shownewpanel('test 3',3);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
 // FPanel.boxid_2.boxLabel2_id_2.Caption:='test zmiany tekstu';
end;

Procedure TForm1.shownewpanel(nazwa:string;id:integer);
var nowe:TNewPanel;
begin
  nowe:=TNewPanel.Create(Form1.Fpanel);
  with nowe do
        begin
          Parent:=  FPanel;
          Name:='boxid_'+inttostr(id);
          Caption:='';
          SetBounds(10,10,100, 100);
          Color:= clRed;

          NewCaption:= TLabel.Create(  nowe);
          NewCaption.Parent:=   nowe;
          NewCaption.Font.Color:=clWhite;
          NewCaption.Caption:= 'napis 1:'+nazwa;
          NewCaption.Left:= 5;
          NewCaption.Top:= 15;
          NewCaption.Name:='boxLabel1_id_'+inttostr(id);

          NewCaption2:= TLabel.Create(  nowe);
          NewCaption2.Parent:=   nowe;
          NewCaption2.Font.Color:=clYellow;
          NewCaption2.Caption:= 'napis 2:'+nazwa+' !';
          NewCaption2.Left:= 10;
          NewCaption2.Top:= 40;
          NewCaption2.Name:='boxLabel2_id_'+inttostr(id);
          onClick:=@ClickOnPanel;

        end;
end;

procedure TForm1.ClickOnPanel(Sender: TObject);
begin
showmessage('kliknieto '+TPanel(sender).Name);
end;

end.
2

No to proszę - poniżej wersja z obsługą kliknięć także na napisach:

Procedure TForm1.shownewpanel(nazwa:string;id:integer);
var nowe:TNewPanel;
begin
  nowe:=TNewPanel.Create(Form1.Fpanel);
  with nowe do
        begin
          Parent:=  FPanel;
          Name:='boxid_'+inttostr(id);
          Caption:='';
          SetBounds(10,10,100, 100);
          Color:= clRed;
          OnClick:= @Form1.ClickOnPanel;

          NewCaption:= TLabel.Create(  nowe);
          NewCaption.Parent:=   nowe;
          NewCaption.Font.Color:=clWhite;
          NewCaption.Caption:= 'napis 1:'+nazwa;
          NewCaption.Left:= 5;
          NewCaption.Top:= 15;
          NewCaption.Name:='boxLabel1_id_'+inttostr(id);
          NewCaption.OnClick:= @Form1.ClickOnPanel;

          NewCaption2:= TLabel.Create(  nowe);
          NewCaption2.Parent:=   nowe;
          NewCaption2.Font.Color:=clYellow;
          NewCaption2.Caption:= 'napis 2:'+nazwa+' !';
          NewCaption2.Left:= 10;
          NewCaption2.Top:= 40;
          NewCaption2.Name:='boxLabel2_id_'+inttostr(id);
          NewCaption2.OnClick:= @Form1.ClickOnPanel;

        end;
end;

procedure TForm1.ClickOnPanel(Sender: TObject);
  var nazwa: string;
begin
  if (Sender is TPanel) then nazwa:= TPanel(Sender).Name;
  if (Sender is TLabel) then nazwa:= TLabel(Sender).Parent.Name;
  showmessage('kliknieto '+nazwa);//TPanel(sender).Name);
end; 
2

A poza tym, nawiązując do naszej innej rozmowy, możesz zastanowić się nad alternatywnym (pytanie - czy lepszym?) rozwiązaniem - zamiast umieszczać na panelu elementy typu TLabel, może obsłuż sobie zdarzenie OnPaint i w nim po prostu sobie napisz tekst na Canvasie tego Panela - coś w stylu

procedure TForm1.Panel1Paint(Sender: TObject);
begin
  panel1.Canvas.TextOut(10,20, 'KASZANKA');
end; 
1

Rozwiązanie z labelami w pełni mnie satysfakcjonuje - ale i za tę ciekawostkę dziękuje :)

0
cerrato napisał(a):

[…] możesz zastanowić się nad alternatywnym (pytanie - czy lepszym?) rozwiązaniem - zamiast umieszczać na panelu elementy typu TLabel, może obsłuż sobie zdarzenie OnPaint […]

Oczywiście, to byłoby najlepsze rozwiązanie – tyle że TFlowPanel tego zdarzenia nie posiada. :D

0

tyle że TFlowPanel tego zdarzenia nie posiada.

Zwróć uwagę, że OP na FlowPanel'a dodaje dynamicznie "zwykłe" obiekty TPanel (https://4programmers.net/Forum/1598317) i to w ich OnPaint proponowałem dodać pisanie tekstu.

0

Trochę to dziwnie wygląda – to przecież TFlowPanel służy do grupowania subkomponentów (np. klasy TPanel), a nie na odwrót. Przydałoby się wiedzieć jakie jest przeznaczenie tych wszystkich paneli, żeby móc coś sensownego doradzić.

0

Ale przecież tak jest w podanym przez OP kodzie:
najpierw na sztywno wrzuca na formatkę TFlowPanel

TForm1 = class(TForm)
    Button1: TButton;
    Fpanel: TFlowPanel;

a potem do niego dodaje obiekty TPanel

TNewPanel.Create(Form1.Fpanel);
[...]
          Parent:=  FPanel;
[...]

Wyjaśnij proszę, o co Ci chodzi, bo czegoś tu nie łapię i nie wiem, który z nas się zakręcił ;)

0

To znów ja :) Dodatkowe zagadnienie związane z mą niewiedzą i ignoranctwem dot. klas i obiektów :

procedure TForm1.ClickOnPanel(Sender: TObject);
  var objekt: TObject;
begin
  if (Sender is TPanel) then objekt:= TPanel(Sender);
  if (Sender is TLabel) then objekt:= TLabel(Sender).Parent;
 TPanel(objekt).Color:=clRed;
end; 

Zmieniam kolor tła TPanel(objekt). A jak zmienić kolor fontu w TLabel mieszcącego się na tym TPanel mając tylko jako uchwyt objekt ?

1

Nie wiem, czy dobrze rozumiem o co Ci chodzi, ale spróbuj zapisu w postaci

procedure ZmienKolor(Sender: TObject);
begin
  (Sender as TLabel).Font.Color:= clGreen;
end;   

Ważna uwaga - jeśli skorzystasz z takiego zapisu, to MUSISZ mieć pewność, że dany obiekt przesłany jako Sender jest typem zgodnym z TLabel. Jeśli wywołasz to na jakimś obiekcie, który nie posiada właściwości Font.Color to wyskoczy błąd. Oczywiście - jeśli sam to piszesz i tego pilnujesz, to nie będzie raczej problemu, ale możesz się i tak zabezpieczyć. W poprzednim poście dałem rozwiązanie sprawdzające, jakiego typu jest dany obiekt. Możesz połączyć tamten post z obecnym i zrobić coś w stylu:

procedure ZmienKolor(Sender: TObject);
begin
  if (Sender is TLabel) then
     (Sender as TLabel).Font.Color:= clGreen;
end;  

0

Chyba się nie zrozumieliśmy - albo ja nie rozumiem kodu który podałeś :P .
Dysponuje tylko uchwytem do TPanel i chce zmienić kolor czcionki na TLabel który jest dzieckiem TPanel .
Z definicji :

 TNewPanel = class(TPanel)
    NewCaption: TLabel;
    NewCaption2: TLabel;
  end;

Zaraz sam sie pogubie :D

0

A którego labela chcesz zmienić kolor? Bo o ile pamiętam, to na każdym panelu miałeś dwie etykietki.

0

Każdy z osobna

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