Тяжело опираясь на решение Леонида, вот моя версия.Я применил несколько изменений, в основном, чтобы было легче отслеживать динамические изменения размера, и потому что мне просто не удалось усвоить часть кода Леонида.
Изменения сделаны:
- Удалено *Опция 1006 *, теперь она не может быть установлена пользователем.Это не так важно.
- Максимальный горизонтальный размер (
maxX
в постах выше) был отброшен, поскольку теперь он рассчитывается на основе заданных пользователем значений ширины панели: w
. - Первый аргумент (
w
, основная динамическая переменная) явно сохраняет ширину панелей вместо сохранения позиций делителя.Кроме того, он был создан как список (w[[n]]
) вместо функции (как split[n]
было в версии Леонида). - Добавлены кнопки минимизации / восстановления в разделители.
- Ограниченоперемещение разделителя: разделители можно перемещать только слева направо, их дальнейшее перемещение невозможно.
- Точно настроенная ширина разделителя,
ImageMargins
, FrameMargins
, Spacings
, чтобы разрешить панели нулевого размера.
Проблемы, которые еще предстоит решить:
- При минимизации / максимизации делителей они должны перекрывать левый / правый.Стек разделителей LIFO решит проблему установки максимального значения разделителя, а затем попытается изменить другие разделители с помощью их кнопок.Это может вызвать некоторые проблемы, поскольку они возвращаются к предыдущим состояниям.Проблема со стековыми делителями состоит в том, что это не может быть решено в Grid, или может быть решено только с помощью специально настроенных отрицательных интервалов.Я думаю, что это не стоит иметь дело.
- Незначительные проблемы с выравниванием при сжатии панели до нулевой ширины / высоты.С этим я могу жить.
</p>
<pre><code>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"]

Я хотел бы услышать ваши идеи / комментарии по этому решению.