My primary objective is to build a file chooser that aides a user in selecting files into one of two categories. Files can be individually selected, or based on the clicking of a specific checkbox, all files listed above it will be selected, or de-selected.
Consider Code Snippet 1: (this code almost accomplishes what I need)
celdatafiles = {"GSM15432", "GSM98765", "GSM34521", "GSM65912", Style["Select All", Bold, Red], Style["Unselect All", Bold, Red]};(* arbitrary test data *) expsym = ConstantArray[False, Length[celdatafiles]]; contsym = ConstantArray[False, Length[celdatafiles]]; expcheckbox = Table[With[{i = i}, Checkbox[Dynamic[expsym[[i]]]]], {i, 1, Length[expsym]}]; contcheckbox = Table[With[{i = i}, Checkbox[Dynamic[contsym[[i]]]]], {i, 1, Length[contsym]}]; celoptions = MapThread[List, {celdatafiles, expcheckbox, contcheckbox}]; (* BEGIN CODE to add control over Select All and Unselect All \ functionality *) Dynamic[Which[ expsym[[-2]] == True \[And] expsym[[-1]] == False, (expsym[[1 ;; (Length[expsym] - 2)]] = ConstantArray[True, (Length[expsym] - 2)]; expsym[[-2]] = False), expsym[[-2]] == False \[And] expsym[[-1]] == True, (expsym[[1 ;; (Length[expsym] - 2)]] = ConstantArray[False, (Length[expsym] - 2)]; expsym[[-1]] = False)]](* do NOT use semicolon at end of statement, because it \ affects display updating *) (* control code for Select All and UnSelect All functionality \ *)Dynamic[ Which[contsym[[-2]] == True \[And] contsym[[-1]] == False, (contsym[[1 ;; (Length[contsym] - 2)]] = ConstantArray[True, (Length[contsym] - 2)]; contsym[[-2]] = False), contsym[[-2]] == False \[And] contsym[[-1]] == True, (contsym[[1 ;; (Length[contsym] - 2)]] = ConstantArray[False, (Length[contsym] - 2)]; contsym[[-1]] = False)]] expchips = Dynamic[Pick[celdatafiles, expsym, True]];(* grab experimental chips that were selected *) contchips = Dynamic[Pick[celdatafiles, contsym, True]];(* grab control chips that were selected *) analysisfiles = TableForm[celoptions, TableAlignments -> Center, TableHeadings -> {None, Map[Style[#, Bold, Blue] &, {"File Name", "Experimental?", "Control?"}]}];(* formatting for gui element where user chooses \ cel files to be analyzed *) (* DialogInput is used because it blocks the kernel from moving \ forward until the dialog is closed *) DialogInput[{analysisfiles, Button["I'm finished selecting files", DialogReturn[]]}, WindowTitle -> "Choose the CEL files you want to analyze", WindowSize -> {400, 400}, WindowElements -> "VerticalScrollBar"] Comments and questions about Code Snippet 1 above:
Notice how the custom control allows multiple files to be chosen by clicking the "Select All" checkbox under a category, and also if files are already chosen, the control allows multiple files to be unchosen by clicking the "Deselect All" checkbox. This is the behavior that I want.
Notice how execution of Code Snippet 1 always produces the "Null", "Null" output in the notebook. I believe this is because the Dynamic statements controlling the "SelectAll" and "Deselect All" behavior do not have a semicolon after them. If I use a semicolon, the Dynamic statements are suppressed and the "Select All"/"Deselect All" functionality does not work anymore.
Q1. How can I maintain the desired behavior without producing the "Null", "Null" output?
- Because I am using the code above inside a custom palette, I really would like to place Code Snippet 1 inside DynamicModule. Unfortunately, this completely destroys the "Select All" and "Unselect All" behavior that I really need to preserve.
Consider what happens when you place code snippet 1 inside a DynamicModule
Code Snippet 2: (desired functionality of code snippet 1 destroyed)
celdatafiles = {"GSM15432", "GSM98765", "GSM34521", "GSM65912", Style["Select All", Bold, Red], Style["Unselect All", Bold, Red]};(* arbitrary test data *) celChooser[celdatafiles_] := DynamicModule[{expsym, contsym, expcheckbox, contcheckbox, celoptions, expchips, contchips, analysisfiles}, expsym = ConstantArray[False, Length[celdatafiles]]; contsym = ConstantArray[False, Length[celdatafiles]]; expcheckbox = Table[With[{i = i}, Checkbox[Dynamic[expsym[[i]]]]], {i, 1, Length[expsym]}]; contcheckbox = Table[With[{i = i}, Checkbox[Dynamic[contsym[[i]]]]], {i, 1, Length[contsym]}]; celoptions = MapThread[List, {celdatafiles, expcheckbox, contcheckbox}]; (* BEGIN CODE to add control over Select All and Unselect All \ functionality *) Dynamic[ Which[expsym[[-2]] == True \[And] expsym[[-1]] == False, (expsym[[1 ;; (Length[expsym] - 2)]] = ConstantArray[True, (Length[expsym] - 2)]; expsym[[-2]] = False), expsym[[-2]] == False \[And] expsym[[-1]] == True, (expsym[[1 ;; (Length[expsym] - 2)]] = ConstantArray[False, (Length[expsym] - 2)]; expsym[[-1]] = False)]](* do NOT use semicolon at end of statement, because it affects display updating *) (* control code for Select All and UnSelect All functionality *) Dynamic[Which[ contsym[[-2]] == True \[And] contsym[[-1]] == False, (contsym[[1 ;; (Length[contsym] - 2)]] = ConstantArray[True, (Length[contsym] - 2)]; contsym[[-2]] = False), contsym[[-2]] == False \[And] contsym[[-1]] == True, (contsym[[1 ;; (Length[contsym] - 2)]] = ConstantArray[False, (Length[contsym] - 2)]; contsym[[-1]] = False)]] expchips = Dynamic[Pick[celdatafiles, expsym, True]];(* grab experimental chips that were selected *) contchips = Dynamic[Pick[celdatafiles, contsym, True]];(* grab control chips that were selected *) analysisfiles = TableForm[celoptions, TableAlignments -> Center, TableHeadings -> {None, Map[Style[#, Bold, Blue] &, {"File Name", "Experimental?", "Control?"}]}];(* formatting for gui element where user chooses cel files to be \ analyzed *) (* DialogInput is used because it blocks the kernel from moving \ forward until the dialog is closed *) DialogInput[{analysisfiles, Button["I'm finished selecting files", DialogReturn[]]}, WindowTitle -> "Choose the CEL files you want to analyze", WindowSize -> {400, 400}, WindowElements -> "VerticalScrollBar"]] celChooser[celdatafiles] Comments and questions about Code Snippet 2:
- If you run code snippet 2, you notice the following things:
A. The "Select All" and "Unselect All" functionality no longer works.
Q2. Why does placing this code inside DynamicModule break the behavior I need?
Q3. I feel like I'm wrestling with Mathematica (and I'm not winning!), so is there an alternative approach I should be trying to get the "Select All"/"Unselect All" functionality to work properly inside DynamicModule.
B. Code snippet 2 produces a Tag Times error, which I believe is also do to the Dynamic[Which .....] statement not having a semicolon after it.
In conclusion, how can I maintain the behavior I am after while inside a DynamicModule? Thanks!