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.
Related
I'm experiencing some problems programmatically selecting all the text inside a TMemo component
I have an OnClick event handler that looks something like this
procedure TForm8.Memo1Click(Sender: TObject);
begin
Memo1.SelectAll;
end;
If I click inside the memo where the text ends, everything is selected.
But If I click somewhere at a position before where the text ends, the selection goes from 0 to the clicked position instead of selecting everything.
I have tried messing around with the memo's SelStart, SetLength and CaretPosition properties before calling SelectAll, but I haven't got this to work.
Interestingly enough, when I put a breakpoint inside the TCustomMemo.SelectAll procedure and press ctrl+a then SelectAll is also called inside TStyledMemo.KeyDown, but then everything is selected. It seems clicking inside the memo does something that makes SelectAll behave differently somehow.
I'm on Delphi 11.0
Does anybody know if it's possible what I'm trying to do?
I have some TRadioButtons on Form2 and call Form2 from Form1 with this code:
procedure TForm1.btnCallForm2Click(Sender:TObject);
begin
Form2.RadioButton2.Checked:= true;
Form2.ShowModal;
end;
If user clicked btnCallForm2, Form2 will be displayed, then user clicks RadioButton3 and closes the form, and then reopen it by clicking btnCallForm2 again.
Now Form2 displayed again but RadioButton3 is checked instead of RadioButton2.
Q: What is this behavior, is it a bug? How to set checked my desired RadioButton instead of what is selected by the user in previous turn?
This is not a bug. The reason that you have this "strange" behavior is that if the Form2 is not destroyed, then next time it becomes visible (e.g. ShowModal) it remembers which control had the focus.
In your case the last control in focus is the RadioButton3 (because you clicked on it to change the "checked" state). So even if you are changing the "checked" state back to RadioButton2, the focus will be restored to RadioButton3 when the form is next activated. To restore the focus, the control is sent a WM_SETFOCUS. Read the rest from documentation for default message processing for button controls:
WM_SETFOCUS Draws a focus rectangle on the button getting the focus.
For radio buttons and automatic radio buttons, the parent window is
sent a BN_CLICKED notification code.
This BN_CLICK notification (WM_COMMAND message) sets the state of the radio button to checked.
The rationale behind this behavior can be found while navigating the radio buttons with the keyboard. When you press up/down arrow while on one of the radio buttons, the next radio button that receives the focus becomes checked.
This behavior only applies to radio buttons, e.g., try the same with another control (e.g. check box), that its state is not altered when it has focus. You will see that everything is working as expected
As kobik was suggesting, a fast and easy solution would be to set the ActiveControl to nil before showing the Form2
Form2.ActiveControl := nil;
or in the light of the documentation:
Form2.ActiveControl := Form2.RadioButton2;
or you could destoy and recreate the form as following:
Remove the Form2 from the AutoCreated Forms in Project->Options->Forms and create it manually in the ButtonClick event
procedure TForm1.btnCallForm2Click(Sender:TObject)
begin
Form2 := TForm2.Create(nil);
try
Form2.RadioButton2.Checked:= true;
Form2.ShowModal;
finally
FreeAndNil(Form2);
end;
end;
I have a problem where:
I have a form with just a combobox.
The combobox has focus and mouse is not hovering over the form when item 3 happens.
I trigger the combobox's drop-down list to show on a key-press event.
When the drop-down list is visible and then I move my mouse pointer over the form, the pointer is either invisible, shows that it is busy, or shows the resizing icon but does not turn back to a normal pointer when over the form.
Is there something that can be done to assure that, when the drop-down of the combobox shows, that the mouse pointer is visible when I move the pointer over the form?
I have tried:
Applicaiton.ProcessMessages after showing the drop-down.
Changing focus to the form the combobox is on after showing the drop-down.
Adding Key := #0; after calling the drop-down to show.
procedure TForm1.ComboBox1KeyPress(Sender: TObject; var Key: Char);
begin
SendMessage(ComboBox1.Handle, CB_SHOWDROPDOWN, Integer(True), 0);
Key := #0;
end;
Tried using a timer to trigger the drop-down within the key-press event.
Tried using "SetCursor" after commanding the drop-down to appear.
Tried using ".DroppedDown", but did not see any difference in result from that of "SendMessage".
I would hope to be able to show the mouse pointer after the drop-down is displayed, but it is hidden instead. Thanks for any suggestions.
(NOTE: This problem I have run into is not exlusive to Delphi. I was able to duplicate the issue using Visual C# 2017. Either way, if there is a way to correct this, it would be good to know).
As already commented to the question, the issue is not Delphi related. You can observe the same behavior in dialog boxes which contains a similar combo that the OS presents. One example is the one on the "run" dialog.
Involving a single environment, re-setting the cursor in an OnDropDown event handler fixes the problem.
procedure TForm1.ComboBox1DropDown(Sender: TObject);
begin
winapi.windows.SetCursor(Screen.Cursors[Cursor]);
end;
Originally I tested the above because no one calls SetCursor after the drop down. Though it seems that no one calls it before either. So I have no idea about the cause or why the above fix works.
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.
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.