Imagine that you have a PopupMenu's
list that requires a lot of scrolling through the selections. Is there a way to create a control that will only display a subsection of the complete list?
-
$\begingroup$ How closely related is that: Autocomplete InputField? $\endgroup$– KubaCommented Dec 20, 2015 at 4:34
-
1$\begingroup$ @Kuba closely related. In this present case the usage requirement was minimise the choices in a large popup but the autocomplete input field looks like an alternative solution to the same, or similar, problem. The reason why the solution you have linked is not useful to me is that is inserts a column of menu choices into your interface whereas a popup is overlayed on top. Therefore the popup does not disrupt your interface design layout. It would be nice if the popup could automatically open when you type in the input field $\endgroup$– Mike HoneychurchCommented Dec 20, 2015 at 4:57
-
$\begingroup$ @kuba please see my edit $\endgroup$– Mike HoneychurchCommented Dec 20, 2015 at 5:05
-
$\begingroup$ I've seen, thanks for clarification. :) $\endgroup$– KubaCommented Dec 20, 2015 at 5:19
2 Answers
I have finished a project where widgets like this have been useful so I thought I would share. By combining InputField and PopupMenu a searchable popup selection table can be created.
searchPopup[Dynamic[selection_], list_List] :=
DynamicModule[{x = ""},
Grid[{{
InputField[Dynamic[x], String,
Appearance -> "Frameless",
ContinuousAction -> True,
FieldHint -> "Search",
FieldSize -> 10],
Spacer[5],
Dynamic[
PopupMenu[Dynamic[selection,(selection = #; x = #) &],
Cases[list,
z_String /; StringMatchQ[z, x ~~ ___, IgnoreCase -> True]],
Null,
Opener[True, Appearance -> Small]],
TrackedSymbols :> {x}]
}},
Alignment -> {{Right, Left}, Center},
Background -> White,
Frame -> True,
FrameStyle -> GrayLevel[0.8]]
]
list = {"Ajax", "admixes", "Acrux", "Alex", "affix", "admixtures",
"Alexei", "affixed", "admixing", "ambidextrously", "admixed",
"admix", "affixing", "ambidextrous", "Alexandrians", "Alexandria",
"Anaxagoras", "Alexandrian", "annexation", "Alexandra",
"admixture", "Alexis", "Alexanders", "annex", "affixes",
"ambidexterity", "Alexander"};
selection = "";
searchPopup[Dynamic[selection], list]
Edit
To address @kuba's comment by way of example in the GIF we have a toy interface. Normally you would not want your interface elements moving around all over the place. Therefore using popup menu is a good way to achieve this search menu objective.
-
$\begingroup$ This
Popup
code is indeed very useful. I have aManipulate
which has twoPopupMenu
s with a very long list. But I am having trouble incorporating yoursearchPopup[Dynamic[selection], list]
into theManipulate
. Could you guide me in using it? $\endgroup$ Commented Nov 25, 2021 at 23:10
Based on undocumented FrontEnd`AttachCell
:
And Experimental`Autocomplete
but this can be replaced with Mike's approach.
Need to work on style, automatic scrolling and some edge cases, but already works quite well. Feedback appreciated.
Column[{
searchPopup2[Dynamic[selection], list],
Graphics@Disk[]
}]
Code
searchPopup2[Dynamic[var_], list_] :=
DynamicModule[{thisBox, currentList = {}, autocompleteF,
attachedCell, dynamicFunction, whatToDo, lastLength, cPos = 1,
itemWrapper, attachTo, dropMenu, menu},
EventHandler[
InputField[Dynamic[First@List@var, dynamicFunction], String,
FieldHint -> "Search",
ContinuousAction ->
True], {"MouseClicked" :> (If[ Length@currentList > 0, attachedCell = attachTo[thisBox, menu[currentList]]]),
"DownArrowKeyDown" :> (cPos =
Mod[cPos + 1, Length@currentList, 1]),
"UpArrowKeyDown" :> (cPos =
Mod[cPos - 1, Length@currentList, 1]), "ReturnKeyDown" :> (
lastLength = Length@currentList;
currentList = autocompleteF[var];
If[Length[currentList] > 0, var = currentList[[cPos]];
FinishDynamic[]]; dropMenu[])}, PassEventsDown -> True],
SynchronousInitialization -> False,
Initialization :> (thisBox = EvaluationBox[];
autocompleteF = Autocomplete[list];
currentList = autocompleteF@var;
dynamicFunction = (var = #;
lastLength = Length@currentList;
currentList = autocompleteF[var];
whatToDo[]) &;
whatToDo[] :=
Which[lastLength != 0 && Length[currentList] == 0, dropMenu[],
Or[lastLength == 0 && Length[currentList] > 0,
And[lastLength != 0 && Length[currentList] != 0,
Not@MatchQ[attachedCell, _CellObject]]],
attachedCell = attachTo[thisBox, menu[currentList]]];
attachTo[parentbox_, what_] :=
MathLink`CallFrontEnd[
FrontEnd`AttachCell[parentbox,
ToBoxes[ExpressionCell[what, StripOnInput -> True,
Background -> White, CellFrameColor -> [email protected],
CellFrameMargins -> 0, CellFrame -> 2]], {Automatic, {Left,
Bottom}}, {Left, Top},
"ClosingActions" -> {"ParentChanged", "EvaluatorQuit",
"OutsideMouseClick"}]];
SetAttributes[menu, HoldFirst];
menu[currentList_] :=
EventHandler[
Pane[Dynamic[
Column[MapIndexed[itemWrapper, currentList], Spacings -> 0],
TrackedSymbols :> {currentList}], {200, {All, 300}},
AppearanceElements -> None, Scrollbars -> {False, True}],
"MouseExited" :> (dropMenu[];)];
itemWrapper[item_, {pos_}] :=
MouseAppearance[#, "LinkHand"] &@
EventHandler[
Framed[item, ImageSize -> {Full, Automatic},
FrameStyle -> None,
Background ->
Dynamic[If[pos == cPos, CurrentValue@"PanelBackground",
White]]], {"MouseClicked" :> (pos == cPos;
var = item;
dropMenu[];
lastLength = Length@currentList;
currentList = autocompleteF[var];),
"MouseEntered" :> (cPos = pos)}, PassEventsDown -> True];
dropMenu[] := (
If[MatchQ[attachedCell, _CellObject],
NotebookDelete[attachedCell];
attachedCell =.
])
)]
-
$\begingroup$ I did not know about
FrontEnd`AttachCell
. That could be useful. Did you learn about it by spelunking something? Do you know of anyway to have a branched pulldown or popup menu. For example, instead of using the second argument of dynamic to populate a menu in another popup could the second menu appear next to the first menu and be populated based on the selection in the first menu? We see this on web pages. If you know how to do this i can ask this as a question and you can post the answer. $\endgroup$ Commented Dec 20, 2015 at 5:48 -
$\begingroup$ @MikeHoneychurch could you link where I can take a look at such functionality? I will answer when take a closer look. All I know about
AttachCell
is posted in the topic I've linked on top. p.s. have to go now, it's quite late(early) :P Will be in touch. $\endgroup$– KubaCommented Dec 20, 2015 at 5:51 -
$\begingroup$ I am finishing now too. I'll se if I can find a pull down menu that shows the functionality. $\endgroup$ Commented Dec 20, 2015 at 5:54
-
$\begingroup$ very nice, but I think there is a typo which made my mathematica complain: there is a double ';;' after
EvaluationBox[];;
in theInitialization
which makes Mathematica complain and the widget not work. $\endgroup$ Commented Dec 20, 2015 at 10:23 -