Is there a property that tells if a form is deactivated by other form `ShowModal` procedure? - forms

Is there a property that tells if a form is deactivated by other form ShowModal procedure ?
EDIT :
My program has a tray icon that brings to front the main form when it's clicked. I want to disable this when another window is shown in modal state. Because not doing so the main form (which is disable) will cover the modal form and completly block my program.

This behaviour is to be expected. When a modal form is shown, the other forms are disabled. You don't need to disable anything at all, the framework already handles it all for you. The beep is sounding because you are attempting to interact with a disabled form.
If you want to be notified when your window has been disabled, for any reason, not just because a modal form has been shown, listen to the WM_ENABLE message. To test whether or not your main form has been disabled. Do that by calling the IsWindowEnabled Win32 function.
Having said that I feel that it is likely you've not diagnosed the issue correctly. It sounds like you might be suffering from window ownership problems, which are common in Delphi 6. Or perhaps you are attempting to restore the application incorrectly from your notification icon code. Use Application.BringToFront for that.
The VCL's handling of modal dialogs seem very mixed up. When you show a system provided modal dialog, e.g. MessageBox, windows are disabled whether or not they are visible. However, the VCL only disables visible windows when ShowModal is called. What's more, you cannot use Enabled to test whether or not the window is disabled, you must use the IsWindowEnabled Win32 function.

You can test Application.ModalLevel at any point in time to find out if there's a modal form. E.g.:
if Application.ModalLevel = 0 then
MainForm.Visible := True;
Note that non-TCustomForm descendants will not set modal level, API dialogs like a file open dialog or MessageBox for instance. If there's a possibility of such a thing, you might surround code that runs those dialogs with ModalStarted and ModalFinished.
It doesn't seem necessary in your case, but if you somehow need to be notified that a form/dialog is going modal, you can attach a handler to Application.OnModalBegin and Application.OnModalEnd events. You can use an TApplicationEvents component for that.

Related

Issue with setting AutomationElement value

I have an issue with setting value of AutomationElement by using method ValuePattern.SetValue().
Everything works just fine until some dialog appears. When the dialog appears the code execution got stuck. No exception is thrown. After the dialog is confirmed, the code exection continues. Bellow is a sample of the code:
BasePattern basePattern = null;
ValuePattern valuePattern = null;
AutomationElement elementA = Window.GetElement(SearchCriteria.ByText(propertyName));
object patternObjectA = null;
elementA.TryGetCurrentPattern(ValuePattern.Pattern, out patternObjectA);
basePattern = (BasePattern)patternObjectA;
valuePattern = (ValuePattern)patternObjectA;
valuePattern.SetValue(optionToSet);
// Window.GetElement() is a method from TestStack.White framework
// The code execution got stuck on the last line until the dialog is confirmed
Is there any other way to set AutomationElement value?
Is somehow possible to avoid of getting stuck by dialog?
I'll by grateful for any help.
Thanks advance.
It could be that this dialog is not supporting UI Automation correctly or that you simply target the wrong element.
To verify that you may use Inspect.exe from Microsoft or similiar tools.
If it works, check if you really target the correct component with your code again.
If it does not work and:
if you are able to change the application
you can change the so called AutomationPeer of the UI component - here is a link for more infos
Or simply use another UI component that supports UI Automation correctly.
if you are not able to change the application, and also do not need to run in background, parallel, etc.. you might just focus the component (call setFocus() onto the AutomationElement, or expand it (via IsExpandCollapsePatternAvailable or simulated MouseClick onto the components coordinates)) and then use the SendKeys.SendWait("test") method.
EDIT: There is one more thing you should have a look at, and I wonder why I didn't mentioned it in the first place: Register to UI Automation Events
For example you could register a callback for the Structure change event type, and check if the dialog you talk about appeared.
If so --> click the confirmed button of the dialog.
Probably you will have to synchronize your execution, so that every further action in the UI Automation script waits until the registered callback got executed and the confirmed button got clicked.

Detect if there is a modal form showing

Is there some method of detecting if there is a modal form showing in my VB6 application.
I want to show another form modally if there is a modal form showing and modeless if there isn't a modal form showing.
I know I can do some error handling to detect this and show modally if the error occurs:
Public Sub ShowFormModeless(frm As Form, Optional ownerForm As Form = Nothing)
On Error GoTo ShowModal
Call frm.Show(, ownerForm)
Exit Sub
ShowModal:
Call frm.Show(vbModal, ownerForm)
End Sub
But I want to be able to detect this without the error being thrown.
Try checking App.NonModalAllowed. Note that this property does not detect modal forms being shown from other (than current module) projects, i.e. if your application consists of main executable and several ActiveX dlls each of these projects will have a separate App object and Forms collection.
The result is that if a dll is showing a modal form only its own project's App.NonModalAllowed is flagged. So once again, App.NonModalAllowed is not a process-wide flag but a per project one.
Note that this flag tracks VB6 only forms, so if you are using API dialogs (open/save file, color picker, etc) this does not enter VB6 runtime's modal loop, so nothing is flagged.
If you application is a single exe then using this flag works as expected.

Addon SDK way to make a dialog

What is the proper way to use the SDK to make a dialog (which is not anchored to the add-on bar, etc. but shows centered on screen)? It doesn't seem like there is any API for this important capability. I do see windows/utils has open but I have two problems with that:
The dialog opening seems to require "chrome" privs to get it to be centered on the screen (and I'd be expectant of add-on reviewers complaining of chrome privs, and even if not, I'd like to try to stick to the SDK way).
While I can get the DOM window reference of the new window/utils' open() dialog, I'm not sure how to attach a content script so I can respond to user interaction in a way that prompts (and can respond to) privileged behavior ala postMessage or port.emit (without again, directly working with chrome privs).
Ok, this answer should have been pretty obvious for anyone with a little experience with the SDK. I realized I can just use a panel. In my defense, the name "panel" is not as clear as "dialog" in conjuring up this idea, and I am so used to using panels with widgets, that it hadn't occurred to me that I could use it independently!
Edit
Unfortunately, as per Bug 595040, these dialogs are not persistent, meaning if the panel loses focus, the "dialog" is gone... So panel looks like it is not a suitable candidate after all... :(
Edit 2
I've since moved on and have gotten things working mostly to my satisfaction with sdk/window/utils and openDialog on whose returned window I add a load listener and then call tabs.activeTab.on('ready', and then set tabs.activeTab.url to my add-on local HTML file so the ready event will get a tab to which I can attach a worker. There is still the problem with chrome privs I suppose, but at least the main communications are using SDK processes.
Update to Edit 2:
Code sample provided by request:
var data = require('sdk/self').data,
tabs = require('sdk/tabs');
var win = require('sdk/window/utils').openDialog({
// No "url" supplied here in this case as we add it below (in order to have a ready listener in place before load which can give us access to the tab worker)
// For more, see https://developer.mozilla.org/en-US/docs/Web/API/window.open#Position_and_size_features
features: Object.keys({
chrome: true, // Needed for centerscreen per docs
centerscreen: true, // Doesn't seem to be working for some reason (even though it does work when calling via XPCOM)
resizable: true,
scrollbars: true
}).join() + ',width=850,height=650',
name: "My window name"
// parent:
// args:
});
win.addEventListener('load', function () {
tabs.activeTab.on('ready', function (tab) {
var worker = tab.attach({
contentScriptFile: ....
// ...
});
// Use worker.port.on, worker.port.emit, etc...
});
tabs.activeTab.url = data.url('myHTMLFile.html');
});
if the panel loses focus, the "dialog" is gone...
It doesn't get destroyed, just hides, right? If so, depending on why it's getting hidden, you can just call show() on it again.
You'd want to make sure it's not being hidden for a good reason before calling show again. If there's a specific situation in which it's losing focus where you don't want it to, create a listener for that situation, then call if (!panel.isShown) panel.show();
For example, if it's losing focus because a user clicks outside the box, then that's probably the expected behaviour and nothing should be done. If it's losing focus when the browser/tab loses focus, just register a tab.on('activate', aboveFunction)
Simply adding ",screenX=0,screenY=0" (or any values, the zeroes seem to be meaningless) to the features screen seems to fix centerscreen.

setting menu item property from another form in oracle

good day, i am working on a system using Oracle Forms Builder. i have 3 forms, MAIN, LOGIN, and REGISTER and a menu form named MENU_MAIN, it is attached to the 3 forms, the first form that will be shown is the MAIN, i made some buttons disabled because the user cant access unless they are registered and login, now my problem is, after they login they are prompted again to the MAIN and i need the button that is disabled to be enabled, how can i do that? am i gonna put the code on the LOGIN? thanks for the response
"am i gonna put the code on the LOGIN?"
Well I honestly don't know which other part of your application can know that a user has logged in, so yes, the LOGIN screen has to handle this.
What should it do? It should set a value in a global variable. Your MAIN screen should interrogate the global variable, probably in a When-New-Form-Instance trigger, and set the buttons' properties accordingly.

Prevent main form from appearing when showing another form

I am trying to bring my secondary form to the Foreground, however when I do
MyForm.Show; // It may be hidden, therefore show it first
SetForegroundWindow(MyForm.Handle);
my Main Form appears aswell. The only way I can prevent that is to do MainForm.Hide; but I got to avoid that.
The idea is to have my secondary form appear on top of another application, without my Main Form having to do so as well.
If you consider to make another application for this functionality, then you may also consider the following compromise: minimize the MainForm to the taskbar (rather than hiding it) to prevent it popping up when activating another form.
If so, then try this answer. It does add an extra icon to your taskbar for the secondary form, but I guess that'll be no problem since a different application would either. However, if the MainForm is nót minimized but obfuscated by other windows, activating the secondary form wíll also popup the MainForm, just like you are experiencing now.
And for the completeness of this answer's sake, but not by any means meant as advice: this answer describes a (somewhat experimental) construction to make fully independent windows. The little time I tested that solution, it seemed to work, but be prepared not counting any longer on the full/default functionality of the VCL.
Try settings the state of the form to fsAlwaysOnTop.