WPFを使う-Gridを使った部品の整列

WPFでGridを使ってGUI部品をきれいに配置するための考え方。

初めに

VisualStudioのWPF GUI構築ツールでは、Grid状に部品をDrag&Dropして配置すると、右・上からのマージン指定での配置となってしまう。

この場合、部品の位置指定が座標値指定となってしまうため、例えば多言語化対応時に、ラベル内のテキストに変更があると、配置のずれが発生してしまう。

例えばラベルの右隣にボタンを配置した例で示すと、ラベルのテキストが長いものに変更された場合、下の図のようにラベルがボタンの上に重なってしまう状態になる。

 →

Gridを使った配置

ある程度部品の大きさが変わっても、自動でいい配置になるようにするためのGridの使い方について記述する。

GUI部品の配置のラフイメージの作成

部品の位置関係を把握するため、どのような部品をどこに配置するか、手書きでもいいので、書き上げる。

 部品の整列状況をイメージしてグループ化する

PowerPointの配置を使った場合、どのような部品をグループ化して整列配置をするかを考える。例えば、上の例だと、2つの左揃えと、4つの中央ぞろえでまずそろえてみる。

なお、黒点線にかかる部品が、整列配置時のグループ化した部品になる。

(リストは複数の配置線をまたぐので、別途検討)

Gridの分割数の検討

基本的に、整列配置した時の基準となるグルーピングの数で、行列数を決定する。上の例だと、2列、4行。

(リストは複数の配置線をまたぐので、別途検討)

この内容で、まず部品を配置してみると、次のようになる。ただ、行列の高さ・幅はAutoで、部品のマージンは0で配置する。

    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        
        <Label Content="ラベル" HorizontalAlignment="Left" VerticalAlignment="Top"/>
        <Label Content="ラベル" HorizontalAlignment="Left" VerticalAlignment="Top" Grid.Row="1"/>
        <Label Content="ラベル" HorizontalAlignment="Left" VerticalAlignment="Top" Grid.Row="2"/>
        <Label Content="ラベル" HorizontalAlignment="Left" VerticalAlignment="Top" Grid.Row="3"/>
        <Label Content="ラベル" HorizontalAlignment="Left" VerticalAlignment="Top" Grid.Row="1" Grid.Column="1"/>
        <ComboBox HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Text="コンボ" IsEditable="True" Grid.Row="1" Grid.Column="1"/>
        <Button Content="ボタン" HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Grid.Row="3" Grid.Column="1"/>
        <RadioButton Content="ラジオ" HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Grid.Row="2" Grid.Column="1"/>
        <TextBox HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Text="テキスト" Grid.Column="1"/>
        <TextBox HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Text="テキスト" Grid.Column="1"/>
        <TextBox HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Text="テキスト" Grid.Row="1" Grid.Column="1"/>
    </Grid>

2列目の部品は、まだ配置が完了していないため、まとまって表示されている。次に、この部品を配置する。

この部品は、横に並べるため、2列目にGridを配置し、その子供として再配置する。

子供のGrid

1,2行目は、それぞれ2部品、3部品を配置するので、2列、3列の2つのGridを使い配置する。この場合、0行目,1列目にあったテキストと、1行目,1列目にあったコンボボックス、ラベル、テキストを、Gridに押し込む。

        <Grid Grid.Column="1">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="Auto"/>
            </Grid.ColumnDefinitions>
            <TextBox HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Text="テキスト" Grid.Column="0"/>
            <TextBox HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Text="テキスト" Grid.Column="1"/>
        </Grid>
        <Grid Grid.Row="1" Grid.Column="1">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="Auto"/>
            </Grid.ColumnDefinitions>
            <Label Content="ラベル" HorizontalAlignment="Left" VerticalAlignment="Top" Grid.Column="1"/>
            <ComboBox HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Text="コンボ" IsEditable="True" Grid.Column="0"/>
            <TextBox HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Text="テキスト" Grid.Column="2"/>
        </Grid>

これで、リストを除く部品については、グリッドに乗せた配置ができた。

後のは、Margin, Alignmentを使い、部品の位置を微調整する。

Gridに乗らなさそうな部品の配置

サンプルでは、リストが2つの行にまたがって配置している。このような部品は、RowSpanやColumnSpanを使い、いくつの行/列にまたがって配置するか示す属性を使う。

今回のケースでは、リストの右で区切り、親のGridを3列4行にしたい。しかし、ここで区切ると、すでに子供のGridで配置したものがそのままでは2列目に押し込められてしまうので、この部分も、2,3列目にまたがるように再調整する。

    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Grid Grid.Column="1" Grid.ColumnSpan="2">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="Auto"/>
            </Grid.ColumnDefinitions>
            <TextBox HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Text="テキスト" Grid.Column="0"/>
            <TextBox HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Text="テキスト" Grid.Column="1"/>
        </Grid>
        <Grid Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="2">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="Auto"/>
            </Grid.ColumnDefinitions>
            <Label Content="ラベル" HorizontalAlignment="Left" VerticalAlignment="Top" Grid.Column="1"/>
            <ComboBox HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Text="コンボ" IsEditable="True" Grid.Column="0"/>
            <TextBox HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Text="テキスト" Grid.Column="2"/>
        </Grid>
        <Label Content="ラベル" HorizontalAlignment="Left" VerticalAlignment="Top"/>
        <Label Content="ラベル" HorizontalAlignment="Left" VerticalAlignment="Top" Grid.Row="1"/>
        <Label Content="ラベル" HorizontalAlignment="Left" VerticalAlignment="Top" Grid.Row="2"/>
        <Label Content="ラベル" HorizontalAlignment="Left" VerticalAlignment="Top" Grid.Row="3"/>
        <Button Content="ボタン" HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Grid.Row="3" Grid.Column="1"/>
        <RadioButton Content="ラジオ" HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Grid.Row="2" Grid.Column="1"/>
        <ListBox Grid.Row="2" Grid.Column="2" Grid.RowSpan="2">
            <ListBoxItem Content="List"/>
            <ListBoxItem Content="List"/>
            <ListBoxItem Content="List"/>
            <ListBoxItem Content="List"/>
        </ListBox>
    </Grid>

これで、当初想定した位置関係で部品が配置できた。

微調整

後は、部品の幅/高さ/マージン/整列位置の調整などを行うことで、綺麗な配置のGUIが出来上がると思う。

一応の完成形。

Listが2行の場合、3,4行目の高さが大きくなってしまうため、親Gridをもう1行増やし、リストは3行にまたぐ設定とした。

まとめ

Gridを再帰的に配置し、必要であれば、複数列/行をまたぐ設定をすることで、部品をきれいに整列配置することができた。

コメント

タイトルとURLをコピーしました