1
$\begingroup$

I want to input a binary matrix via buttons as in the following code:

ClearAll["Global`*"];
initVariablesOut[] := Module[{r = Table[{k}, {k, 1, 4}]},
   If[Length[Flatten[row]] != 9, Print[REJECTED]; 
    row = {{}, {}, {}, {}}; Return[],];
   B = Array[0 &, {4, 9}];
   (B[[Sequence @@ #]] = -1) & /@ 
    Flatten[Outer[({#1, #2}) &, r[[#]], row[[#]]] & /@ Range[4], 2];
   Print[B // MatrixForm];
   ];
row = {{}, {}, {}, {}};
{TogglerBar[
   Dynamic[row[[1]]], {1 -> 6, 2 -> 7, 3 -> 8, 4 -> 9, 5 -> "10", 
    6 -> "J", 7 -> "Q", 8 -> "K", 9 -> "A"}],
  TogglerBar[
   Dynamic[row[[2]]], {1 -> 6, 2 -> 7, 3 -> 8, 4 -> 9, 5 -> "10", 
    6 -> "J", 7 -> "Q", 8 -> "K", 9 -> "A"}],
  TogglerBar[
   Dynamic[row[[3]]], {1 -> 6, 2 -> 7, 3 -> 8, 4 -> 9, 5 -> "10", 
    6 -> "J", 7 -> "Q", 8 -> "K", 9 -> "A"}],
  TogglerBar[
   Dynamic[row[[4]]], {1 -> 6, 2 -> 7, 3 -> 8, 4 -> 9, 5 -> "10", 
    6 -> "J", 7 -> "Q", 8 -> "K", 9 -> "A"}]} // MatrixForm
Button["run", initVariablesOut[], Method -> "Queued"]

The entries of B corresponding to the buttons which are pressed should have the value -1 and the rest should have the value 0. If not exactly 9 buttons are selected it should reset the buttons and do nothing except printing "REJECTED".

Question 1: I don't like my code, this must be possible way cleaner?!

Question 2: I'd like to delete all outputs every time I press run except my buttons (the run button and the buttons corresponding to the matrix). How would I do that? I found

NotebookDelete[Cells[EvaluationNotebook[], GeneratedCell -> True]]

but this deletes my buttons as well :(

Thanks for the help in advance :)

$\endgroup$
1
  • $\begingroup$ Welcome to Mathematica.SE! I hope you will become a regular contributor. To get started, 1) take the introductory tour now, 2) when you see good questions and answers, vote them up by clicking the gray triangles, because the credibility of the system is based on the reputation gained by users sharing their knowledge, 3) remember to accept the answer, if any, that solves your problem, by clicking the checkmark sign, and 4) give help too, by answering questions in your areas of expertise. $\endgroup$
    – bbgodfrey
    Nov 30, 2021 at 14:13

1 Answer 1

4
$\begingroup$

TBH I didn't really read the question, but here's a way to make a custom object with a constructor GUI that I think follows what you want.

First we define a validator function to make sure the data is good and a constructor to get the data into the canonical format

ClearAll[BinaryMatrix, validateMatrix, constructMatrix];
validateMatrix[vals_List] :=
  Dimensions[vals] === {3, 3} &&
   Developer`PackedArrayQ[vals] &&
   Head[vals[[1, 1]]] == Integer;
constructMatrix[vals_List] :=
 If[Not@Developer`PackedArrayQ[vals], 
  {Developer`ToPackedArray[vals], True}, 
  {vals, False}
  ]

In this case I'm forcing a 3x3 packed array of integers (so not really binary). The second return value from constructMatrix simply tells us if the object needs to be rebuilt.

Next we define a constructor that sets the Valid flag and a nice format form

b : BinaryMatrix[vals_List]?System`Private`HoldNotValidQ :=
  
  Block[{data, rebuild, isValid},
   {data, rebuild} = constructMatrix[vals];
   If[rebuild, isValid = True, isValid = validateMatrix[data]];
   If[rebuild,
     BinaryMatrix[data],
     System`Private`HoldSetValid[b]
     ] /; isValid
   ];
Format[b_BinaryMatrix?System`Private`ValidQ] :=
  Interpretation[
   BinaryMatrix[MatrixForm[b[[1]]]],
   b
   ];

We can make one of these matrices like this, then

enter image description here

Note that the mis-shapen one doesn't format because it failed to validate.

Finally, we can make our constructor GUI. In this case I'll use Checkbox to make a table of 0 and 1. The key is that we provide a BoxID so we can replace the GUI using BoxReferenceReplace once we're done. I set this up to be very modular so that it can be easily adapted for other objects.

ClearAll[initializeMatrixInputGUIData, createMatrixInputGUI,
   constructMatrixFromGUIData, overwriteGUIWithMatrix];
initializeMatrixInputGUIData[] := ConstantArray[False, {3, 3}];
createMatrixInputGUI[Dynamic[data_]] :=
  Panel@Grid@
    Table[
     With[{i = i, j = j}, Checkbox[Dynamic[data[[i, j]]]]],
     {i, 3},
     {j, 3}
     ];
constructMatrixFromGUIData[data_] := BinaryMatrix[Boole@data]
overwriteGUIWithMatrix[mat_, id_] :=
 MathLink`CallFrontEnd@
  FrontEnd`BoxReferenceReplace[
   FE`BoxReference[
    EvaluationNotebook[],
    {{id}},
    FE`SearchStart -> "StartFromBeginning"
    ],
   ToBoxes@mat
   ]
BinaryMatrix[] :=
 With[{id = CreateUUID[]},
  DynamicModule[
   {data = initializeMatrixInputGUIData[]},
   Column[{
     createMatrixInputGUI[Dynamic[data]],
     Button["Done", 
      overwriteGUIWithMatrix[constructMatrixFromGUIData[data], id]
      ]
     },
    Alignment -> Center
    ],
   BoxID -> id
   ]
  ]

This looks like enter image description here

and after pressing Done

enter image description here

I have no idea if this solves your problem, but realistically it gives you the toolset you need to get the job done.

This is also easy to work into the Dynamic[outputVar] paradigm like

BinaryMatrix[Dynamic[var_]] :=
 With[{id = CreateUUID[]},
  DynamicModule[
   {data = initializeMatrixInputGUIData[]},
   Column[{
     createMatrixInputGUI[Dynamic[data]],
     Button["Done",
      var = constructMatrixFromGUIData[data];
      overwriteGUIWithMatrix[Defer[var], id]]
     },
    Alignment -> Center
    ],
   BoxID -> id]
  ]

where now Done will replace the object with the variable you specified for the output

Or if you want to allow for initializing the object/more advanced Dynamic controls

initializeMatrixInputGUIData[BinaryMatrix[v_]?System`Private`ValidQ] := 
  Map[(# === True || # != 0) &, v, {2}];
initializeMatrixInputGUIData[l_List] :=
  Replace[constructMatrix[l],
   {
    {a_List?validateMatrix, _} :> Map[
      If[Head[#] === Integer, # != 0, TrueQ[#]] &, a, {2}
      ],
    {a_List?(Dimensions[#] === {3, 3} && MatrixQ[#, BooleanQ] &), _} :> Map[
      If[Head[#] === Integer, # != 0, TrueQ[#]] &, a, {2}
      ],
    e_ :> initializeMatrixInputGUIData[]
    }
   ];
initializeMatrixInputGUIData[e_] := initializeMatrixInputGUIData[];
BinaryMatrix[Dynamic[var_]] :=
 With[{id = CreateUUID[]},
  DynamicModule[
   {},
   var = initializeMatrixInputGUIData[var];
   Column[{
     createMatrixInputGUI[Dynamic[var]],
     Button["Done",
      var = constructMatrixFromGUIData[var];
      overwriteGUIWithMatrix[Defer[var], id]]
     },
    Alignment -> Center
    ],
   BoxID -> id]
  ]
$\endgroup$
1
  • $\begingroup$ Thanks a lot!!! $\endgroup$ Nov 30, 2021 at 22:06

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.