Problem with creating tpaintbox on tpanel - delphi

I have a little problem. I'm trying to create a TPaintBox on a TPanel like this:
procedure TForm1.mkPaint(S: string);
var PB: TPaintBox;
begin
PB := TPaintBox.Create(Self);
with PB do
begin
Parent := Panel1;
Visible := True;
Name := S;
Height := 100;
Width := 100;
Left := 8;
Top := 8;
// ParentColor := False;
Brush.Style := bsSolid;
Brush.Color := $00000000;
end;
Application.ProcessMessages;
end;
Now, if i change the PaintBox's Parent to Form1, i can see the brush.
But, with parent changed to Panel1, nothing happens. Any idea of how can i fix this?
Thanks in advance!

Is the TPanel visible to begin with?
Also, TPaintBox does not have a public Brush property (perhaps you are thinking of TShape?). TWinControl does, but TPaintBox is not a TWinControl descendant. It is a TGraphicControl descendant.

Yeah that was a mistake of mine. I changed the code to:
pb := TPaintBox.Create(self);
with pb do begin
Parent := Form1;
Visible := true;
Top := 1;
Left := 1;
Width := 250;
Height := 100;
ParentColor := false;
Canvas.Brush.Color := clBlack;
Canvas.Font.Size := 12;
Canvas.Font.Color := clWhite;
Canvas.FillRect(ClientRect);
Canvas.TextOut(1, 1, 'test');
end;
but without success.. i mean, if i drop a PaintBox component to the form then the code is taking effect as it should do, but dynamically creating a TPaintBox.... dunno.

Related

Creating custom button in Delphi with different actions [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 3 years ago.
Improve this question
I am creating a custom component, a button-switch like this :
In my "form activate" function, I wrote a for loop in which I call 3 times the button function with a different position parameter like : SwitchButton(30); where 30 is the top position.
What I want to do is assign at these 3 buttons different actions, here some code.
Code for button creation :
procedure TFMain.SwitchButton(posPulsante: Integer);
var
i: Integer;
posDescrizionePulsante: Integer;
strDescrizione: String;
begin
posDescrizionePulsante := 32;
lastPressed := 1;
Pulsante := TPanel.Create(FMain);
BordoPulsante := TShape.Create(self);
LevaPulsante := TPanel.Create(self);
DescrizionePulsante := TLabel.Create(self);
//Proprietà Descrizione
with DescrizionePulsante do
begin
Parent := PComandi;
Top := posDescrizionePulsante;
Left := 100;
Caption := 'Visualizza finestra utenti';
Font.Name := 'Tahoma';
Font.Size := 12;
Font.Style := [fsBold];
Font.Color := clWhite;
end;
//Proprietà Pulsante
with Pulsante do
begin
Parent := PComandi;
ParentColor := false;
ParentBackground := false;
BevelOuter := bvNone;
Color := clWhite;
Width := 57;
Height := 25;
Top := posPulsante;
Left := 20;
Visible := true;
end;
//Proprietà Bordo
with BordoPulsante do
begin
Parent := Pulsante;
Align := alClient;
Brush.Style := bsClear;
Brush.Color := RGB(122,136,201);
Pen.Color := clWhite;
Pen.Style := psSolid;
Pen.Width := 3;
end;
//Proprietà Leva
with LevaPulsante do
begin
Parent := Pulsante;
ParentBackground := false;
ParentColor := false;
BevelOuter := bvNone;
Color := clWhite;
Cursor := crHandPoint;
Width := 23;
Height := 13;
Top := 6;
Left := 28;
LevaPulsante.OnClick := SwitchState;
end;
end;
Code for creating Button object :
procedure TFMain.FormActivate(Sender: TObject);
var
i: Integer;
posPulsante: Integer;
begin
posPulsante := 30;
for i := 1 to 3 do
begin
SwitchButton(posPulsante);
posPulsante := posPulsante + 50;
end;
end;
Would be nice to have some : if SwitchButton 1 is clicked then do something. if SwitchButton 2 is clicked then do something else.
I think this is an acceptable use of the Tag property. You can specify some number, for example the index of the for loop, in each of the panels:
procedure TFMain.FormActivate(Sender: TObject);
var
i: Integer;
posPulsante: Integer;
begin
posPulsante := 30;
for i := 1 to 3 do
begin
SwitchButton(posPulsante, i {For example, add the tag as extra parameter});
posPulsante := posPulsante + 50;
end;
end;
And then set that tag in the button, here using the added parameter indexPulsante.
procedure TFMain.SwitchButton(posPulsante: Integer; indexPulsante: Integer);
var
i: Integer;
posDescrizionePulsante: Integer;
strDescrizione: String;
begin
...
LevaPulsante.Tag := indexPulsante;
end;
And then, in the event handler (which I think you called SwitchState), you'll have the Sender, which is the control that was clicked (the panel, in your case).
procedure TFMain.SwitchState(Sender: TObject);
begin
case (Sender as TComponent).Tag of
1: ShowMessage('You clicked the first. Do something.')
2: ShowMessage('Do something else.')
else
ShowMessage('You clicked another button than 1 or 2');
end;
end;
NB: Tag is introduced in TComponent and therefore also available in TPanel. In the code above I only typecast to TComponent, because it doesn't matter that it's a panel to get the tag, but if you want to use other properties, a more specific cast may be needed. I like to keep the cast generic, to make it easier to make changes like switching to another type than TPanel, for instance when you actually gonna make a component out of this (inherited from TCustomControl?), or use a third party component.

Simulate Align position in Delphi Custom Panel

I'm building a custom panel in Delphi XE5 and I'm having a hard time simulating a new "Gravity" property where I can combine two coordinates (like Right + Bottom) and the effect is similar to "Align" however, it does not resize the object, direction. The main problem I encountered is to simulate this behavior. My initial intention was to create a panel in memory with the same "Parent" in my custom panel and then align to the position defined in "Gravity" overwriting the "SetBounds" method. It's working, but a bit precarious, especially in "Design Time". Could someone suggest me how to more effectively simulate this alignment using VCL?
function TZPanel.GetPosition: TCustomPanel;
var
sid: TZSide;
anch: TAnchors;
panTest: TPanel;
function getGravity(al: TAlign): TRect;
var
panGravity: TPanel;
I: Integer;
begin
try
//Self.Visible := False;
panGravity:= TPanel.Create(Self);
panGravity.BevelInner := panTest.BevelInner;
panGravity.BevelOuter := panTest.BevelOuter;
panGravity.BevelWidth := panTest.BevelWidth;
panGravity.BorderWidth := panTest.BorderWidth;
panGravity.ParentBackground := True;
panGravity.SetBounds(panTest.Left, panTest.Top, panTest.Width, panTest.Height);
panGravity.Parent:= Self.Parent;
panGravity.Align := al;
Result:= panGravity.BoundsRect;
finally
panGravity.Destroy;
Self.Visible := True;
end;
end;
begin
panTest := TPanel.Create(Self);
panTest.Align := Align;
panTest.Anchors := Anchors;
panTest.BevelInner := BevelInner;
panTest.BevelOuter := BevelOuter;
panTest.BevelWidth := BevelWidth;
panTest.BorderWidth := BorderWidth;
panTest.SetBounds(Left, Top, Width, Height);
if (FGravity = []) then
begin
//
end
else
begin
panTest.Align := alCustom;
anch := [];
for sid in FGravity do
begin
case sid of
sTop:
begin
panTest.Top := getGravity(alTop).Top;
anch := anch + [akTop];
end;
sRight:
begin
panTest.Left := getGravity(alRight).Left;
anch := anch + [akRight];
end;
sBottom:
begin
panTest.Top := getGravity(alBottom).Top;
anch := anch + [akBottom];
end;
sLeft:
begin
panTest.Left := getGravity(alLeft).Left;
anch := anch + [akLeft];
end;
end;
end;
panTest.Anchors := anch;
end;
Result := panTest;
end;

How to properly create a TSplitter on a TCustomControl Component?

I´m designing a new VCL component using a set of existing TControls.
The controls are placed on TPanels, some aligned to left position, one to the right position and finally one to the client area. Each of those panels has the customized component as it´s parent.
I need to place splitters between the panels, in order for the users to be able to resize the inner components.
The problem is, I simply can´t figure out the logic applied to the positioning of the splitters when created at runtime.
I visited quite a number of forums, each pointing to a different solution, but none of them worked.
Tried to:
1 - when creating the splitters, use the properties "lef"t and "width" of the component where it should be positioned aside, as its "left" property.
2 - Use the left property to assign the position where it should be.
and some others I can´t remember.
What am I missing?
In the code below, the splitters abre being created where it should be.
Just after the corresponding panel, and theirs left property corresponds to the last thing i´ve tried (it´s position).
constructor TDBIDBGridFilterBar.Create(AOwner: TComponent);
begin
inherited;
Self.Width := 490;
Self.Height := 23;
Self.Constraints.MinWidth := 285;
if fComboColunasWidth = 0 then
fComboColunasWidth := 118;
fBackGroundPanel := TPanel.Create(Self);
fBackGroundPanel.Parent := Self;
fBackGroundPanel.ShowCaption := false;
fBackGroundPanel.BevelOuter := bvNone;
fBackGroundPanel.Align := alClient;
fButtonsPanel := TPanel.Create(Self);
fButtonsPanel.Parent := fBackGroundPanel;
fButtonsPanel.ShowCaption := false;
fButtonsPanel.BevelOuter := bvNone;
fButtonsPanel.Width := 73;
fButtonsPanel.Align := alLeft;
fBtnMarcaTodos := TButton.Create(Self);
fBtnMarcaTodos.Parent := fButtonsPanel;
fBtnMarcaTodos.Width := 23;
fBtnMarcaTodos.Height := 23;
fBtnMarcaTodos.Left := 0;
fBtnMarcaTodos.Hint := 'Marcar todos';
fBtnMarcaTodos.ShowHint := true;
fBtnDesmarcaTodos := TButton.Create(Self);
fBtnDesmarcaTodos.Parent := fButtonsPanel;
fBtnDesmarcaTodos.Width := 23;
fBtnDesmarcaTodos.Height := 23;
fBtnDesmarcaTodos.Left := 23;
fBtnDesmarcaTodos.Hint := 'Desarcar todos';
fBtnDesmarcaTodos.ShowHint := true;
fBtnInveteSelecao := TButton.Create(Self);
fBtnInveteSelecao.Parent := fButtonsPanel;
fBtnInveteSelecao.Width := 23;
fBtnInveteSelecao.Height := 23;
fBtnInveteSelecao.Left := 46;
fBtnInveteSelecao.Hint := 'Inverter seleção';
fBtnInveteSelecao.ShowHint := true;
fLabelPanel := TPanel.Create(Self);
fLabelPanel.Parent := fBackGroundPanel;
fLabelPanel.Width := 33;
fLabelPanel.Align := alLeft;
fLabelPanel.ShowCaption := false;
fLabelPanel.BevelOuter := bvNone;
fLabel := TLabel.Create(Self);
fLabel.Parent := fLabelPanel;
fLabel.Top := 4;
fLabel.Left := 4;
fLabel.Caption := 'Filtro:';
fLabel.Width := 28;
fComboColunasPan := TPanel.Create(Self);
fComboColunasPan.Parent := fBackGroundPanel;
fComboColunasPan.ShowCaption := false;
fComboColunasPan.BevelOuter := bvNone;
fComboColunasPan.width := fComboColunasWidth;
fComboColunasPan.Align := alLeft;
fComboColunas := TDBIComboBox.Create(Self);
fComboColunas.Parent := fComboColunasPan;
fComboColunas.Text := '';
fComboColunas.OnEnter := PopulaComboColunas;
fComboColunas.OnChange := ComboChange;
fComboColunas.Style := csOwnerDrawFixed;
fComboColunas.Align := alClient;
fComboColunas.Hint := 'Colunas';
fComboColunas.ShowHint := true;
fSplitterColunas := TSplitter.Create(Self);
fSplitterColunas.Parent := fBackGroundPanel;
fSplitterColunas.Align := alLeft;
fSplitterColunas.Left := 1;
fComboOperadorPan := TPanel.Create(Self);
fComboOperadorPan.Parent := fBackGroundPanel;
fComboOperadorPan.ShowCaption := false;
fComboOperadorPan.BevelOuter := bvNone;
fComboOperadorPan.width := fComboColunasWidth;
fComboOperadorPan.Align := alLeft;
fComboOperador := TDBIComboBox.Create(Self);
fComboOperador.Parent := fComboOperadorPan;
// fComboOperador.Items.Add(cItensComboFiltro);
fComboOperador.Style := csOwnerDrawFixed;
fComboOperador.Align := alClient;
fComboOperador.Hint := 'Comparação';
fComboOperador.ShowHint := true;
fComboOperador.Text := ' = ';
fSplitterOperador := TSplitter.Create(Self);
fSplitterOperador.Parent := fBackGroundPanel;
fSplitterOperador.Align := alLeft;
fSplitterOperador.Left := 2;
fBtnAdcFiltroPan := TPanel.Create(Self);
fBtnAdcFiltroPan.Parent := fBackGroundPanel;
fBtnAdcFiltroPan.ShowCaption := false;
fBtnAdcFiltroPan.BevelOuter := bvNone;
fBtnAdcFiltroPan.width := 23;
fBtnAdcFiltroPan.Align := alRight;
fBtnAdcFiltro := TButton.Create(Self);
fBtnAdcFiltro.Parent := fBtnAdcFiltroPan;
fBtnAdcFiltro.Height := 23;
fBtnAdcFiltro.Width := 23;
fBtnAdcFiltro.Caption := '+';
fBtnAdcFiltro.Hint := 'Adicionar filtro...';
fBtnAdcFiltro.ShowHint := true;
fBtnAdcFiltro.OnClick := btnNewFilterClick;
fClientPanel := TPanel.Create(Self);
fClientPanel.Parent := fBackGroundPanel;
fClientPanel.ShowCaption := false;
fClientPanel.BevelOuter := bvNone;
fClientPanel.Align := AlClient;
fMaskEdit := TDBIMaskEdit.Create(Self);
fMaskEdit.Parent := fClientPanel;
fMaskEdit.Font.Size := 9;
fMaskEdit.Align := alTop;
end;
When you add the panels to the background panel in left to right order, it is sufficient to set the Left property of the added panels before you set the Alignment property, to a large enough value, so it exceeds the Left property of components already placed on the background panel. The value you set can even be bigger than the width of the background panel.
When you add panels or other components in a right to left order (Alignment = alRight;) you can leave the Left property as 0.
The above is true for any component you place on the background panel, also splitters. When using splitters, you probably also want to set the neighbouring components Constraints.MinWidth property to something like e.g. 10 to prevent the component width to accidentally be reduced to zero, and therefore become invisible. Once that happens there's no way to get it visible again with the splitter.
For example, this code:
procedure TForm1.Panel1Click(Sender: TObject);
var
i: integer;
begin
i := 1;
repeat
with TPanel.Create(self) do
begin
Parent := Panel1;
Left := 510;
Align := alLeft;
Width := 40;
Constraints.MinWidth := 10;
Caption := 'L'+IntToStr(i);
end;
if (i = 3) or (i = 5) then
with TSplitter.Create(self) do
begin
Parent := Panel1;
Left := 510;
Width := 10;
Align := alLeft;
end;
inc(i);
until i > 5;
with TPanel.Create(self) do
begin
Parent := Panel1;
Width := 40;
Align := alRight;
Caption := 'R1';
end;
with TPanel.Create(self) do
begin
Parent := Panel1;
Width := 40;
Align := alRight;
Caption := 'R2';
end;
with TPanel.Create(self) do
begin
Parent := Panel1;
Left := 510;
Align := alClient;
Caption := 'C';
end;
end;
produces this design:
L1 .. L5 are alLeft aligned, C is alClient aligned and R1 .. R2 are alRight aligned.
I managed to figure it out.
Since all the components created before are left aligned, their left property are set to 0, no matter where in the form they are located.
So, in order to fix the problem, i had to propperly fill the left property of the previous panels.
fThisPanel.left := fPreviousPanel.Left + fPreviousPanel.width + 1, and so on ...

Cant write to a form's canvas

I am creating a form on the fly and would like to draw on its canvas however I'm unable to do so. No errors are generated just no output.
Here is the simple test code
procedure TForm11.Button1Click(Sender: TObject);
var
Fm: TForm;
R: TRect;
begin
try
Fm := TForm.Create(nil);
Fm.Position := poScreenCenter;
Fm.Caption := 'Test';
Fm.Width := 600;
Fm.Height := 400;
Fm.Color := clGreen;
Fm.Canvas.Font.Color := clBlack;
Fm.Canvas.Font.Size := 12;
Fm.Canvas.Pen.Color := clBlack;
Fm.Canvas.Pen.Width := 5;
Fm.Canvas.Brush.Color := clRed;;
Fm.Canvas.Brush.Style := bsSolid;
R.Left := 10;
R.Top := 10;
R.Width := 100;
R.Height := 100;
Fm.Canvas.TextOut(200, 10, 'Hello');
Fm.Canvas.Rectangle(R);
Fm.ShowModal;
finally
Fm.Free;
end;
end;
The canvas is redrawn all the time when you click controls, move the form around. In your case you draw the image, but after that, the form is shown and it will (re)-draw itself, overwriting your drawing. In order to keep your drawing, you could draw it in the OnPaint event of the form, which is invoked everytime the form needs to repaint itself.
procedure TForm11.Button1Click(Sender: TObject);
var
Fm: TForm;
begin
Fm := TForm.Create(nil);
try
Fm.Position := poScreenCenter;
Fm.Caption := 'Test';
Fm.Width := 600;
Fm.Height := 400;
Fm.Color := clGreen;
Fm.OnPaint := MyFormPaint;
Fm.ShowModal;
finally
Fm.Free;
end;
end;
procedure TForm11.MyFormPaint(Sender: TObject);
var
Fm: TForm;
R: TRect;
begin
FM := TForm(Sender);
Fm.Canvas.Font.Color := clBlack;
Fm.Canvas.Font.Size := 12;
Fm.Canvas.Pen.Color := clBlack;
Fm.Canvas.Pen.Width := 5;
Fm.Canvas.Brush.Color := clRed;;
Fm.Canvas.Brush.Style := bsSolid;
R.Left := 10;
R.Top := 10;
R.Width := 100;
R.Height := 100;
Fm.Canvas.TextOut(200, 10, 'Hello');
Fm.Canvas.Rectangle(R);
end;
Another solution would be to draw it on the canvas of a Bitmap, assign that bitmap to a TImage's Picture property, and show the TImage on the form. Then, everytime when the form needs to repaint, it lets each control repaint itself too, and the image will redraw the bitmap, so it remains visible.
procedure TForm11.Button1Click(Sender: TObject);
var
Fm: TForm;
Img: TImage;
B: TBitmap;
R: TRect;
begin
Fm := TForm.Create(nil);
try
Fm.Position := poScreenCenter;
Fm.Caption := 'Test';
Fm.Width := 600;
Fm.Height := 400;
// Add an image. Make the form the owner. That way, it is automatically
// discarded when you free the form in the `finally` block.
Img := TImage.Create(Fm);
// Make the form the parent too, and make sure the image covers the form.
Img.Parent := Fm;
Img.Align := alClient;
// Get bitmap of the picture. This will automatically create
// a bitmap for it too, which is managed by the image.
// You just have to give it the right dimensions.
B := Img.Picture.Bitmap;
B.Width := Fm.ClientWidth;
B.Height := Fm.ClientHeight;
// The image is not transparent, so you'll have to draw the green background too.
B.Canvas.Brush.Color := clGreen;
B.Canvas.FillRect(B.Canvas.ClipRect);
// Draw on the canvas of the bitmap.
B.Canvas.Font.Color := clBlack;
B.Canvas.Font.Size := 12;
B.Canvas.Pen.Color := clBlack;
B.Canvas.Pen.Width := 5;
B.Canvas.Brush.Color := clRed;;
B.Canvas.Brush.Style := bsSolid;
R.Left := 10;
R.Top := 10;
R.Width := 100;
R.Height := 100;
B.Canvas.TextOut(200, 10, 'Hello');
B.Canvas.Rectangle(R);
Fm.ShowModal;
finally
Fm.Free;
end;
end;

Delphi 7 edit component creation

I have a problem according to run-time creation of edit components in Delphi 7.
So when I create TEdit components after the program ran for "some" time it perfectly works.
However, when I create TEdit elements at the Forms OnCreate event, they have a wrong height.
Furthermore the (almost) simultaneously created Shapes have the right height.
Edit:
procedure TTPLVisorForm.CreateZeichen(ZShape : TShape; ZEdit : TEdit; VLeft : integer);
begin
with ZShape do
begin
Width := 50;
Height := 50;
Left := VLeft;
Top := 25;
Shape := stRectangle;
Parent := self.Band;
SendToBack();
end;
with ZEdit do
begin
Text := '#';
Left := VLeft+1;
Top := 26;
Parent := self.Band;
Font.Height := 48;
Width := 48;
Height := 48;
SendToBack;
end;
end;
Getting called by:
procedure TZeichen.Anzeigen(Form : TObject; Left : integer);
begin
self.Form := Form;
self.ZShape := TShape.Create(TTPLVisorForm(self.Form).Band);
self.ZEdit := TEdit.Create(TTPLVisorForm(self.Form).Band);
TTPLVisorForm(Form).CreateZeichen(self.ZShape, self.ZEdit, Left);
end;
Getting called by:
procedure TMagnetband.ErweitereRechts;
var
Zeichen : TZeichenKette;
begin
Zeichen := TZeichenKette.Create;
self.LetztesZeichen.Naechstes := TZeichenKette(Zeichen);
Zeichen.Vorheriges := self.LetztesZeichen;
Zeichen.Zeichen.Anzeigen(self.Form,
self.LetztesZeichen.Zeichen.ZShape.Left +
self.LetztesZeichen.Zeichen.ZShape.Width +
self.Padding);
self.LetztesZeichen := Zeichen;
self.Laenge := self.Laenge+1;
end;
Getting again called by:
procedure TTuringmaschine.ZeichenAnfuegen;
begin
self.Magnetband.ErweitereRechts;
end;
Getting called by:
procedure TTuringmaschine.PanelResize(Sender: TObject);
begin
while self.Magnetband.GetRechtsMax < self.Panel.Width do
self.ZeichenAnfuegen;
end;
Finally gets called by:
Constructor TTuringmaschine.Create(Form : TObject);
var
Breite : integer;
begin
self.Zustand := 0;
self.Form := TTPLVisorForm(Form);
self.Panel := TTPLVisorForm(self.Form).Band;
self.Magnetband := TMagnetband.Create(self.Form);
TTPLVisorForm(Form).Band.OnResize := self.PanelResize;
self.PanelResize(Nil);
//self.CreateMagnetkopf;
end;
And the Constructor is either called at the OnCreate event or on another event.
There's a margin around the text in TEdit control, so if you set the Font.Height to 48, the height of the control won't be exactly 48 if the control has the AutoSize property set to True. I would personally decrease height of the font, and for being sure turn the AutoSize off. Your CreateZeichen method would then look like this:
procedure TTPLVisorForm.CreateZeichen(ZShape: TShape; ZEdit: TEdit;
VLeft: Integer);
begin
with ZShape do
begin
Width := 50;
Height := 50;
Left := VLeft;
Top := 25;
Shape := stRectangle;
Parent := Self.Band;
SendToBack;
end;
with ZEdit do
begin
AutoSize := False;
Text := '#';
Left := VLeft + 1;
Top := 26;
Parent := Self.Band;
Font.Height := 40;
Width := 48;
Height := 48;
SendToBack;
end;
end;

Resources