How to avoid setting focus when showing multiple forms? - delphi

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

Related

Delphi - Changing active page's tab color and having it reset after clicking on another tab

So in the program I'm writing, I'm using a TPageControl component with multiple tab sheets. I want to change the color of the tab of the sheet that is currently the active page on the PageControl and then have the color be reset after clicking on another page (then that tab will change due to it being the active page and so on...), to make navigating the page control a bit easier. But I'm not sure how to do it? I did try using the OnChange procedure of the page control and some code like this (I know it's horribly wrong but I ran out of ideas and google searches. It didn't work anyway.):
with pgcTabs.ActivePage do
begin
brush.color:=clBlue;
font.color:=clWhite;
end;
Thanks in advance for the help!
Kind Regards
PrimeBeat
You can't. Apart from using TTabSheet.Highlighted you have no control over how the tabs are displayed.
Or you have to fully draw it yourself, as usual as for most other controls: set TPageControl.OwnerDraw to true, then use the OnDrawTab event to paint whatever you want to. It should be identical to TTabControl.OnDrawTab (see answer). The drawbacks (pun intended) of painting everything yourself is usually all the extra work to do: checking dimensions, interpreting accelerator keys, respecting system colors and settings (i.e. LTR)...
In my opinion "just adding a color" has little to no value compared to how the control by default paints already with all its advantages and features. Consider color blindness: those people might rather have problems.

Firemonkey and Mobile Navigation

I have an interesting observation and question, but first a comment. I have been using Delphi for 14 years and have taken a job developing an iOS mobile application using XE5. This is my first time using FMX and frankly I feel like I am stepping back in time many moons ago. In other words, if this is the future, then it feels like I have crippled. No problem though. Roll with the punches. Developing in this brave new world is not just a job. It is an adventure.
Now my question. Start a FMX mobile project using the "Header/Footer with Navigation" as your base. Then add an edit control (Edit1) to the first tab item. Then set the tab control align to none and move it to the right until you can clearly see the form itself. Then add an edit control (Edit2) to the form.
Now set the form's active control to Edit1 and run the app - no focus on Edit1. Now set the form's active control to Edit2 and run the app - focus is placed on Edit2. Interesting. Tab is a foreign word to tablets, right? Why have active control or even setfocus available? Is this an oversight by Embarcadero? Any thoughts?
Long story short I think they both have potential uses.
I use the SetFocus call to manually show the keyboard. Lets say the user navigates to a page where they're 100% sure to be putting in their username (or any text), I'll use ctrl.SetFocus to show the keyboard just to save them having to click (or is it press now?) on the edit.
I don't see ActiveControl being as useful, but it could definitely still be used. You could possibly use it to set up some sort of tabbing like structure for when the user presses Next on the keyboard (when the edit's ReturnKeyType is rkNext).

How to capture mouse clicks outside of form (like with Code Insight in Delphi)

I like the idea of the Delphi Code Insight window (custom listbox on form without borders basically) where you can click outside of the form and it will close it automatically.
My first thought was to call SetCapture/ReleaseCapture in the FormCreate and FormDestroy respectively. I set the form's caption to X/Y on the FormMouseMove, but it doesn't update the coordinates outside of the form.
If I call SetCapture/ReleaseCapture from within MouseDown and MouseUp, it does update the coordinates as expected, so that proves the concept does work.
I tried other things as well, e.g. post a WM_USER in the OnShow event, and call SetCapture from there, but it still doesn't update the coordinates. I then tried the TApplicationEvents component (OnMessage), but that doesn't work either.
I've read several articles already, but wasn't able to find what I was looking for. Some articles called SetCapture from within the MouseMove, but that doesn't work when the mouse cursor starts outside of the form. Hrm...
The next step would be to use a WindowsHook, but that's where I stopped. I know how to implement one, but it just seems like I'm missing something really obvious here. There must be a simpler way to do this.
Any ideas? :)
Cheers,
Jarno
What you want can be done easier by adding TApplicationEvents to your form and use the event OnDeactivate. That one gets triggered whenever the application loses focus.
Maybe WM_NCHITTEST can help you somehow. As they say, if the mouse is captured, this message is sent to the window that has captured the mouse. So I would capture the mouse for the form and then wait until result of this message is HTNOWHERE, which should mean "out of the window".
But as far as I can remember, this never worked for me fine, so I finally used (as you mentioned) mouse hook.But in my case I've had a lot of components on that popup form and you need to consider messaging for them too.
The implementation I've used (with a little changes) and which works is here.
I had a similar problem (I needed to implement a scrolling windows if the mouse pointer hovered over a special area and I was not able to use SetCapture)
and circumvented it using a timer + GetCursorPos method.
Just do then a ScreenToClient and check if the mouse is within the window.

Drawing and clearing the desktop canvas with Delphi

I'm trying to draw over the whole screen by using the desktop canvas and painting to it directly. The problem is I can't clear that desktop canvas. I've tried setting the canvas.pen.style to psNotXOR and draw over the old image but unfortunately, this is not reliable enough and some left overs are still present in some conditions.
My need is to draw a selection rectangle around a window / control when the mouse is over it.
You don't write on what OS you have problems with the artefacts after clearing.
At least with desktop composition activated it is a very bad idea to draw directly to the desktop and to do XOR painting (see "Drawing To and Reading From the Screen -- Baaaad!" in this blog post). Apart from the negative performance implications you can't be sure what other painting happens at the same time and what effects and animations alter the displayed content, so a simple XOR may not be enough to completely erase everything.
One possible way to implement it would be a transparent overlay window of desktop size, and to draw your rubber band selector over that. Invalidating the whole window if the size changes should be enough, no need to erase the old selection line. If the overlay is removed the line will be gone too. Desktop composition will make sure that no flicker occurs. However, switching applications while selecting an area will be problematic, you need to catch this and immediately cancel the selection.
Edit:
I just tested it with Delphi 2009, and with the following test app:
a form with FormStyle set to fsStayOnTop and with AlphaBlend set to True
with an overridden CreateParams() method to add the WS_EX_TRANSPARENT extended style flag
I can pass all mouse clicks through to the underlying windows while being able to draw into a window on top of them. This should get you started.
I've done some stuff like this in the past and I've never come up with an acceptable solution.
Having a think about it though you could send the desktop HWND an invalidate command.
Because the desktop is a modified listview control you should able to use something like
procedure InvalidateDesktop;
begin
RedrawWindow(GetDesktopWindow, 0, 0, RDW_INVALIDATE);
//if that doesn't work then try this:
//Sendmessage(GetDesktopWindow, wm_setredraw, 1, 0);
end;
That might do what you want, I haven't tested it as I've just knocked it up for the example.
the problem is that Windows won't return me the control behind the mouse
I think you need to hook the mouse event messages for this - the hooked message then gives you the window handle that the mouse is over.
Look up SetWindowsHookEx(WH_MOUSE,,,) and MOUSEHOOKSTRUCT.
This is how we do it in our app:
FBitmap.Canvas.Brush.Color := clWhite;
FBitmap.Canvas.FillRect(FBitmap.Canvas.ClipRect);

Why is the caret suddenly centered in an edit field?

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;

Resources