Jak w temacie - da sie to jakoś uzyskać ?
+#13+#10+ nie działa
sLineBreak też nie działa
- 1
- 2
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 postacilabel1.Caption := 'linia pierwsza' + #13#10 + 'linia poniżej';
. - jeśli tego
TLabel
umieścisz naTPanel
- 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śccaption
panelu i umieść na nim osobny komponentTLabel
, 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
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 :)
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ą.
- screenshot-20190611095155.png (6 KB) - ściągnięć: 70

- Rejestracja:ponad 9 lat
- Ostatnio:około 15 godzin
- Postów:259
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
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.

- Rejestracja:ponad 13 lat
- Ostatnio:około 3 godziny
- Lokalizacja:Tuchów
- Postów:12166
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.

- Rejestracja:ponad 9 lat
- Ostatnio:około 15 godzin
- Postów:259
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ć ?

- Rejestracja:ponad 9 lat
- Ostatnio:około 15 godzin
- Postów:259
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:=???????;
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.
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

- Rejestracja:ponad 9 lat
- Ostatnio:około 15 godzin
- Postów:259
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



- Rejestracja:ponad 15 lat
- Ostatnio:7 miesięcy
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)

- Rejestracja:ponad 9 lat
- Ostatnio:około 15 godzin
- Postów:259
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.
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;
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;

- Rejestracja:ponad 13 lat
- Ostatnio:około 3 godziny
- Lokalizacja:Tuchów
- Postów:12166
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 zdarzenieOnPaint
[…]
Oczywiście, to byłoby najlepsze rozwiązanie – tyle że TFlowPanel
tego zdarzenia nie posiada. :D
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.

- Rejestracja:ponad 13 lat
- Ostatnio:około 3 godziny
- Lokalizacja:Tuchów
- Postów:12166
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ć.
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ł ;)

- Rejestracja:ponad 9 lat
- Ostatnio:około 15 godzin
- Postów:259
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 ?
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;

- Rejestracja:ponad 9 lat
- Ostatnio:około 15 godzin
- Postów:259
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
- 1
- 2