Why is the caret suddenly centered in an edit field? - delphi

I have a "username" TEdit on a Delphi 2006 login form. When the application starts up the user is asked to enter the username. The TEdit gets focus and the caret is placed in its horizontal center for some reason. As soon as anything is typed the caret is left aligned again and everything looks normal.
It is also strange that it wasn't always like this. This behaviour suddenly started a few years ago (I believe we still used Delphi 6 at that time). Any idea what might be causing this?
Additional info (has been asked for):
The problem is widespread: D2006 and D6 (I believe), 5 or 6 Delphi instances on as much computers, all applications using that login form. The effect is limited to the form however, it does not occur on other TEdits.
The TEdit is not filled with spaces (that would be strange to do in the first place).
More info (Nov 13):
The caret is not centered exactly, it is almost centered.
Currently it seems to occur in a DLL only. The same login dialog is used in regular executables and does not show the problem there (although I believe it did at some time).
The edit field is a password edit, the OnChange handler sets an integer field of that form only, there are no other event handlers on that edit field.
I added another plain TEdit, which is also the ActiveControl so that it has focus when the form shows (as it was with the password edit). I also removed the default text "Edit1". Now the issue is present in that TEdit in the same way.
The "centered" caret goes back to normal if either a character is entered or if I tab through the controls - when I come back to the TEdit it looks normal. This was the same with the password edit.

I had also the same problem in Delphi 2007,
with a TEdit placed in a modal form called by double-clicking in a Grid.
I made some tests launching the same Form from a TSpeedButton.
I noticed that the problem with the TEdit appears only when the grid is focused.
after more tests the problem appears to be a bug in the VCL.
in TCustomGrid.paint there is a Call of SetCaretPos, even if the grid is not on an active Form.
../..
Focused := IsActiveControl;
if Focused and (CurRow = Row) and (CurCol = Col) then
begin
SetCaretPos(Where.Left, Where.Top);
Include(DrawState, gdFocused);
end;
../..
the code above is from TCustomGrid.paint in Grids.pas
in this code, Focused is set to true if the grid is the "activeControl" of the parent form, the code don't take into account if the form is active or not.
then, if the grid need to be repaint, setCaretPos is called with grid coordinates, causing the bug mentioned in the question.
The bug is very difficult to notice because, most of the times, the caret simply disappear from the active form instead of blinking near the middle of a TEdit.
steps to reproduce the bug :
start new VCL form app.
add TStringGrid into it.
add a second form to the app with just a TEdit in it.
return in main form (unit1) and call form2.showmodal from the grid DblClick event.
that's all : you can launch the application and double click on a grid cell.
if you drag the modal form away of the main form, the grid will need to be repaint, then causing the caret to disappear from the modal form (or to appear in the middle of the TEdit if you are very lucky)
So, I think a fix is needed in Grids.pas.
in the excerpt of grid.pas above, I suggest replacing the call of the function IsActiveControl by a call of a new function called IsFocusedControl :
// new function introduced to fix a bug
// this function is a duplicate of the function IsActiveControl
// with a minor modification (see comment)
function TCustomGrid.IsFocusedControl: Boolean;
var
H: Hwnd;
ParentForm: TCustomForm;
begin
Result := False;
ParentForm := GetParentForm(Self);
if Assigned(ParentForm) then
begin
if (ParentForm.ActiveControl = Self) then
//Result := True; // removed by DamienD
Result := ParentForm.Active; // added by DamienD
end
else
begin
H := GetFocus;
while IsWindow(H) and (Result = False) do
begin
if H = WindowHandle then
Result := True
else
H := GetParent(H);
end;
end;
end;
this fix (made in Delphi2007) worked well for me, but is not garanteed.
(also, do not modify directly units of the VCL).

Just a few additional questions:
Is this problem on one pc or on more pc's?
Does it occur on one application or on all applications?
Does it happen only on your Delphi applications or on all applications?
If it is only on one pc, I think it is a strange registry setting. If its on more pc's but you only have one delphi development pc, it could still be a registry setting. But there are other possibilities.
You could try some tests:
Create an simple app on the dev pc and run it on another. Does this show the effect.
Use an app that is created by Delphi but build on another pc that does not show the effect, and run it on the dev pc, does this show the effect?
I really think this is a registry setting. According to the information you gave me, it happened since Delphi 6 and is still happening.
It also can be a locale setting but then it has to happen in more programs.
Edit:
Thanks for the extra info.
So it looks like the problem can be isolated to a single form. But it occurs on all pc's.
What you can do, is delete the edit, and re-add a new one. This saves searching for weird property values.
Are there events hooked on the TEdit that can possible explain the effects?
What property values are set? (But I prefer a look at the dfm and the code, because then I'm possible able to reproduce the effect.)

Are you sure it is a simple TEdit? It might be initialized with a few spaces instead of an empty string. The onChange handler then might just strip spaces as soon as you start typing.
A TEdit extension might have text alignment set on centered instead of left, and set text alignment only on onChange.
[edit]
Please show the event handlers of the TEdit.

I've also noticed this behaviour in richedits.
One place in our app is a double click on a grid which displays another screen containing a RichEdit. The caret always seems to appear in the Richedit in the same place as the double click on the grid occured, ie if the dblclick was on the 3rd line of the grid, the caret will appear ~3 lines down on the edit. As soon as a key is pressed, the caret resets to the correct position of top left.
Its not limited to a certain form or pc as it happens on all developers machines and also on clients machines.
The app was originally developed in Delphi 5, but the problem didn't occur (or wasn't noticed) until we moved to D2006.
Its not a particularily big problem, just... irritating.

Another workaround:
Before showing the second form, prevent the grid on the first form doing Paint action. Code snippet as below.
Gird.BeginUpdate;
try
//Show the second form here
finally
Grid.EndUpdate;
end;

Related

How to avoid setting focus when showing multiple forms?

First of all, this question is continued off of an answer of mine on another question...
Assume I'm using this particular solution to place a frame around any given window. How can I make this to where the focused form keeps its focus without jumping focus to these frame forms? Currently, i'd have to call SetFocus to set anything straight, but, then the windows get glitchy and don't show right.
How can I make sure the focused form keeps its focus at all times regardless of these 4 border forms showing?
Instead of showing edge windows with directly Show procedure (FTop.Show), use show window without activation:
ShowWindow(FTop.Handle, SW_SHOWNOACTIVATE);
FTop.Visible := True;
Daniel Rikowski wrote here

Form moving to the back and staying active

I have a largish Delphi 6 app that I have ported to Delphi XE3. At one point the main form launches another non-modal form. Sometimes (say 50%) after a second or two the newly created form moves behind the main form. Even thought it is now at the back, the newly created form still has focus so there are no activate/deactivate events. There are a few Timer controls and I have disabled them. It still happens.
I can accept my code is doing this -- but how can I find out what is happening? Is there a way to intercept when then new form moves to the back?
Just to be clear: I want both forms to be used separately. Any of them can appear behind the other. What is happening at the moment is that the z-order seems to be changing.
I have found the answer to this. I discovered I had added a CreateParams override that did this:
// make a taskbar window
inherited CreateParams( params );
params.ExStyle := params.ExStyle or WS_EX_APPWINDOW;
params.WndParent := GetDesktopwindow; // this line caused the problem
Commenting the WndParent solved it. The effect is bizarre though. It is as if there is a timer that goes off about a second after any key or mouse event that forces the window behind others. Thanks to David Heffernan whose comments about stepping CreateParam made me notice it.

TStyleManager.SetStyle leaves visual components on other TPageControls not visible

A MainMenu option in my app calls:
TStyleManager.SetStyle('Ruby Graphite');
It properly changes the style in my XE2 (Update 3) application almost everywhere. Here's the problem:
I have a TPageControl with 3 TabSheets, each containing a TFrame. The above call properly changes the style of the currently visible TabSheet's components to 'Ruby Graphite'.
However, when I click to switch to another tabsheet, all of its components are invisible until I move my mouse over them. When I return to the original TabSheet, its components too are now not visible until I hover over them.
I tried explicitly calling .Refresh and .Repaint on the frames themselves, but that didn't make the components on them visible.
What's weird is that executing:
TStyleManager.SetStyle('Windows');
returns the style to the standard, with all components visible.
The TTabSheet is on a panel which is on a panel, if that matters. And, I'm using some 3rd party components (not in these frames) that are threaded. I believe that I have disabled them though.
Any suggestions on how to force the visual components on a formerly hidden tab to become visible after changing the style from Windows?
EDIT: Link to short screen video that shows the refresh problem: http://tinyurl.com/sostyle.
I have also on occasion found that the software doesn't respond when clicking on the icons (like maximize) in the upper right corner. There's just something weird going on that is over my head. So far, I've been unable boil this down to a small example from the 40,000 lines of code in the application.
Here's a solution and a direction to try that worked for me on Delphi XE4.
I have found that I get the same issues when I minimize a form that is set to use the TStyleManager and sets styles dynamically during the execution of the application.
Another problem besides the redraw problem that I noticed is one that involves the form style not being set to a sizeable when the form is restored from being minimized to the taskbar or a trayicon. The sizeable form border problem and the redraw problem seem to be linked.
I overcame the redraw problem and the border resizing problem by adding an event handler for the OnClick event of the TrayIcon component and calling RecreateWnd for the form that uses the TStyleManager.
Currently it looks like this, with the jtiApp component being a TJvTrayIcon component:
procedure TMainForm.jtiAppClick(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
if not Visible then
begin
WindowState := wsNormal;
RecreateWnd;
Show;
end;
end;
That seems to take care of the redraw problem and the border settings for the recreated form. I'm not sure if that's a JVCL issue or with the TStyleManager but that fix worked when it was an issue dealing with a restore from the tray via a TrayIcon component.
I hope that helps with your issue and others who view this solution.

How do I get rid of this? (Looks like the form version of mouse trails)

I have cursor shaped forms (functioning as actual cursors). Whenever I drag it makes what looks like mouse trails.
The red and white stuff. See the little red arrow on the upper heart and the little white arrow on the lowest heart? Those are my cursor shaped forms, it's a picture on a tiny form (I cut regions so that the form will be shaped like the picture on it). Those are created in the MainUnit (which I minimized).
form trails http://img10.imageshack.us/img10/9718/mousetrails.png
When I click and hold, it makes these trails... hovering over those will erase it.
How do I get rid of this behavior?
And I can get rid of these by refreshing but if I refresh everytime a mouse moves there is terrible flickering. My current solution is refreshing whenever there is a click, but I want a solution that will get rid of the behavior and not just erase it after it gets drawn.
Okay, I tried it without the wallpaper.
No wallpaper http://img830.imageshack.us/img830/6595/nowallpaper.png
It's the same effect inside folders too.
Through a little more experimenting. I've discovered that it wasn't the (cursor) form at all. And it wasn't the code.
I tried moving (randomly) forms (with a timer using it's left and top properties). And it seemed okay at first but when I click and hold on the desktop. This happens:
Form Trails http://img411.imageshack.us/img411/7409/formg.png
Soooooo. Any suggestions as to what I should do to avoid/minimize/control this?
Update your video driver.
Or, as a shortcut, fallback to stock plain vanilla (i.e. standard Windows-supplied) VGA drivers, without changing anything else. If the symptom then persists, the problem is not in the driver, and you can forget about the driver update. (This shortcut is a shortcut because you often cannot easily undo a driver update, just in case you'd want.)
Based upon Sertac Akyuz comment and http://msdn.microsoft.com/en-us/library/dd145034(VS.85).aspx, try the following:
function TForm1.WaitUntilDesktopUnlocks: Boolean;
var
desktopUnlocked: Boolean;
begin
desktopUnlocked:= False;
while not desktopUnlocked do begin
desktopUnlocked:= LockWindowUpdate(Self.Handle);
LockWindowUpdate(0);
end;
end;
procedure TForm1.DoMoveCursorWindow() // method called to move the window each step
begin
WaitUntilDesktopUnlocks;
Self.Left := Self.Left + 1;
Self.Top := Self.Top + 1;
end;

Multiple form Delphi applications and dialogs

I have a Delphi 7 application that has two views of a document (e.g. a WYSIWYG HTML edit might have a WYSIWYG view and a source view - not my real application). They can be opened in separate windows, or docked into tabs in the main window.
If I open a modal dialog from one of the separate forms, the main form is brought to the front, and is shown as the selected window in the windows taskbar. Say the main form is the WYSIWYG view, and the source view is poped out. You go to a particular point in the source view and insert an image tag. A dialog appears to allow you to select and enter the properties you want for the image. If the WYSIWYG view and the source view overlap, the WYSIWYG view will be brought to the front and the source view is hidden. Once the dialog is dismissed, the source view comes back into sight.
I've tried setting the owner and the ParentWindow properties to the form it is related to:
dialog := TDialogForm.Create( parentForm );
dialog.ParentWindow := parentForm.Handle;
How can I fix this problem? What else should I be trying?
Given that people seem to be stumbling on my example, perhaps I can try with a better example: a text editor that allows you to have more than one file open at the same time. The files you have open are either in tabs (like in the Delphi IDE) or in its own window. Suppose the user brings up the spell check dialog or the find dialog. What happens, is that if the file is being editing in its own window, that window is sent to below the main form in the z-order when the modal dialog is shown; once the dialog is closed, it is returned to its original z-order.
Note: If you are using Delphi 7 and looking for a solution to this problem, see my answer lower down on the page to see what I ended up doing.
I'd use this code... (Basically what Lars said)
dialog := TDialogForm.Create( parentForm );
dialog.PopupParent := parentForm;
dialog.PopupMode := pmExplicit;
dialog.ShowModal();
I ultimately ended up finding the answer using Google Groups. In a nutshell, all the modal dialogs need to have the following added to them:
procedure TDialogForm.CreateParams(var Params: TCreateParams);
begin
inherited;
Params.Style := Params.Style or WS_POPUP;
Params.WndParent := (Owner as TWinControl).Handle;
end;
I'm guessing this does the equivalent of Lars' and Marius' answers in Delphi 7.
Is the dialog shown using ShowModal or just Show? You should probably set the PopupMode property correct of the your dialog. pmAuto would probably your best choice. Also see if you need to set the PopupParent property.
First of all, I am not completely sure I follow, you might need to provide some additional details to help us understand what is happening and what the problem is. I guess I am not sure I understand exactly what you're trying to accomplish and what the problem is.
Second, you shouldn't need to set the dialog's parent since that is essentially what is happening with the call to Create (passing the parent). The dialogs you're describing sound like they could use some "re-thinking" a bit to be honest. Is this dialog to enter the properties of the image a child of the source window, or the WYSIWYG window?
I'm not sure I quite understand what you are getting at, but here's a few things I can suggest you can try...
This behaviour changes between different versions of Delphi. I'd suggest that this is due to the hoops they jumped through to support Windows Vista in Delphi 2007.
If you are using Delphi 2007, try removing the line from the project source file that sets the Application.MainFormOnTaskBar boolean variable.
With this removed, you should be able to use the various Form's BringToFront / SendToBack methods to achieve the Z-ordering that you are after.
I suspect that what you've discovered has been discussed on this link
Of course, I may have just missed your point entirely, so apologies in advance!

Resources