Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/user-interface/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
User interface 分割窗格gui对象_User Interface_Wolfram Mathematica - Fatal编程技术网

User interface 分割窗格gui对象

User interface 分割窗格gui对象,user-interface,wolfram-mathematica,User Interface,Wolfram Mathematica,我开发gui已经有一段时间了,这需要创建Mathematica所缺少的通用控制对象(例如spinner、treeview、openerbar等)。一种是多面板,即分为两个(或更多)子面板的窗格对象,可通过鼠标设置分隔符。这是我的双窗格版本。我想听听你的意见和想法,关于如何扩展它,不仅处理2个,而且处理任意数量的子平面,以及如何优化它。目前,对于重负载的子面板,它严重滞后,不知道为什么 Options[SplitPane] = {Direction -> "Vertical", Di

我开发gui已经有一段时间了,这需要创建Mathematica所缺少的通用控制对象(例如spinner、treeview、openerbar等)。一种是多面板,即分为两个(或更多)子面板的窗格对象,可通过鼠标设置分隔符。这是我的双窗格版本。我想听听你的意见和想法,关于如何扩展它,不仅处理2个,而且处理任意数量的子平面,以及如何优化它。目前,对于重负载的子面板,它严重滞后,不知道为什么

Options[SplitPane] = {Direction -> "Vertical", 
   DividerWidth -> Automatic, Paneled -> {True, True}};
SplitPane[opts___?OptionQ] := 
  Module[{dummy}, SplitPane[Dynamic[dummy], opts]];
SplitPane[val_, opts___?OptionQ] := SplitPane[val, {"", ""}, opts];
SplitPane[val_, content_, opts___?OptionQ] := 
  SplitPane[val, content, {100, 50}, opts];
SplitPane[Dynamic[split_, arg___], {expr1_, expr2_}, {maxX_, maxY_}, 
   opts___?OptionQ] := 
  DynamicModule[{temp, dir, d, panel, coord, max, fix, val},
   {dir, d, panel} = {Direction, DividerWidth, Paneled} /. {opts} /. 
     Options[SplitPane];
   dir = dir /. {Bottom | Top | "Vertical" -> "Vertical", _ -> 
       "Horizontal"};
   d = d /. Automatic -> 2;
   split = If[NumberQ[split], split, max/2];
   val = Clip[split /. {_?NumberQ -> split, _ -> maxX/2}, {0, maxX}];
   {coord, max, fix} = 
    Switch[dir, "Vertical", {First, maxX, maxY}, 
     "Horizontal", {(max - Last[#]) &, maxY, maxX}];
   panel = (# /. {None | False -> 
          Identity, _ -> (Panel[#, ImageMargins -> 0, 
             FrameMargins -> -1] &)}) & /@ panel;

   Grid[If[dir === "Vertical",
     {{
       Dynamic[
        panel[[1]]@
         Pane[expr1, ImageSize -> {split - d, fix}, 
          ImageSizeAction -> "Scrollable", Scrollbars -> Automatic, 
          AppearanceElements -> None], TrackedSymbols :> {split}],
       Deploy@EventHandler[
         MouseAppearance[
          Pane[Null, ImageSize -> {d*2, fix}, ImageMargins -> -1, 
           FrameMargins -> -1], "FrameLRResize"],
         "MouseDown" :> (temp = 
            coord@MousePosition@"CellContentsAbsolute"; 
           split = 
            If[Abs[temp - split] <= d \[And] 0 <= temp <= max, temp, 
             split]), 
         "MouseDragged" :> (temp = 
            coord@MousePosition@"CellContentsAbsolute"; 
           split = If[0 <= temp <= max, temp, split])],
       Dynamic@
        panel[[2]]@
         Pane[expr2, ImageSizeAction -> "Scrollable", 
          Scrollbars -> Automatic, AppearanceElements -> None, 
          ImageSize -> {max - split - d, fix}]
       }},
     {
      List@
       Dynamic[panel[[1]]@
         Pane[expr1, ImageSize -> {fix, split - d}, 
          ImageSizeAction -> "Scrollable", Scrollbars -> Automatic, 
          AppearanceElements -> None], TrackedSymbols :> {split}],
      List@Deploy@EventHandler[
         MouseAppearance[
          Pane[Null, ImageSize -> {fix, d*2}, ImageMargins -> -1, 
           FrameMargins -> -1], "FrameTBResize"],
         "MouseDown" :> (temp = 
            coord@MousePosition@"CellContentsAbsolute"; 
           split = 
            If[Abs[temp - split] <= d \[And] 0 <= temp <= max, temp, 
             split]), 
         "MouseDragged" :> (temp = 
            coord@MousePosition@"CellContentsAbsolute"; 
           split = If[0 <= temp <= max, temp, split])],
      List@
       Dynamic[panel[[2]]@
         Pane[expr2, ImageSizeAction -> "Scrollable", 
          Scrollbars -> Automatic, 
          ImageSize -> {fix, max - split - d}, 
          AppearanceElements -> None], TrackedSymbols :> {split}]
      }
     ], Spacings -> {0, -.1}]
   ];
SplitPane[val_, arg___] /; NumberQ[val] := 
  Module[{x = val}, SplitPane[Dynamic[x], arg]];

pos = 300;
SplitPane[
 Dynamic[pos], {Manipulate[
   Plot[Sin[x (1 + a x)], {x, 0, 6}], {a, 0, 2}], 
  Factorial[123]}, {500, 300}]
Options[SplitPane]={Direction->“Vertical”,
DividerWidth->Automatic,Paneled->{True,True};
拆分窗格[选项Q]:=
模块[{dummy},拆分窗格[Dynamic[dummy],opts]];
SplitPane[val,opts,OptionQ]:=SplitPane[val,{,“,”},opts];
拆分窗格[值、内容、选项]:
SplitPane[val,content,{100,50},opts];
SplitPane[Dynamic[split_uu,arg_uu],{expr1_u,expr2_u},{maxX_u,maxY_u},
选项Q]:=
动态模块[{temp,dir,d,panel,coord,max,fix,val},
{dir,d,panel}={Direction,DividerWidth,Paneled}/{opts}/。
选项[拆分窗格];
dir=dir/{Bottom | Top |“Vertical”->“Vertical”,124;->
“水平”};
d=d/。自动->2;
拆分=如果[NumberQ[split],拆分,最大值/2];
val=Clip[split/{{uu?NumberQ->split,{ux->maxX/2},{0,maxX}];
{coord,max,fix}=
开关[dir,“Vertical”{First,maxX,maxY},
“水平”{(max-Last[#]&,maxY,maxX}];
面板=(#/。{None | False->
标识,->(面板[#,图像边距->0,
框架边距->-1]&)}和/@面板;
网格[如果[dir==”垂直“,
{{
动态的[
小组[[1]]@
窗格[expr1,ImageSize->{split-d,fix},
ImageSizeAction->“可滚动”,滚动条->自动,
AppearanceElements->None],跟踪符号:>{split}],
Deploy@EventHandler[
鼠标外观[
窗格[Null,ImageSize->{d*2,fix},ImageMargins->-1,
FrameMargins->-1],“FramelResize”],
“鼠标向下”:>(温度=
coord@MousePosition@“细胞含量溶质”;
拆分=
如果[Abs[temp-split]{max-split-d,fix}]
}},
{
名单@
动态[面板[[1]]@
窗格[expr1,ImageSize->{fix,split-d},
ImageSizeAction->“可滚动”,滚动条->自动,
AppearanceElements->None],跟踪符号:>{split}],
List@Deploy@事件处理程序[
鼠标外观[
窗格[Null,ImageSize->{fix,d*2},ImageMargins->-1,
框架边距->-1],“框架大小调整”],
“鼠标向下”:>(温度=
coord@MousePosition@“细胞含量溶质”;
拆分=
如果[Abs[temp-split]None],则TrackedSymbols:>{split}]
}
],间距->{0,-.1}]
];
拆分窗格[val,arg]/;编号q[val]:=
模块[{x=val},拆分窗格[Dynamic[x],arg]];
pos=300;
拆分窗格[
动态[pos],{操作[
图[Sin[x(1+ax)],{x,0,6}],{a,0,2}],
阶乘[123]},{500300}]

将多个面板通用化的关键是重构代码。在目前的形式下,虽然非常好,但它将可视化/UI原语和选项与拆分逻辑混合在一起,并且有大量重复的代码。这使得通用化很难。以下是重构版本:

ClearAll[SplitPane];
Options[SplitPane] = {
    Direction -> "Vertical", DividerWidth -> Automatic, Paneled -> True
};
SplitPane[opts___?OptionQ] :=   Module[{dummy}, SplitPane[Dynamic[dummy], opts]];
SplitPane[val_, opts___?OptionQ] := SplitPane[val, {"", ""}, opts];
SplitPane[val_, content_, opts___?OptionQ] :=
    SplitPane[val, content, {100, 50}, opts];
SplitPane[sp_List, {cont__}, {maxX_, maxY_}, opts___?OptionQ] /; 
        Length[sp] == Length[Hold[cont]] - 1 :=
  Module[{scrollablePane, dividerPane, onMouseDownCode, onMouseDraggedCode, dynPane,
      gridArg, split, divider, panel},
    With[{paneled = Paneled /. {opts} /. Options[SplitPane],len = Length[Hold[cont]]},
       Which[
          TrueQ[paneled ],
             panel = Table[True, {len}],
          MatchQ[paneled, {Repeated[(True | False), {len}]}],
             panel = paneled,
          True,
            Message[SplitPane::badopt]; Return[$Failed, Module]
       ]
    ];

    DynamicModule[{temp, dir, d, coord, max, fix, val},
      {dir, d} = {Direction, DividerWidth}/.{opts}/.Options[SplitPane];
      dir =  dir /. {
         Bottom | Top | "Vertical" -> "Vertical", _ -> "Horizontal"
      };
      d = d /. Automatic -> 2;
      val = Clip[sp /. {_?NumberQ -> sp, _ -> maxX/2}, {0, maxX}];
      {coord, max, fix} =
        Switch[dir,
          "Vertical",
             {First, maxX, maxY},
          "Horizontal",
             {(max - Last[#]) &, maxY, maxX}
        ];
      Do[split[i] = sp[[i]], {i, 1, Length[sp]}];
      split[Length[sp] + 1] = max - Total[sp] - 2*d*Length[sp];
      panel =
          (# /. {
            None | False -> Identity, 
            _ -> (Panel[#, ImageMargins -> 0,FrameMargins -> -1] &)
           }) & /@ panel;
      scrollablePane[args___] :=
          Pane[args, ImageSizeAction -> "Scrollable", 
               Scrollbars -> Automatic, AppearanceElements -> None];
      dividerPane[size : {_, _}] :=
          Pane[Null, ImageSize -> size, ImageMargins -> -1,FrameMargins -> -1];

      onMouseDownCode[n_] := 
        Module[{old},
          temp = coord@MousePosition@"CellContentsAbsolute";
          If[Abs[temp - split[n]] <= d \[And] 0 <= temp <= max,
            old = split[n];
            split[n] = temp-Sum[split[i], {i, n - 1}];
            split[n + 1] += old - split[n];       
        ]];

      onMouseDraggedCode[n_] :=
         Module[{old},
            temp = coord@MousePosition@"CellContentsAbsolute";
            If[0 <= temp <= max,
               old = split[n];
               split[n] = temp -Sum[split[i], {i, n - 1}];
               split[n + 1] += old - split[n];
            ] ;
         ];

      SetAttributes[dynPane, HoldFirst];
      dynPane[expr_, n_, size_] :=
          panel[[n]]@scrollablePane[expr, ImageSize -> size];

      divider[n_, sizediv_, resizeType_] :=
         Deploy@EventHandler[
            MouseAppearance[dividerPane[sizediv], resizeType],
           "MouseDown" :> onMouseDownCode[n],
           "MouseDragged" :> onMouseDraggedCode[n]
         ];

      SetAttributes[gridArg, HoldAll];
      gridArg[{content__}, sizediv_, resizeType_, sizeF_] :=
         Module[{myHold, len = Length[Hold[content]] },
           SetAttributes[myHold, HoldAll];
           List @@ Map[
             Dynamic,
             Apply[Hold, 
                MapThread[Compose,
                   {
                      Range[len] /. {
                        len :>               
                          Function[
                             exp, 
                             myHold[dynPane[exp, len, sizeF[len]]], 
                             HoldAll
                          ],
                        n_Integer :>
                          Function[exp,
                             myHold[dynPane[exp, n, sizeF[n]],
                                divider[n, sizediv, resizeType]
                             ], 
                          HoldAll]
                      },
                      Unevaluated /@ Unevaluated[{content}]
                    }] (* MapThread *)
               ] /. myHold[x__] :> x
           ] (* Map *)
         ]; (* Module *)
      (* Output *)
      Grid[
        If[dir === "Vertical",
           List@ gridArg[{cont}, {d*2, fix},"FrameLRResize",{split[#] - d, fix} &],
           (* else *)
           List /@ gridArg[{cont}, {fix, d*2},"FrameTBResize", {fix, split[#] - d} &]
        ],
        Spacings -> {0, -.1}]]];

SplitPane[val_, arg___] /; NumberQ[val] := 
   Module[{x = val}, SplitPane[Dynamic[x], arg]];

无法对您提到的性能问题发表评论。此外,当您开始用鼠标拖动时,实际光标位置通常与分隔符位置相差甚远。这对于您和我的版本都适用,可能需要更精确的缩放

我只想再次强调一点——只有在我进行重构之后,才有可能实现泛化,将拆分逻辑与可视化相关的东西分离。至于优化,我还认为,出于同样的原因,尝试优化这个版本要比原始版本容易得多

编辑


我有点犹豫是否要添加此注释,但必须指出的是,我上面的解决方案在工作时显示了一种被专业UI mma程序员认为是不好的做法。即,它在
模块
内部使用
模块
生成的变量
动态
内部到
模块
(尤其是上述代码中的
split
,以及各种辅助功能)。我使用它的原因是,我无法仅使用
动态模块
-生成的变量,再加上
模块
-生成的变量以前一直对我有效。但是,请参阅John Fultz在MathGroup thread中的帖子,他在帖子中指出,应该避免这种做法。

大量基于Leonid的解决方案,这是我的版本。我已经应用了一些更改,基本上是为了更容易跟踪动态大小更改,因为我只是没有将Leonid的部分代码内部化

所作的修改:

  • 删除了
    DividerWidth
    选项,现在用户无法设置它。它没有那么重要
  • 最大水平尺寸(
    maxX
    在上面的文章中)被删除,因为它现在是根据用户指定的面板宽度值计算的:
    w
  • 第一个参数(
    w
    ,主要的动态变量)明确地保存面板的宽度,而不是保存分隔器的位置。此外,它是一个列表(
    w[[n]]
    ),而不是一个函数(正如Leonid版本中的
    split[n]
  • 添加了最小化/还原按钮到分割器
  • 分隔器移动受限:分隔器只能从其左侧移动到其右侧邻接处,不能进一步移动
  • 微调分隔器宽度,
    图像边距
    帧边距
    间距
    ,以允许零尺寸窗格
有待解决的问题:

  • 当最小化/最大化divi时
    SplitPane[{300, 300}, 
     {
       Manipulate[Plot[Sin[x (1 + a x)], {x, 0, 6}], {a, 0, 2}], 
       Factorial[123], 
       CompleteGraph[5]
     }, {900, 300}]
    
    ClearAll[SplitPane];
    Options[SplitPane] = {Direction -> "Vertical", Paneled -> True};
    SplitPane[opts___?OptionQ] := 
      Module[{dummy = {200, 200}}, SplitPane[Dynamic[dummy], opts]];
    SplitPane[val_, opts___?OptionQ] := SplitPane[val, {"", ""}, opts];
    SplitPane[val_, content_, opts___?OptionQ] := 
      SplitPane[val, content, Automatic, opts];
    SplitPane[Dynamic[w_], cont_, s_, opts___?OptionQ] :=
      DynamicModule[{
        scrollPane, divPane, onMouseDownCode, onMouseDraggedCode, grid,
        dir, panel, bg, coord, mouse, icon, sizeD, sizeB,
        num, old, pos, origo, temp, max, prev, state, fix},
    
       {dir, panel} = {Direction, Paneled} /. {opts} /. Options@SplitPane;
       dir = dir /. {Bottom | Top | "Vertical" -> "Vertical", _ -> 
           "Horizontal"};
       bg = panel /. {None | False -> GrayLevel@.9, _ -> None};
       panel = 
        panel /. {None | False -> 
           None, _ -> {RGBColor[0.70588, 0.70588, 0.70588]}}; (* 
       Simulate Panel-like colors on the frame. *)
       fix = s /. {Automatic -> If[dir === "Vertical", 300, 800]};
    
       (* {coordinate function, mouse cursor, button icon, divider size, 
       button size} *)
       {coord, mouse, icon, sizeD, sizeB} = Switch[dir,
         "Vertical", {First, 
          "FrameLRResize", {"\[RightPointer]", "\[LeftPointer]"}, {5, 
           fix}, {5, 60}},
         "Horizontal", {(max - Last@#) &, 
          "FrameTBResize", {"\[DownPointer]", "\[UpPointer]"}, {fix, 
           7}, {60, 7}}
         ];
    
       SetAttributes[{scrollPane, grid}, HoldAll];
       (* Framed is required below becase otherwise the horizontal \
    version of scrollPane cannot be set to zero height. *)
       scrollPane[expr_, size_] := 
        Framed[Pane[expr, Scrollbars -> Automatic, 
          AppearanceElements -> None, ImageSizeAction -> "Scrollable", 
          ImageMargins -> 0, FrameMargins -> 0, ImageSize -> size], 
         FrameStyle -> panel, ImageMargins -> 0, FrameMargins -> 0, 
         ImageSize -> size];
       divPane[n_] :=
        Deploy@EventHandler[MouseAppearance[Framed[
            Item[Button[Dynamic@If[state[[n]], First@icon, Last@icon],
    
              If[state[[n]], prev[[n]] = w; 
               w[[n]] = max - Sum[w[[i]], {i, n - 1}]; 
               Do[w[[i]] = 0, {i, n + 1, num}]; state[[n]] = False;, 
               w = prev[[n]]; state[[n]] = True;]
              , ContentPadding -> False, ImageSize -> sizeB, 
              FrameMargins -> 0, ImageMargins -> -1, 
              Appearance -> "Palette"], Alignment -> {Center, Center}]
            , ImageSize -> sizeD, FrameStyle -> None, ImageMargins -> 0, 
            FrameMargins -> 0, Background -> bg], mouse], 
          "MouseDown" :> onMouseDownCode@n, 
          "MouseDragged" :> onMouseDraggedCode@n, PassEventsDown -> True];
       onMouseDownCode[n_] := (
         old = {w[[n]], w[[n + 1]]};
         origo = coord@MousePosition@"CellContentsAbsolute";
         );
       onMouseDraggedCode[n_] := (
         temp = coord@MousePosition@"CellContentsAbsolute" - origo;
         w[[n]] = Min[Max[0, First@old + temp], Total@old];
         w[[n + 1]] = Total@old - w[[n]];
         );
       (* Framed is required below because it gives the expression \
    margins. Otherwise, 
       if the scrollPane is set with larger than 0 FrameMargins, 
       they cannot be shrinked to zero width. *)
       grid[content_, size_] := 
        Riffle[MapThread[
          Dynamic[scrollPane[Framed[#1, FrameStyle -> None], size@#2], 
            TrackedSymbols :> {w}] &, {content, Range@Length@w}], 
         Dynamic[divPane@#, TrackedSymbols :> {w}] & /@ 
          Range@((Length@w) - 1)];
    
       Deploy@Grid[If[dir === "Vertical",
          List@grid[cont, {w[[#]], fix} &],
          List /@ grid[cont, {fix, w[[#]]} &]
          ], Spacings -> {0, -.1}, 
         ItemSize -> {{Table[0, {Length@w}]}, {Table[0, {Length@w}]}}],
    
       Initialization :> (
         (* w = width data list for all panels *)
         (* m = number of panels *)
         (* state = button states *)
         (* prev = previous state of w *)
         (* max = total width of all panels *)
         num = Length@w; state = True & /@ Range@num; 
         prev = w & /@ Range@num; max = Total@w;)
       ];
    SplitPane[val_, 
        arg___] /; (Head@val === List \[And] And @@ (NumberQ /@ val)) := 
      Module[{x = val}, SplitPane[Dynamic@x, arg]];
    
    w = {200, 50, 100, 300};
    SplitPane[
     Dynamic@w, {Manipulate[Plot[Sin[x (1 + a x)], {x, 0, 6}], {a, 0, 2}],
       Null, CompleteGraph[5], "121234"}]
    
    SplitPane[{50, 50, 50, 
      50}, {Manipulate[Plot[Sin[x (1 + a x)], {x, 0, 6}], {a, 0, 2}, 
       ContentSize -> 300], Null, CompleteGraph[5], "121234"}, 
     Direction -> "Horizontal"]
    
    xpane = {200, 300};
    ypane = {200, 50};
    SplitPane[Dynamic@xpane, {
      Manipulate[Plot[Sin[x (1 + a x)], {x, 0, 6}], {a, 0, 2}],
      Dynamic[
       SplitPane[Dynamic@ypane, {CompleteGraph[5], "status"}, Last@xpane, 
        Paneled -> False, Direction -> "Horizontal"], 
       TrackedSymbols :> {xpane}]
      }, 300, Direction -> "Vertical"]