0
$\begingroup$

I'm trying to make a wrapper for ListPicker that delays updating the list unless Ctrl or Shift is released. The aim is to allow nested ListPickers to work without grinding to a halt.

I've made some headway using an answer by @István Zachar to a question on detecting key release: Detecting KeyUp events

The ListPicker2 code snippet below generates a new list that updates when I release either Ctrl or Shift, just as I would like.

However, I'd like it to to update x only when Ctrl or Shift are released, not just the new list (that way ListPicker2 can become a direct replacement for ListPicker in my scripts).

I'm missing something, hopefully it is a simple! How do I make x in the script below only update this way?

ListPicker2[tempX_, list_] := DynamicModule[{return, shiftDown},   
      Print[ListPicker[Dynamic[tempX], list]];
      shiftDown = False;
      Dynamic[If[
                  MemberQ[CurrentValue["ModifierKeys"], ("Shift" | "Control")],
                  (shiftDown = True;),
                  If[shiftDown, 
                     (shiftDown = False; return := tempX)];
                ];
              Dynamic[return, TrackedSymbols :> {return}]
             ]
       ]

x =.;
ListPicker2[x, {a, b, c, d}]
Dynamic[x]
$\endgroup$
2
  • $\begingroup$ Ctrl and Shift provide additional functionality for ListPicker, you can select multiple elements. That is why I'm not sure what do you want at the end. What if someone did not press any additional key at all? p.s. Print is not the best approach, now I've got ListPicker in message window ;) $\endgroup$
    – Kuba
    Dec 16, 2014 at 20:25
  • $\begingroup$ Thanks Kuba, yes I want to be able to select multiple elements using shift and control, but I don't want the list it returns to update until I release. The upshot is that if I select only one element without pressing shift or control, then I can just tap ctrl to activate that selection. I have a script where selected elements in a ListPicker each open another ListPicker, so I want' to select the elements first then once selected, let the other ListPickers open, otherwise it gets very slow between each selection. (I haven't figured out how to do this without Print either, I need to work on it!) $\endgroup$
    – DrBubbles
    Dec 16, 2014 at 21:13

1 Answer 1

1
$\begingroup$

I'm sorry, I don't have time to address all issues in your code. But if you take a closer look at docs for things I'm using I'm sure you can understand what was wrong and why it works now.


SetAttributes[ListPicker3, HoldFirst]

ListPicker3[var_, list_] := DynamicModule[{temp = var, keycap},

  DynamicWrapper[
       ListPicker[Dynamic[temp], list],
       If[ 
          MemberQ[CurrentValue["ModifierKeys"], ("Shift" | "Control")], 
          (keycap = True;), 
          If[keycap, (keycap = False; var = temp)];];
       ]
  ]
$\endgroup$
3
  • $\begingroup$ This is a great solution Kuba, I think I can learn a lot from it. It illustrates how to properly avoid the Print kludge I used, by making ListPicker the part displayed by the DynamicWrapper (which is ironically a new construct for me considering the aim of the question!). Thank you. $\endgroup$
    – DrBubbles
    Dec 16, 2014 at 21:39
  • 1
    $\begingroup$ I added If[(CurrentValue["ModifierKeys"] == {} \[And] Length[Dynamic[temp][[1]]] == 1), var = temp]; inside the DynamicWrapper immediately after the main If statement. This causes it to update when only a single item is selected too. $\endgroup$
    – DrBubbles
    Dec 17, 2014 at 6:56
  • $\begingroup$ @DrBubbles Great :) I'm glad to see you were able to adjust it for your needs. Good luck! $\endgroup$
    – Kuba
    Dec 17, 2014 at 7:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.