How to disable wait cursor using MessageDlg - delphi

In Windows 10, when I execute
MessageDlg('Hello', mtInformation, [mbOK], 0);
I can notice the cursor switch to hour glass in a flash while. I understand this is due the a flag UseLatestCommonDialogs to control the runtime using TTaskDialog. Is that possible to disable the hour glass cursor flashing by not touching UseLatestCommonDialogs?

Maybe you can use the ShowCursor(False/True) function. This function is tied to Winapi.Windows and controls the cursor.
I assume you should walk through this example about hiding or changing the mouse cursor system-wide: https://flixengineering.com/archives/484

Related

How to force the "Caps Lock is On" balloon for password editor?

I have a TEdit with PasswordChar set to * and I want the standard "Caps Lock is On" balloon to appear if the Caps Lock mode is on. That standard balloon appearing only when the editor is getting focus or when Caps Lock mode has been turned on, while the focus was in that editor.
My password editor is the first focused control of the application. So, when the application starts with Caps Lock mode previously on, I cannot see any balloons until my password editor will lose focus and then will be focused again. The user has a chance to not see that balloon in half of the use cases!
Can I force this "Caps Lock is On" balloon at application startup without switching focus?
The solution is to call WM_KILLFOCUS and WM_SETFOCUS, this will force the editor to show "Caps Lock is On" balloon:
if GetKeyState(VK_CAPITAL) and 1 <> 0 then
begin
if edtPassword.Focused then
begin
PostMessage(edtPassword.Handle, WM_KILLFOCUS, 0, 0);
PostMessage(edtPassword.Handle, WM_SETFOCUS, 0, 0);
end;
end;

Insert text from an Edit into any window where the mouse pointer is

How can I insert the text from an Edit control into any window where the mouse pointer is, without using the clipboard and/or window handle.
I am using Delphi 7.
Call GetCursorPos to find out where the cursor is.
Call WindowFromPoint to find the window under the cursor.
Send an EM_REPLACESEL message to replace the selection in that window. If nothing is selected then the text will be inserted at the caret.
Note: Be prepared for this to fail more commonly than it succeeds. Many applications don't used windowed edit controls. For a more robust solution you should look into UI Automation.
You asked for some code. Here's what it would look like:
var
Pos: TPoint;
Target: HWND;
...
if not GetCursorPos(Pos) then
RaiseLastOSError;
Target := WindowFromPoint(Pos);
if Target<>0 then
SendMessage(Target, EM_REPLACESEL, ord(True), LPARAM(PChar(Edit1.Text)));
If the window underneath the cursor is not an edit window, this will, probably, be benign.

Control's OnExit eats up mouseup event for new control when showing another window

I found this question on Experts-Exchange.
Control's OnExit eats up mouseup event for new control when showing
another window
The problem can be replicated easily.
place 3 tedits on a form. write a showmessage('exit') in edit1's
onexit event run the program give edit1 focus use the mouse to give
edit3 focus, click ok to the showmessage observe how you can't write
anything in edit3 now, until you click with the mouse somewhere on the
form ! give edit2 focus, then use to the mouse to give edit3 focus
observe how you can type what you want in edit3 now !
So far I've established that the problem lies in the fact that edit3
doesn't receive a mouseup-message when the old controls onExit event
displays a window of any kind, i've tried it as well with showing a
form of my own in the onExit event, same result. In fact, windows is
under the impression that the mouse is held down over edit3 after
you've clicked Ok to the showmessage
I guess it's a bug in Delphi/Windows but how to work around it ? I
know i can force a WM_LBUTTONUP on edit3's onMouseDown event (since
its the last event called in the process) but that's more than
tedious, and not always applicable
I am trying to do something similiar:
In the onexit event I show a warningbox and then want to proceed
as normal - moving the focus to where the user in fact clicked.
Is that possible?
Once again PostMessage to the rescue! Defer your dialog just a little bit longer so that Windows can finish its focus change. Post yourself a message instead of showing the dialog directly:
const
WM_SHOWMYDIALOG = WM_APP + 321;
TForm1 = class(TForm)
Edit1: TEdit;
Edit2: TEdit;
procedure Edit1Exit(Sender: TObject);
private
procedure WMSHOWMYDIALOG(var Message: TMessage); message WM_SHOWMYDIALOG;
end;
procedure TForm1.Edit1Exit(Sender: TObject);
begin
PostMessage(Self.Handle, WM_SHOWMYDIALOG, 0, 0);
end;
procedure TForm1.WMSHOWMYDIALOG(var Message: TMessage);
begin
ShowMessage('Nice one');
end;
And everything is fine :)
I'm not so sure that the reason of the behavior is an eaten mouse message. Anyway, either that's the case or not, when you activate a window in an OnExit event of a control, what you're doing is, changing the focus while the focus is changing. That's because, the window is activated before WM_SETFOCUS for the newly focused control returns. This is discouraged, the below quote is from 'Best practices' section of 'Win32 Activation and Focus', a blog entry on MSDN:
Avoid manually changing focus when getting and/or losing focus. This
usually proves to be error prone.
The fact that the controls are disabled during focus transfer due to the modal nature of the activated window certainly would not help. If you really must do this, an approach like Heinrich's answer would at least delay the launch of the window till the focus transfer completes.
In the onexit event I show a warningbox and then want to proceed as normal - moving the focus to where the user in fact clicked. Is that possible?
Yes, (Screen.)ActiveControl will always point to Edit3: before and after the call to ShowMessage:
procedure TForm1.Edit1Exit(Sender: TObject);
begin
ShowMessage('Exit');
PostMessage(ActiveControl.Handle, WM_LBUTTONUP, 0, 0);
end;
But this is just for completeness sake to your question! And it certainly is no tip nor advice! See Sertac's answer for the reason.

Why does OnMouseMove fire repeatedly when the mouse is not moving in D2010?

I'm porting a Delphi 5 app to D2010, and I've got a bit of a problem. On one form is a TImage component with an OnMouseMove event that's supposed to update a label whenever the mouse is moved over the image. This worked just fine in the original app, but now the OnMouseMove event fires constantly whenever the mouse is over the image, whether it's moving or not, which causes the label to flicker horribly.
Does anyone know what's causing this and how to fix it?
My psychic debugging sense tells me that you are on Windows, the label is a tooltip window and you are updating on every mousemove.
In all seriousness, I've seen this exact thing with tooltip window when we switched to Vista. It seems that more recent versions of the Windows tooltip window somehow generate WM_MOUSEMOVE messages when you update them. The only fix I could find was to only update the label when the text actually changes.
So, If you aren't on windows, Ignore me. But if you are on Windows, try updating the label text only when it actually changes.
Since I couldn't add a comment I'm using the answer section to confirm this behavior change. I have a project that was developed in Delphi 2007 where the OnMouseMove event is only called when the mouse position changes. I found that with XE OnMouseMove is constantly being called for the same code. I don't know why since they're both triggered by WM_MOUSEMOVE.
What I am doing till I get to the bottom of this is to compare the previous XY coordinates and exit if no change:
if ( x = ZoomRect.Right ) and ( y = ZoomRect.Bottom ) then exit ;
Mason, I can't reproduce this is a new D2010 (Update 4 & 5) VCL Forms application on Windows XP SP2. Here's what I did:
File|New|VCL Forms Application
Dropped a TImage and TLabel on the form
Picked a random image out of the default images folder (GreenBar.bmp) for the TImage.Picture
Double-clicked the TImage.OnMouseMove event in the Object Inspector, and added the following code:
procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
begin
Label1.Caption := Format('X: %d Y: %d', [X, Y]);
end;
Ran the application (F9).
The label showed "Label1" (the default caption, of course) until I first moved the mouse over the image. It then updated correctly to show the X and Y coordinates. As soon as I moved the mouse pointer out of the image, the label stopped updating.
It appears to be something in your specific code, or something specific to the version of Windows you're using, and not Delphi 2010 itself.

How do I make TProgressBar stop lagging?

I've got an app that runs a long set of operations, and I'm trying to use a TProgressBar to keep track of what's going on. I set a number of steps, and call .StepIt to increment the progress bar.
Problem is, it doesn't keep up very well. Instead of jumping directly to the correct position, it seems to like to slide gradually up to it. That's all well and good if it's eye candy you're after, but when I'm trying to get an accurate representation of my routine's progress, this makes it appear to be constantly lagging behind the true status. How can I turn that "feature" off?
I only notice this happening under Windows Vista. Not sure if it's also going on on XP or not, because when I test it on XP, the process goes a lot faster and it's over too quickly. :P But this may or may not be Vista-specific. Either way, it's driving me nuts. Does anyone know how to fix it?
I have a quick but partial and inelegant solution, if you don't mind having the progressbar yellow instead of green:
ProgressBar1.SmoothReverse := True;
ProgressBar1.State := pbsPaused; // for yellow or pbsError for red
Or if you don't mind loosing the vista/theme look and go back to a flat blue one:
UxTheme.SetWindowTheme(ProgressBar1.Handle, ' ', ' ');
The real "problem" according to Microsoft is that you try to "pervert" a ProgressBar into a Meter which they claim it is not.
You could also try to draw it yourself ;-)
Same problem on Windows7 !!
But the answer was already in one of the older posts:
If tou make the progressbar step backwards there will NO delay !!!
So I implemented this..... (and get instant updates)
if(progress < ProgressBar.Max)
then
begin
ProgressBar.Position := progress+1;
ProgressBar.Position := progress; //This will set Progress backwards and give an instant update....
end
else
begin //cannot set position beyond max...
ProgressBar.Max := progress + 1;
ProgressBar.Position := progress + 1;
ProgressBar.Max := progress; //This will also set Progress backwards also so instant update........
end;
I ran into exactly the same problem a while ago. After searching Google for a long time, I found that it is a Vista-specific problem. It seems to boil down to this: Microsoft added fancy animations to the progress bar control in Vista (i.e., the moving 'highlight'). To make updates more smooth, they implemented some sort of 'lagging' in the repaint of the control --- and this basically screws the whole progress bar control. Rather annoying, I'd say, especially since there doesn't seem to be a decent solution.
See for more details the replies by Arvid Winkelsdorf to this Embarcadero Discussion Forum post:
It's the same for VB, C++ and C#
somehow as the problem lies in the
Vista drawing of the new animated
ProgressBars. To provide a smoother
visual feedback drawing is delayed
when moving forward. Your application
cannot be sure that 100% will be
reached at any given time.
By setting the position back to a
smaller value, the ProgressBar drawing
is forced to jump back. No delay in
getting to a position smaller than the
current. So you'll have nearly 100%
immediately. Afterwards set to the
maximum and you'll have exactly 100%.
[...]
There is a similar glitch when using
the new Vista ProgressBar Styles like
PB Paused or PB Error. If the bar is
still moving (MS part) and your app
sets the color to paused by
SendMessage (like in D2009) the
message will be ignored by the
ProgressBar.
Maybe you can try to set the position of the ProgressBar directly instead of using the StepIt procedure. I'm on XP with Delphi 7 here, so I can't test it, but looking at the code of TProgressBar it uses a different message (PBM_SETPOS instead of PBM_STEPIT). So maybe it sets the position of the progressbar without an animation.
Additionally there are several 3rd party components which provide better Progress bar implementations that still render nice on Vista. Personally, I prefer the one from Raize components which works quite well. It doesn't "lag" like the windows control does and works independent of any theming.
If you don't really want anything fancy, then you can always build one yourself using a panel and a tshape aligned left inside the panel. Resize the tshape to be a % of the panel it sets on.
I had the same problem, my solution was to switch to another control available in the VCL :
I choose to use the Range of TTrackBar to display the progression.
(with slider off and control resized to hide the range marks).
Not the same visual (particulary if themed), but it fit well my need (no lag).
Here is a simple solution:
ProgressBar.max := ProgressBar.max +1;
ProgressBar.StepBy(2);
ProgressBar.StepBy(-1);
ProgressBar.max := ProgressBar.max -1;

Resources