
この間作ったToggleSwitchのレイアウトが面倒だったので、StackPanelを作りました。
元々、dockプロパティを持つPanelはありました。 PanelでもdockプロパティでTOPとかLEFTを設定してコントロールを追加していけば 今回追加したStackPanelのような挙動をさせることはできましたが、 同じ方向に一列に子コントロールを配置することに特化させています。 スタックって機能を限定させることで使いやすくなるものですよね。
WinFormsのOrientation列挙子にはOrientation.VERTICALとOrientation.HORIZONTALしかありませんが、 DFLではこれを拡張してOrientation.VERTICAL_INVERSEとOrientation.HORIZONTAL_INVERSEを追加したので、 逆順に並べることができます。
パディングとマージン
これまではdockPadding()がScrollableControlクラスに定義されていたので、 Controlクラス一般ではパディングが設定できませんでした。 今回の改修でパディングの機能をControlクラスに移動したので、 すべてのCoontrolでパディングが設定できるようになりました。
また、ControlクラスにdockMargin()を追加して、 マージンを設定することも可能になりました。
パディングとマージンの考え方は、WinFormsと同じです。
パディング
パディングは、親コントロールに設定するものであり、子コントロールの外側の隙間です。 子コントロールが自動レイアウトされるときに、親コントロールのパディング設定しだいで、 子コントロールのlocationやsizeが調整されます。
マージン
マージンは、コントロールが自動レイアウトされるとき、 隣のコントロールとの間に設けられる隙間です。 同じ親を持つ子コントロール同士の隙間と考えられます。
サンプルコード
import dfl; class MainForm : Form { private StackPanel _sidePanel; private StackPanel _headerPanel; private StackPanel _contentPanel; this() { this.text = "StackPanel example"; this.size = Size(500, 500); // // サイドパネルを作る // _sidePanel = new StackPanel; _sidePanel.orientation = Orientation.VERTICAL; // 上から下に追加 // _sidePanel.orientation = Orientation.VERTICAL_INVERSE; // 下から上に追加 // _sidePanel.orientation = Orientation.HORIZONTAL; // 左から右に追加 // _sidePanel.orientation = Orientation.HORIZONTAL_INVERSE; // 右から左に追加 _sidePanel.width = 150; // 横幅を固定 // _sidePanel.height = 150; _sidePanel.dock = DockStyle.LEFT; // 左サイドパネルにする _sidePanel.backColor = SystemColors.controlLight; _sidePanel.parent = this; _sidePanel.dockPadding.all = 10; // クライアントエリア全方向の端から10ピクセルのパディングを設定 for (size_t i; i < 5; ++i) { Button b = new Button; b.text = ["Settings", "Name", "Address", "Tel", "Email"][i]; b.height = 50; // ボタンの高さを固定 b.dockMargin.bottom = 10; // 次のボタンとのマージンを10ピクセルに設定 // b.dockMargin.right = 10; _sidePanel.add(b); // スタックパネルに追加 if (i == 0) // 1つ目のボタンの下に境界線(セパレータ)を追加 { Separator s = new Separator; s.dockMargin.bottom = 10; // 次のボタンとのマージンを10ピクセルに設定 // s.dockMargin.right = 10; _sidePanel.add(s); // スタックパネルに追加 } } // // ヘッダーパネルとコンテンツパネルを作る。 // _headerPanel = new StackPanel; _headerPanel.dock = DockStyle.TOP; // 上方向にドッキングさせる _headerPanel.dockMargin.all = 10; // クライアントエリアの残りの部分の全方向に10ピクセルのパディングを設定 _headerPanel.paint ~= (Control c, PaintEventArgs e) { // オーナードロー Graphics g = e.graphics; Rect rect = c.displayRectangle; g.drawRectangle(new Pen(SystemColors.controlDarkDark), rect); rect.inflate(-10, -10); g.drawText("TOP docking area", new Font("MS Gothic", 20f), Color.black, rect); }; _headerPanel.resizeRedraw = true; // ウィンドウサイズが変わったときに自動再描画するように設定 // _headerPanel.width = 200; _headerPanel.height = 100; // ヘッダーパネルの高さを固定 _headerPanel.parent = this; _contentPanel = new StackPanel; _contentPanel.dock = DockStyle.FILL; // クライアントエリアの残りの大きさにパネルの大きさを合わせる _contentPanel.dockMargin.all = 10; // クライアントエリアの残りの部分の全方向に10ピクセルのパディングを設定 _contentPanel.paint ~= (Control c, PaintEventArgs e) { // オーナードロー Graphics g = e.graphics; Rect rect = c.displayRectangle; g.drawRectangle(new Pen(SystemColors.controlDarkDark), rect); rect.inflate(-10, -10); g.drawText("FILL docking area", new Font("MS Gothic", 20f), Color.black, rect); }; _contentPanel.resizeRedraw = true; // ウィンドウサイズが変わったときに自動再描画するように設定 _contentPanel.parent = this; } } void main(string[] args) { Application.enableVisualStyles(); import dfl.internal.dpiaware; SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); Application.run(new MainForm()); }