I need to know the reason (and possible workarounds) for a strange behavior in Windows 7.
I have Form1 with a button on it and also a second form called Form2. In button's click handler I've:
Form2.Show;
After running my program, the first time I click on the button, my Form2 appears with a nice fade-in effect (sorry, I don't know the exact effect name in Windows 7. Tell me if you know!). OK. I close Form2 and click the button again. This time Form2 appears with no effect at all.
I want my Form2 to appear with that effect every time I click on the button. To be more specific, I need the main form of a real application to appear when user clicks on a tray icon. The first time clicking on the tray icon shows the window with animation, but second time it doesn't. How can I solve that?
Windows shows that animation the first time a window is shown. So all you need to do is make sure that every time your form is shown, the associated window is being shown for the first time.
You could destroy the form when it closes and create a new instance when you need to show it again. However, that may be inconvenient for you depending on how your form manages state. Judging from your edit and comments, you cannot afford to destroy the form when you close it. Instead you would need to force a new window to be created for your form, each time you show it.
For example, add a call to DestroyHandle in the OnClose event of the form. Or make a call to RecreateWnd immediately before you show the window. Note that the latter will involve making the protected method RecreateWnd visible to whoever calls Show on the form.
Remove your Form2 from the auto-create list. (Project->Options->Forms, click Form2 in the left pane, and click the button labeled > to move it to the right side.)
Change your ButtonClick handler:
procedure TForm1.Button1Click(Sender: TObject);
var
TempFrm: TForm2;
begin
TempFrm := TForm2.Create(nil);
TempForm.Show;
end;
Add a FormClose event to TForm2 (while you're at it, delete the global Form2: TForm2; variable just above the implementation clause, so you don't use it again by mistake)::
procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action := caFree;
end;
As a note: You should go to Tools->Options->VCL Designer, and uncheck Auto create forms and data modules in the Module creation options at the bottom. Auto-creating forms is almost always a bad idea; the only thing I ever allow to be auto-create (other than the main form) is any TDataModule that needs to be available immediately, and I move it to the top of the auto-create list you saw in the first paragraph so that it's created before the main form.
Related
I have an SQLite database with many Tables and one is named "tblAccounts"
I have a dlgCommon that has a TDBGrid on it with the dbgridAccounts.DataSource:=srcAccounts
I have several other Dialogs all of which at some time need to click a button and show the Accounts Grid to select an Account from. Rather than have many Forms all with their own TDBgrid.DataSource:=srcAccounts I am doing this...
procedure TdlgFolders.btnAcctSelClick(Sender: TObject);
begin
dlgCommon.pnlAccounts.Parent:=Self;
dlgCommon.pnlAccounts.Left:=dbedAccount.Left;
dlgCommon.pnlAccounts.Top:=dbedAccount.Top+dbedAccount.Height+2;
dlgCommon.pnlAccounts.Width:=190;
end;
When the user has the dlgFolders active and clicks "btnAcctSel" it all does as I need and shows the Grid. But, when the user clicks the Grid-Cell I am at a loss where/how to put the dbgridAccountsCellClick(Column: TColumn); Handler.
I tried putting it in the dlgCommon and it compiles, but is not used as that is no longer the Parent when the Grid is visible and Cell-clicked in one of the other Dialogs.
I would prefer to keep using the single-Grid approach as the user gets to set the column widths, Row-colors etc and I'd rather not make them do that in every Form where the Accounts Grid is needed.
How can I reassign the dlgCommon.AccountsCellClick so that the click is trapped and used in dlgFolders and other Dialogs that call it too?
I'm not sure I folllow your structure and design, but I would place the grid that shows the accounts on a TFrame. This TFrame would hold all event handlers you need for the grid, in addition to the grid itself.
Then, whenever you need to show the grid, you instantiate the frame, assign its parent and the grid and event handlers are ready for use.
On a second and third reading, if dlgCommon is a form with a hierarchial structure like
dlgCommon: TdlgCommon
pnlAccounts: TPanel
AccountsGrid: TDBGrid
it appears that you have tried to "rip-out" (by changing the parent) the pnlAccounts from that form and then the event handlers don't work, just as you have noticed.
The idea of changing a components parent like this is a really bad idea, because when you assign a new parent to the grid, it will ofcourse not anymore show up in dlgCommon. It can be visible in only one dialog at a time.
If you want the grid simultaneously visible on various forms for (at least) some period of time, I would still use a TFrame as I already suggested.
In this case you can add an OnCellClick event manually to the forms private section
procedure DBGridCellClick(Column: TColumn);
and implement it in the form
procedure TForm1.DBGridCellClick(Column: TColumn);
begin
// whatever you want to do
end;
And you instantiate the frame as follows:
procedure TForm1.Button2Click(Sender: TObject);
begin
frame:= TFrame3.Create(self);
frame.Parent := self;
frame.Left := 8;
frame.Top := 75;
frame.DBGrid1.OnCellClick := DBGridCellClick;
end;
If, on the other hand, the user needs to see the grid only briefly, to select an account (and be done with it), I would simply show the dlgCommon modally.
I have a simple test app, with one empty form, and a second containing a TButton. The button script is like this:-
procedure TForm1.Button1Click(Sender: TObject);
begin
Form2.Show();
end;
Form2 is auto-created at startup. There's no other code at all.
When I run the app, I can press the button and Form2 appears. I can reposition/resize Form2 on the primary monitor, and then close it. If I press the Form1 button again, Form2 correctly reappears in the position it was last at. All fine so far...
However, if I position Form2 onto a secondary monitor, close it, and then press the button, then Form2 appears back on the primary monitor!
I want the form to reappear on the monitor it was last on - how can I get this behaviour??
This is because the default value for the form's DefaultMonitor property is dmActiveForm.
Set Form2's DefaultMonitor to dmDesktop, and the problem is resolved.
This question already has answers here:
How can I use an action to determine a control's visibility?
(3 answers)
Closed 8 years ago.
When I make a component invisible by setting the connected TAction to invisible, the onupdate event will not trigger anymore. To recreate, do the following.
Create a new VCL forms application
Drop a button, a checkbox and an actionlist on the form.
Create a new action, and connect the button to it.
Write the following code for the actions OnExecute and OnUpdate event:
procedure TForm1.Action1Execute(Sender: TObject);
begin
ShowMessage('Test');
end;
procedure TForm1.Action1Update(Sender: TObject);
begin
TAction(Sender).Enabled := not CheckBox1.Checked;
TAction(Sender).Visible := TAction(Sender).Enabled;
end;
Run the application. The button is visible, and works properly. Check the checkbox, and the button disappears. Uncheck the checkbox. The button doesn't appear. In fact, if you put a breakpoint in Action1Update, you'll never get to it. Why is this, and how do I fix it?
No need to fix this, it works as designed. Only visible controls need to update their state, so only actions whose linked controls are visible are updated. When you hide the button there's no more reason to update the action.
Have the OnUpdate only call a separate routine that does what is required. Then you can call that routine from other places. Action lists were designed for that.
I understand what you're trying to do, and it makes sense that you would want it to work that way. However, here's a workaround for the way it does work.
You can update other controls in an OnUpdate also. You're not limited to updating the control that receives the notification. So, in the action for the control that determines visibility, you can set the visibility of the other controls there. In your case, that's the checkbox:
Create a new action (Action2) and assign it to Checkbox1.
Then in the checkbox action's OnUpdate:
procedure TForm1.Action2Update(Sender: TObject);
begin
Button1.Visible := TAction(Sender).Checked;
end;
Be sure to assign an OnExecute to the checkbox as well. Something as simple as this is fine:
procedure TForm1.Action2Execute(Sender: TObject);
begin
TAction(Sender).Checked := not TAction(Sender).Checked;
end;
To me, this still makes logical sense. You'll be able to look in one spot to see all of the controls whose visibility relies on that checkbox being set.
You can override the InitiateAction method on the form. This will happen whenever the application goes idle, just as on OnUpdate event does for each action.
I have a form that is being opened by another form.
I set the Position to be poOwnerFormCenter, so that the new form is opened where the original was
However, when I move this new form and then go back to the original, its shown where it was when I first opened the new form, not where I closed it
How would I fix this?
Thanks!
I'm a bit confused by your question so I'll clarify what I'm try to solve here!...
I think what you're trying to do is
When Form2 Opens, it is positioned centrally to Form1 and Form1 is hidden.
When Form2 Closes, Form1 is shown (exactly where it was hidden).
I think you want to do is have Form1 Show where Form2 was closed.
So I'm guessing that you have some code like...
procedure TForm1.ButtonClick(Sender: TObject);
begin
Form2.ShowModal;
end;
and you were expecting Form2 to update form1's position because you set Form2's position to poOwnerFormCenter
Well if I guessed all that correctly then all you need to do to update Form1's position when Form2 closes is
procedure TForm1.ButtonClick(Sender: TObject);
begin
Form2.ShowModal;
Left := Form2.Left;
Top := Form2.Top;
end;
The problem is that you are reusing the same instance of the modal form. Setting the position only works the first time you show the form. You have to options here:
Option 1
You can destroy the modal form every time it closes. One of the ways of doing that is having this line on the OnClose event of the form:
Action = caFree;
Of course, that means you have to recreate the modal form from the caller every time as well.
Option 2
You have to manually set the modal form's position on the OnShow event.
Use the option which best suits you.
This is (I guess) because you recreate the form every time you display it. That is, you do
with TForm2.Create(nil) do
try
ShowModal;
finally
Free;
end;
Because you create a new instance of the TForm2 class every time you show it, and destroy it when the form has closed, the position changes; indeed, the new TForm2 object cannot possibly remember the position of any previous TForm2 object. They are two different objects (yes, same class, but that doesn't matter)!
The simplest solution is to add the TForm2 to the 'auto-create forms' list in the Project Options. It is there by default, but if you create it manually (as I think you do, and as in the code snippet above), you should have removed it from the list of forms that are automatically created...
Then you make sure that Unit1 uses Unit2, so that you can access the global Form2 variable in Unit2 from Form1 that resides in Unit1. While editing Unit1, press Alt+F11 to do this.
Then you can just show Form2 by doing
Form2.ShowModal;
The first time it is shown, it will respect its Position parameter, and position itself above its owner form. But then it will remember its position, so the second time you display it, it will be right where it closed the first time.
I currently have a delphi 7 project sitting in front of me and what the original creators of the software have done is used the main form as a launch pad for another form which contains the actual controls and logic behind the entire application. So basically, form1 loads up, is set to invisible and another form (the form with all the UI controls and logic) is created and shown, its a strange way to do things, but its the way they did it.
Now I'm not familiar with the way delphi 7 handles its forms, but this second window, the window with all the controls on, whenever i click the minimise button, the form does not drop down to the taskbar as one would expect, but rather, resizes so that only the minimise, maximise and close buttons are visible and then places itself at the bottom left of the screen, just above the start menu.
the creation of this second window is:
frmPlatform := TfrmPlatform.Create(frmMain);
ModalResult := frmPlatform.ShowModal;
where frmMain is the invisible form.
My question is, why does the second window not minimize as one would expect and drop to the taskbar? and how do i get it to work,
thanks
Standard behaviour of forms I'm afraid as the mainform is by default the only form shown by Delphi on the taskbar. You can however set other forms to appear on the taskbar as well:
procedure TForm1.CreateParams
(var Params: TCreateParams);
begin
inherited CreateParams(Params);
Params.ExStyle := Params.ExStyle
or WS_EX_APPWINDOW;
end;
And you can hide your current main form of course as well, see: http://delphi.about.com/od/adptips1999/qt/hidefromtaskbar.htm, and http://delphi.about.com/od/delphitips2008/qt/hide_taskbutton.htm for D2007 and up.
I think you will find that in standard Delphi apps only the main (first) form will be shown in the task bar. Since your main form is invisible that's your issue. The minimize is probably due to the second form being called with show modal rather than simply show.
Can you remove the first form or change which form is the main form? This can be done from the project settings page.