- Go to the Detached Dialogs docs page and copy the code under the heading "Script Code - JScript" into a new toolbar button:
function OnClick(clickData) { var Dlg = DOpus.Dlg; Dlg.window = clickData.func.sourcetab; Dlg.template = "testdlg"; Dlg.detach = true; Dlg.Show(); while (true) { var Msg = Dlg.GetMsg(); if (!Msg.result) break; DOpus.Output("Msg Event = " + Msg.event); } DOpus.Output("Return code = " + Dlg.result); }
Bug:The code doesn't work ("Invalid procedure call or argument").
- Change
Dlg.template = "testdlg";
toDlg.message = "The message.";
and it works.- Possible bugs (at least in docs): I find it strange that
DOpus.Dlg
without parentheses works.DOpus.TypeOf()
says its anobject.Dialog
, even though the docs say its a method.
- Possible bugs (at least in docs): I find it strange that
- Paste the line
DOpus.Output("after Show()");
betweenDlg.Show();
andwhile (true) {
.- Bug: This reveals that
Show()
blocks, even though its docs say:If the detach property is True, the call will return immediately
- Bug: This reveals that
Maybe it's not a bug ... and you just forgot to create the so called testdlg
template in the resources tab.
Maybe ...
You're right, with the <resources>
XML, the example from the page works: DOpus.Output("after Show()");
is called early.
My use case that prompted this pursuit was to have a detached dialog, set up just via properties. And with that, Show()
blocks, though. If this different behavior is intended, the docs should clarify that. But I don't know why that should be - both ways just define the dialog's UI.
What did you expect to happen with Dlg.template = "testdlg";
when you hadn’t defined a testdlg
template?
What could we write in the docs to clarify that?
I already corrected that (with strike-through as well as a comment)!
I wrote:
How can you confuse this with the Dlg.template = "testdlg";
thing?
But, again:
So, should Show()
rather never block?
I don’t know if it’s my eyes or my brain but I can’t see any strike-through in this thread (at least the current versions).
If the problem isn’t the template, I’m not sure which details we’re actually talking about. This thread is very unclear to me.
Let's go back to the two types of Dialogs : simple and detached.
The purpose of the detached dialog is to let you do things in the message loop, such as modifying an UI element or change specific things (variables, logic, ...) when interacting with another UI element.
It makes no sense to use a detached dialog with a dialog only set-up via properties. For that, use a simple dialog and get the results when it exists (with a blocking Show method).
Second sentence in first comment:
That Show()
blocks, because DOpus.Output("after Show()");
isn't printed, even though Show()
's docs say:
If the detach property is True, the call will return immediately
This code sets detach
to true
, still Show()
doesn't return immediately:
function OnClick(clickData) {
var Dlg = DOpus.Dlg;
Dlg.window = clickData.func.sourcetab;
Dlg.message = "The message.";
Dlg.detach = true;
Dlg.Show();
DOpus.Output("after Show()");
while (true) {
var Msg = Dlg.GetMsg();
if (!Msg.result) break;
DOpus.Output("Msg Event = " + Msg.event);
}
DOpus.Output("Return code = " + Dlg.result);
}
Before this thread I tried whether this detached-thing by any chance allowed me to show a dialog, directly continue with final script actions and return from the script while the message box is still shown. I.e., I wanted to try whether an asynchronous message box is possible, because Show()
docs only say: "You should then either...or...", leaving room for its implementation allowing me to do what I wanted.
Of course, Dialog
's implementation in the DOpus code base could, e.g., not react on the OK button click anymore when not running your own message loop after Show()
, but I didn't know anything about (and still don't). Halfway in my test, I encountered the bug and directly reported it. It's either a code base bug, or a docs bug, because Show()
doesn't tell you a difference in behavior when using a template
vs. other properties like message
only.
If you're asking yourself why I wanted to return from the script while the message box is still shown, this had to do with with the script being run from a script add-in that runs it via a Command
, and the script add-in should continue its actions and not be blocked by the dialog. The dialog was meant to be a more salient version of writing to the script log via DOpus.Output()
, but in the same way a one-and-done deal.
The problem is that you're totally twisting the way this is supposed to be used, because your use case is very specific and then come here declaring things as bugs or not working the way it should when it reality, it's not working the way you'd expect because of your kind of specific use case.
Anyway, for that specific need, what I'd do is:
- Build a new command that launches at startup (with OnStartup event)
- Embeds a basic dialog (but in detached mode) with a text box to display messages
- Register some custom message on this dialog (through
AddCustomMsg
) such asShowMyCustomDialog
,CloseMyCustomDialog
,DisplayAMessageInMyCustomDialog
, ... - Implement accordingly the message loop
- THEN in your other scripts send the custom messages (with
DOpus.SendCustomMsg
)
EDIT: About Show() blocking when you defined a detached dialog with a wrong (meaning non existent) template ... well, I don't know of many languages that are able to perform perfectly when given garabge in. You initiate poorly an object with an invalid property, do not expect things to works as if everything was fine.
This is the way
, in order to stop the 'bug hunting' madness .
Another approach I'll try is:
- Create a new command that can accept a simple raw string as a parameter (the "caller" script). This would be the
custom message
(or even more than one?) sent to the "main" script. - Another script that runs on DOpus startup with a
Dialog
set tomsgonly = true
. This script would register any custom message that could be sent by the "caller" script, and it would handle all the logic to execute whatever task you want. The code could reside in the same script or even in included scripts. - Then, from your Python script, you'd simply run the caller script with the appropriate message. The main script would receive it and execute the related command or task—no need to embed raw script command lines, use dcf files, or other goofy workarounds.
Well, Show()
's and its most directly related docs aren't enough to know that. I roughly did this:
- Look at
Show()
docs.-
Read:
If the detach property is True, the call will return immediately and the return value is meaningless.
Great, I want it to return immediately.
-
Read:
You should then either run a message loop for the “detached” dialog, or call RunDlg to run the standard loop.
- Look as
RunDlg()
docs.-
Read:
The RunDlg method won't return until the dialog has closed.
- Okay, ruled out.
-
- Think: It says "should", not "must" run a message loop. Maybe the closing OK button will still work without my own message loop.
- Look as
-
- Learn a bit more about what could be relevant for my use case by taking a look at the
detach
property's and the generalDialog
object's docs.
I'm not hunting. They simply cross my way.
You're mixing up my general voice command set implementation with the possibility to show an async message box.
Regarding the general voice command set implementation, you seem to recommend having functionality in the script add-in instead of reading it from files told to read by the Python side. I can see some benefits to that (mostly code reuse, if indeed possible, which didn't become a problem for me, though), but currently tend to see it more negatively:
- Each distinct functionality should be in a separate file. You could use modules with filenames like
script-addin-name.NameOfFunctionToldToBeCalledByPython.js
for that. But if I'm not mistaken, the hierarchy would have to be flat. Also, everything would need to reside near the script add-in implementation without the freedom of residing near the non-script-add-in code (a tree) where the .js scripts and many, many single-line DOpus commands are called. - If you'd want to gate-keep/sanitize a little and not work with
eval()
, I think you'd need to maintain a dictionary of call strings passed to the custom script add-in command and their respective JScript function names. Contrast this to myRunBareCommandFile
approach where I only need to add a .js file to the repo and mention its relative file path in a function call on the Python/Talon side. - When the end user updates the voice command set repo, they would need to reinstall the script add-in much more often instead of only when the generic
RunBareCommandFile
infrastructure changed.
Back to async message boxes:
As of now, I only had a single simple use case for an async message box that shouldn't necessitate anything from out of its small context. And the following solution that came to my mind today fits this better:
function OnClick(clickData) {
var cmd = clickData.func.command;
cmd.SetType("script");
cmd.AddLine("@script:JScript");
// Use `DOpus.Output` instead of `cmd.AddLine`, if you need
// this to better understand the code.
cmd.AddLine(" \
function OnClick(clickData) { \
/* Attention: Goofiness incoming! /s */ \
void " + function () {
DOpus.Output("inside");
var Dlg = DOpus.Dlg;
Dlg.window = clickData.func.sourcetab;
Dlg.message = "The message.";
Dlg.Show();
DOpus.Output("inner end");
}.toString() + "(); \
} \
");
cmd.RunAsync();
DOpus.Output("outer end");
}
This is what it prints for me (in the script log, not the Command Editor dialog's output display):
outer end
inside
inner end
I'd rather like to have this more straightforward, though, of course.
Exactly what I'm saying: the proper way to do things is not mixing well with your objective.
You can have one file with all the commands.
I don't want that?! Numbers of lines of only the biggest .js files are 227+121+100+67+59+55+49+43+37 == 758
. And the project is set up for growth. Spaghetti code is to be avoided.
Spaghetti code is to be avoided, but no problem with void " + function () {
Oki ...
You're now confusing multiple pairs:
- Macroperspective with microperspective
- Quick-and-dirty proof-of-concept examples with its at least slightly polished version that gets committed
Also, didn't I convey I'd like to avoid that? It's just the best solution I saw until now that doesn't demand anything from the larger context that isn't already provided by DOpus's API, especially since the demand in my code base for async message boxes is (at least currently) small.