Hopefully I can articulate this properly. I have a TScrollBox on a form. I am adding instances of another form to a dynamically created panel that I am adding to the TScrollBox , here is the code I am using to add it.
procedure TSettings.AddWFOnclick(Sender: TObject);
var
dlg : TWFDetail;
panel: TPanel;
i : Integer;
begin
panel := TPanel.Create(self);
dlg := TWFDetail.Create(self);
panel.Parent := WFList;
panel.clientheight := dlg.height;
panel.align := alTop;
panel.Top := 330;
panel.Left := 0;
dlg.Parent := panel;
dlg.align := alClient;
dlg.visible := True;
dlg.Show;
end;
The above works beautifully to add my form and panel. As seen here:
The issue occurs when I try to close the dlg and remove the panel. I don't have any sample code for that. I have tried a dozen different things and can't seem to figure it out. I am closing the form with a close call on the click of the red X, then the panel remains. Seen here:
I need to be able to remove the blank panel and shift everything up. I just can't seem to wrap my head around it since the panel is being created dynamically.
The parenting structure is TScrollBox > TPanel > MyForm
Any help would be appreciated.
You can use an TNorifyEvent on TWFDetail form. Define it:
property OnCloseForm:TNotifyEvent read FOnCloseForm write FOnCloseForm;
When you close the form, fire the event if assigned:
Self.Close;
if Assigned(OnCloseForm) then
OnCloseForm(Self);
When you create the form, assign the OnCloseForm event:
...
dlg.OnCloseForm := CloseForm;
...
And define a simple CloseForm procedure to free the panel that you use to contain the form:
var
pnl:TPanel;
begin
if (Sender is TWFDetail) then begin
if TWFDetail(Sender).Parent is TPanel then begin
pnl := TPanel(TWFDetail(Sender).Parent);
pnl.Free;
end;
end;
end;
There are some other ways to to this, but this work fine.
Related
I've noticed that it's possible to set the TextHint property on a TDBEdit in code (it's not visible in the Object Inspector), however it doesn't display, is there an easy way of making this work?
The following setup works in XE2. Drop a TClientDataSet, TDataSource, and 2 TDBEdit controls on a Form, and make the OnCreate event handler of the Form look like this:
procedure TForm1.FormCreate(Sender: TObject);
begin
DataSource1.DataSet := ClientDataSet1;
DBEdit1.DataSource := DataSource1;
DBEdit2.DataSource := DataSource1;
ClientDataSet1.FieldDefs.Add('First', ftString, 20);
ClientDataSet1.FieldDefs.Add('Last', ftString, 20);
ClientDataSet1.CreateDataSet;
ClientDataSet1.Open;
DBEdit1.DataField := ClientDataSet1.Fields[0].FieldName;
DBEdit1.TextHint := 'first name';
DBEdit2.DataField := ClientDataSet1.Fields[1].FieldName;
DBEdit2.TextHint := 'last name';
ClientDataSet1.Insert;
end;
One potential problem is the TDBEdits being read-only. For instance, remove the Insert() call from the snippet and the edits will remain empty. This behavior is similar with regular edits, which is reasonable - when an edit control does not allow editing, there's no point in showing a hint about what the user should enter.
I have an application with a TTrayIcon Component that I use to "Hide" and "Restore" my MainForm. Here is what I use to "Hide" (OnTrayClick)
procedure TMainWindow.TrayIcon1Click(Sender: TObject);
var
I : Integer;
begin
if Application.MainForm.Visible then begin
{ Hide }
Application.MainForm.Visible := FALSE;
end else begin
{ Restore }
Application.MainForm.Visible := TRUE;
WindowState := wsNormal;
Application.BringToFront();
{ Workaround for ModalForms }
for I := 0 to Screen.FormCount-1 do begin
if (fsModal in Screen.Forms[I].FormState) then begin
Screen.Forms[I].BringToFront;
Screen.Forms[I].SetFocus;
break; // Stop looking for more ModalForms
end;
end;
end;
end;
This example works just fine if there are no other (Modal) Forms open.
But if there is a ModalForm open and restore my MainForm, the ModalForm seems to be behind the MainForm and I can't reach it. How can I activate/focus the ModalForm and put it in front of my MainForm after my MainForm has been restored? My Application.MainFormOnTaskbar is set to False
EDIT:
If a ModalForm is open and I restore my MainForm, both of the forms won't focus at all.
The setting of MainFormOnTaskbar seems to be causing the problem. You really need to keep that set to true.
You could choose to not hide any forms if there is a modal windows. In that case check for Application.ModalLevel > 0 in your hide code. You could even show a balloon hint stating that the application cannot be minimized until messages are closed.
Otherwise if you really want to minimize all windows the code below works well for me. Hide all of the open windows including the modal window. This will cause the main taskbar icon to go away and everything is off the screen. The one thing you need to do is keep track of which windows were just open. I did that below by setting the Tag value on the forms that were just hidden. Then in the restore code you can set the visible of those windows back to true.
The only case this does not deal with is hiding the main window but leaving the modal window visible. I'm not sure why you would want to do that and personally I would find that confusing as a user.
procedure TForm1.TrayIcon1Click(Sender: TObject);
var
I : Integer;
begin
if Application.MainForm.Visible then
begin
// Hide
for I := 0 to Screen.FormCount-1 do
begin
if Screen.Forms[i].Visible = true then
begin
Screen.Forms[i].Visible := false;
Screen.Forms[i].Tag := 1;
end;
end;
end
else
begin
// Restore
for I := 0 to Screen.FormCount-1 do
begin
if Screen.Forms[i].Tag = 1 then
begin
Screen.Forms[i].Visible := true;
Screen.Forms[i].Tag := 0;
end;
end;
Application.BringToFront();
end;
end;
You may need need to set the PopupParent property on the Modal Form to be your main form. This is set to pmAuto for new forms but if this is an old project it could be pmNone.
Here is a link to a blog post by Allen on PopupMode and PopupParent and here is another Stackoverflow questions that address the topic Newly created modal window loses focus and become inacessible in Windows Vista
I normally use something like this:
MyPopupForm := TMyForm.Create(Owner);
MyPopupForm.PopupMode := pmAuto;
MyPopupForm.PopupParent := Owner;
MyPopupForm.ShowModal;
I have two separate forms in my application. I created one additional empty form and placed a TMainMenu component on it with two menu items. This new form will serve as the main form from which everything else will be loaded. Now I want it to work like this: when you click either of the two menu items, it should load the respective form's contents the menu item associated with to the main form. How can I achieve this? Or what is the typical approach to this kind of problem? Please, provide a simple illustrative example.
Create a TPanel on your MainForm and set its Align := alClient, BevelOuter := bvNone. Also give the MainForm attributes Form1: TForm1 and Form2: TForm2. Then display Form1 or Form2 in this way:
Showing Form1:
if not Assigned(MainForm.Form1) then
MainForm.Form1 := TForm1.Create(MainForm);
MainForm.Form1.Parent := MainForm.Panel1;
MainForm.Form1.Align := alClient;
MainForm.Form1.BorderStyle := bsNone;
MainForm.Form1.Visible := True;
if Assigned(MainForm.Form2) then
MainForm.Form2.Visible := False;
Of course you don't need to write MainForm; it's just to make the example clear.
If you have a bunch of Forms already created and want to add the ability of being show "docked" you could change the inheritance to a new template instead of TFrom.
By adding and overloaded constructor you will be able to use them as usual or "docked".
To change the inheritance you only have to replace
type
TYourForm = class(TForm)
with
type
TYourForm = class(TTemplate)
and replace the object in your DMF's with inherited
{
public
Constructor Create(AOwner:TComponent;AParent:TWinControl=nil);Overload;
.....
}
constructor TTemplate.Create(AOwner: TComponent; AParent: TWinControl);
begin
inherited Create(AOwner);
if Assigned(AParent) then
begin
BorderStyle := bsNone;
Parent := AParent;
Align := alClient;
end;
end;
if you want to embed other form in the your main form put a tpanel in to your main form set alclient property. And when clicked set fromxxx.parent is your panel name.
here is a sample code
begin
if Dm.TblUser.Active=False then
Dm.TblUser.Active := True;
if FrmPUserG=nil then
FrmPUserG := TFrmPUserG.Create(Self);
FrmpUserG.Parent := PnLContainer;
FrmpUserG.Align := alClient;
FrmpUserG.BorderStyle := bsNone;
FrmpUserG.Visible := True;
FrmpUserG.BringToFront;
end;
I want to avoid mouse right click on the edit boxes of my application which I am doing in BDS 2006.
I googled about it and i found a code as follows.
noPopUp := TPopupMenu.create(Edit1);
Edit1.PopupMenu := noPopup;
This is written on form activate. It works fine for edit1, but there are many edit boxes on the form so i wrote a for loop,
for i := 0 to Self.ControlCount-1 do
begin
if Self.Controls[i].ClassName = 'TEdit' then
begin
noPopUp := TPopupMenu.create(Self.Controls[i]);
TEdit(Self.Controls[i]).PopupMenu := noPopup;
end;
end;
This works fine for the edit boxes whose parent is Form. But if there are edit boxes on groupboxes or panels then, these panels and groupboxes in turn children of the form.
So my question is how to disable mouse right click on the edit boxes when the parent is not the form?
This accepted answer allocate unnecessary memory . You can think then it causes memory leaks too, because the created TPopupMenu are never released. But the Create( AOwner) of each TPopupMenu prevent this, releasing this memory on TEdit's Free.
To avoid unnecessary memory alloc, try this:
procedure TForm1.MyContextPopup(Sender: TObject; MousePos: TPoint;
var Handled: Boolean);
begin
Handled := True;
end;
and in the loop:
for i := 0 to Self.ComponentCount-1 do
if Self.Components[i] is TEdit then
TEdit(Self.Components[i]).OnContextPopUp := MyContextPopup;
This is enought to do what you want!
Best regards!
The solution in not that far: substitute control with component, like this
for i := 0 to Self.ComponentCount-1 do
begin
if Self.Components[i].ClassName = 'TEdit' then
begin
noPopUp := TPopupMenu.create(Self.Components[i]);
TEdit(Self.Components[i]).PopupMenu := noPopup;
end;
end;
I would like to get text width of a string before an application starts. Everything works fine until Application.MainForm canvas present. The problem is, when I try dynamically create TOrdinarium in the OnCreate event of the app. main form, "Canvas does not allow drawing" error occurs. (Application.MainForm is nil....). I tried several ways to create Canvas dynamically (one of them is written below), but it can not measure text sizes without being attached to parented control.
Is there way how to make it work somehow?
Thanx
I tried this:
TOrdinarium = class (TCustomControl)
private
function GetVirtualWidth:integer;
end;
constructor TOrdinarium.Create(AOwner:TComponent);
begin
inherited;
Width:=GetVirtualWidth;
end;
function TOrdinarium.GetVirtualWidth:integer;
var ACanvas : TControlCanvas;
begin
ACanvas := TControlCanvas.Create;
TControlCanvas(ACanvas).Control := Application.MainForm;
ACanvas.Font.Assign(Font);
result:=ACanvas.TextWidth('0');
ACanvas.Free;
end;
This works:
procedure TForm1.FormCreate(Sender: TObject);
var
c: TBitmap;
begin
c := TBitmap.Create;
try
c.Canvas.Font.Assign(self.Font);
Caption := IntToStr(c.Canvas.TextWidth('My String'));
finally
c.Free;
end;
end;
I'm not sure if this can be done, but if by "before the app starts" you mean "before the main form is displayed", you could always put your canvas-related code in the main form's OnCreate event. You'll have a valid canvas by that point.