Changing the default modal result of a form.showModal - delphi

In my Delphi application I have a custom Yes, No, Cancel dialogue, which will be called from the main form to confirm saving the changes made to the current file edited. This would normally be achieved by messageDlg() but I wanted this dialogue to have customised looks, so I am trying to achieve this functionality by
case myDialogue.showModal of
mrYes: <<save changes>>;
mrNo: <<quit application without saving changes>>
mrCancel: <<set the closeAction to caNone and do nothing>>
end;
The problem is that, by default, the form reacts to pressing the Escape key by returning mrNo TModalResult. And you can see how BAAAD this is, since your intuition tells you that Esc-aping the modal dialogue will CANCEL the intended Quit Application process, but in fact what happens is you issue a Don't save any changes command and application quits.
I have not noticed this behaviour until I lost an hour's work in this fashion. No FormKeyPressed event handler or anything responding to key presses was put into the myModalDialogue code. It just so works that pressing the Esc in forms shown using showModal will return mrNo. How can I override this default behaviour?

You need to make sure that the Cancel property of the "No" button is False, and that the Cancel property of the "Cancel" button is True.

Set the Cancel and Default properties of the buttons in your dialog.

Related

How to make Electron tray click events working reliably?

In my OSX Electron app I have a tray icon that I would like to toggle between opening and closing the Electron app window. Similar to how clicking on the OSX Dropbox tray icon will open and close the Dropbox tray menu, no matter how fast you click the tray icon.
Here is the code I'm using:
tray.on('click', function(e){
if (mainWindow.isVisible()) {
mainWindow.hide()
} else {
mainWindow.show()
}
});
This works if you click slowly (wait a second between clicks) however if you click repeatedly, more than 1x in a second, the click fails and nothing happens. I couldn't find any type of delays in the docs. Any ideas on what's going on and how to make the click event work reliably?
The problem you're describing is easy to reproduce. The result you're getting is not a bug or a wrong implementation on your side but it's the expected result regarding the current way Electron is handling these click events on a tray element.
The class Tray exposes 3 events relative to click: click, double-click and right-click.
If you use the right-click event, you're not going to have this issue, you can click as fast as you want, you'll get your callback called every times.
The Electron code for macOS for example to handle this event is the following:
- (void)rightMouseUp:(NSEvent*)event {
trayIcon_->NotifyRightClicked(
[self getBoundsFromEvent:event],
ui::EventFlagsFromModifiers([event modifierFlags]));
}
For every right click, they're firing the right-click event and that's it.
Now if we take a look at how the left click are handled, the code is slightly different:
- (void)mouseUp:(NSEvent*)event {
// ...
// Truncated to only show the relevant part...
// ...
// Single click event.
if (event.clickCount == 1)
trayIcon_->NotifyClicked(
[self getBoundsFromEvent:event],
ui::EventFlagsFromModifiers([event modifierFlags]));
// Double click event.
if (event.clickCount == 2)
trayIcon_->NotifyDoubleClicked(
[self getBoundsFromEvent:event],
ui::EventFlagsFromModifiers([event modifierFlags]));
[self setNeedsDisplay:YES];
}
When the tray icon get clicked multiple times, the event.clickCount doesn't always return 1. Instead, it returns a value that counts the clicked times.
So when you're click the tray icon very fast, event.clickCount will have a value greater than 2 and they're only emitting an event when the value is 1 or 2 and if it's not the case, they don't have any fallback, they simply don't emit any event. That's the result you're seeing in your tests when clicking fast enough.
So without modifying the Electron implementation yourself, submitting an issue or a pull request, you can't at the moment avoid this behaviour.
Electron 3.0 introduced an API that prevents waiting for double-click.
// Ignore double click events for the tray icon
tray.setIgnoreDoubleClickEvents(true)
"Sets the option to ignore double click events. Ignoring these events allows you to detect every individual click of the tray icon. This value is set to false by default."
Related Docs | Release Notes for Electron 3.0

Delphi - how do I find out which modal dialog has focus and bring it to the front?

I have a Delphi 2006 app which can pop up a modal dialog in response to an error condition. It seems to get itself into a state where one of these modal dialogs is open, positioned in front of the main form, but neither form is responding to messages. Clicking on either gives a "bonk". The app is running fine, the UI is updating the main form, but you can't do anything. I guess there is most likely another modal dialog under the main form. Whether it is one of mine or one from Windows I have no idea.
Other points:
the app responds to keyboard shortcuts OK. One of these shortuts shuts down the app gracefully and this worked. I have been unable to reproduce the situation since.
the app has a tray icon. This responds to right mouse clicks. If I minimize the app from here the main form minimizes and leaves the modal dialog displayed, still without focus. If I restore the main form, things are as they were, with neither window having focus. Alt-tab has similar results.
platform is Windows 7
I call DisableProcessWindowsGhosting before any forms are created
I open the modal dialogs with
ModalDialog.PopupParent := MainForm ;
ModalDialog.ShowModal ;
I postpone these error dialogs if other modal dialogs are open:
if (Application.ModalLevel = 0) then
{open modal dialog}
My question has two parts:
Is there a way of programmatically finding out what window has focus? I could then take some action for this scenario or a last resort I could them provide a shortcut key to bring it to the front or take some evasive action (depending on the dialog) like set the ModalResult to mrCancel.
How can this situation arise? Normally when I get a modal dialog behind the main form (I can do that by getting the modal dialog to open, minimizing the app from the tray icon, then restoring the app again - the app main form restores in front of the dialog, with the dialog still retaining focus), I can bring it to the front again by clicking on the tray icon, or close it with the Esc key but it didn't work in this case.
**UPDATE**
Misha's fix worked apart from non-delphi dialogs like TSaveDialog. I was able to get them to work as well by adding Application.ModalPopupMode := pmAuto ; just before the call to Execute.
By "got it to work" I mean that the save dialog was in front after the following sequence:
open save dialog
minimize app from tray icon
restore app from tray icon
whereas it was behind the main form without the ModalPopupMode := pmAuto.
So I'm hoping these changes will help the (as yet unreproduced) problem.
If a form that has focus takes too long to respond to messages (Form1), so that Windows thinks Form1 is unresponsive, and Form1 then displays a modal form (Form2), after Form2 is displayed and the application is processing messages again, Form1 will be brought to the front, thereby potentially "covering" Form2.
Putting this in the Application.OnIdle event will do the trick:
if Assigned(Screen.ActiveForm) then
begin
if (fsModal in Screen.ActiveForm.FormState) and
(Application.DialogHandle <= 0)) then
begin
Screen.ActiveForm.BringToFront;
end;
end;
The last active popup window (VCL or not) can be queried with GetLastActivePopup:
function GetTopWindow: HWND;
begin
Result := GetLastActivePopup(Application.Handle);
if (Result = 0) or (Result = Application.Handle) or
not IsWindowVisible(Result) then
Result := Screen.ActiveCustomForm.Handle;
end;
This is somewhat copied from TApplication.BringToFront.
Bringing this window to the front can be done by SetForegroundWindow:
SetForegroundWindow(GetTopWindow);
Note that Application.BringToFront might do the trick altogether, but I once experienced it did not function properly, a situation I have not been able to reproduce since though.
GetForegroundWindow() is the function you are looking for, if you know the title or have the handle of the modal window it's straightforward.
HWND GetForegroundWindow();
Retrieves a handle to the foreground window (the window with which the
user is currently working). The system assigns a slightly higher
priority to the thread that creates the foreground window than it does
to other threads.
http://msdn.microsoft.com/en-us/library/windows/desktop/ms633505%28v=vs.85%29.aspx
I used Misha’s solution and worked a little further (using NGLN’s code), to solve the problems rossmcm has seen (handlings non VCL dialogs).
The following code is running I a timer:
type
TCustomFormAccess = class(TCustomForm);
if Assigned(Screen.ActiveCustomForm) then
begin
if ((fsModal in Screen.ActiveCustomForm.FormState) and
(Application.DialogHandle <= 0)) then
begin
TopWindow := GetLastActivePopup(Application.Handle);
TopWindowForm := nil;
for i := 0 to Screen.CustomFormCount - 1 do
begin
CustomFormAccess := TCustomFormAccess(Screen.CustomForms[i]);
if CustomFormAccess.WindowHandle = TopWindow then TopWindowForm := CustomFormAccess;
end;
if Assigned(TopWindowForm) and (Screen.ActiveCustomForm.Handle <> TopWindow) then
begin
Screen.ActiveCustomForm.BringToFront;
end;
end;
end;

Removing save,cancel options while pressing previous button blackberry

Whenever i press the Back or previous button on the blackberry simulator everytime it asks whether to save cancel or discard? I don't want that to be shown at all .Please anybody help me to remove that.
ok you can do the following to remove it.
protected boolean onSavePrompt() {
return true;
}
You consume the event by returning true. Hence the prompt is not shown

Delphi messagebox appearing behind other form

I am using the code below to create a messagebox in Delphi 7. However I also have another form on screen who's FormStyle is set to fsStayOnTop and the messagebox appears behind this form.
Is there any way to force the messagebox to appear in front?
if Application.MessageBox('Amessage here','Title', +MB_APPLMODAL + MB_ICONQUESTION + MB_YESNO) = IDNO then
Call NormalizeTopMosts prior to showing the message box.
Use NormalizeTopMosts to allow a message box or dialog box that is
displayed using the Windows API functions (such as MessageBox and
MessageDlg) directly, appear on top of a topmost form. Otherwise the
topmost form remains on top, and may obscure the message box.
(Hope it's available in Delphi 7.)
Edit: Not sure about the downvote. If it hints in the direction that OP should use the native MessageBox function and set its parent HWND to the topmost window - I would agree. But maybe this is not possible for some reason.
In Windows.pas you can find more flags to MessageBox():
MB_APPLMODAL = $00000000;
MB_SYSTEMMODAL = $00001000;
MB_TASKMODAL = $00002000;
Read about them in MessageBox documentation
You can even use MB_TOPMOST flag.
Try MB_TASKMODAL flag instead of MB_APPLMODAL.

DelphiTwain how to show form setting

I'm using Delphitwain (delphitwain.sourceforge.net) to add scan functionality to my app. Everything was fine, when i click scan button on my app it will show scan mode with scanner's Properties such as Page Size, Scanning Side (canon dr-3010c) and there is a Scan button and Cancel button. If i click cancel of course all the properties back to it's value before.
How can I show this Scanner's Properties only to change properties without Scan, since i can do scan without showing properties
Twain.LoadLibrary;
Twain.LoadSourceManager;
Twain.Source[CurrentSource].Loaded := TRUE;
Twain.Source[CurrentSource].TransferMode := TTwainTransferMode(0);
Twain.Source[CurrentSource].EnableSource(True, True);
while Twain.Source[CurrentSource].Enabled do Application.ProcessMessages;
Twain.UnloadLibrary;
Twain.Source[CurrentSource].EnableSource(True, True);
The first True for ShowUI and the second True for Modal
I know it can be achieved 'cos i've seen another application that can show scanner's properties without scan, only OK and Cancel button, i've searched google all over but no luck, or maybe it just the limitation of the delphitwain component? Thanks, any suggestion appreciated
It has a boolean property in TTwainSource class named ShowUI. Using that property, you can control whether native UI of the scanner should be shown or not.
But take note that some scanners show their UI forcefully whether you set ShowUI to True or False.

Resources