Itsukaraの日記

最新IT技術を勉強・実践中。最近はDeep Learningに注力。

PowerShellでGUI: 部品配置はGridとテキスト編集が良い

2つ前の記事「PowerShellでGUI: 可変個数RadioButton実現方法(別法) - Itsukaraの日記」で、PowerShellGUIVisual Studioで作成する方法を書きました。ただ、GUIを実現するWPFの勉強が不足していたので、GUI画面上にGUI部品を適当に貼り付けていました。そのため、部品の位置等を表す数字「Margin="68,119,0,0"」が沢山あり、後で調整するのが大変そうと感じました。

f:id:Itsukara:20170326015246p:plain

その後、WPFを少し調べたところ、GRIDを使うことにより部品をテーブル状に整然と並べることが出来ると分かりました。下記のような感じです。
f:id:Itsukara:20170326020148p:plain

ただ、GRIDへのGUI部品配置をGUIでやると、微調整が結構面倒なので、1~2個部品を並べたら、あとは、XAMLテキストをコピー・ペーストし適切な修正を行うのが良いです。

また、GUIで部品を配置すると、HeightやMarginなどに、色々な数字が入りますが、これらが部品ごとに入っていると、後で纏めて変えるのが面倒なので、それらの数字はできるだけ削っておいた方が良いです。順序としては、上記のコピー・ペーストの前にやっておく必要がありますね。

なお、Syleを使うと、後でTextBoxのHeightを纏めて30にしたりといったことが、簡単にできます。Styleは、<Window.Resources>というタグ内に記述します。

結果として、次のようなプログラムになりました。表示内容は、依然とあまり変わりませんが、無駄な数字がなくなって、すっきりしています。その分、後で変更するのが楽(なはず)です。

  • プログラム例-
$ErrorActionPreference = "stop"
Set-PSDebug -Strict
Add-Type -AssemblyName PresentationFramework

[xml]$xaml = @'
<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <Style TargetType="TextBox">
            <Setter Property="Height" Value="30"/>
        </Style>
        <Style TargetType="Button">
            <Setter Property="Height" Value="30"/>
        </Style>
        <Style TargetType="TextBlock">
            <Setter Property="Foreground" Value="Blue"/>
        </Style>
    </Window.Resources>

    <Grid Margin="10,10,10,10">
        <Grid.RowDefinitions>
            <RowDefinition Height="30"/>
            <RowDefinition Height="30"/>
            <RowDefinition Height="30"/>
            <RowDefinition Height="30"/>
            <RowDefinition Height="30"/>
            <RowDefinition Height="10"/>
            <RowDefinition Height="30"/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="50"/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>

        <Label x:Name="label01" Content="名前" Margin="0" VerticalAlignment="Center" HorizontalAlignment="Right"/>
        <TextBox x:Name="textName" Margin="0" TextWrapping="Wrap" VerticalAlignment="Center" Grid.Column="1"/>

        <Label x:Name="label02" Content="ふりがな" Margin="0" VerticalAlignment="Center" HorizontalAlignment="Right" Grid.Row="1"/>
        <TextBox x:Name="textFurigana" Margin="0" TextWrapping="Wrap" VerticalAlignment="Center" Grid.Column="1" Grid.Row="1" />

        <Label x:Name="label03" Content="性別" Margin="0" VerticalAlignment="Top" HorizontalAlignment="Right" Grid.Row="2"/>
        <StackPanel x:Name="stackGender" HorizontalAlignment="Left" Margin="0" VerticalAlignment="Center" Orientation="Horizontal" Grid.Column="1" Grid.Row="2" Width="120">
            <RadioButton x:Name="radioButtonMale" Content="Male" VerticalAlignment="Center" HorizontalAlignment="Left" Margin="0,0,10,0"/>
            <RadioButton x:Name="radioButtonFemale" Content="Female" VerticalAlignment="Center" HorizontalAlignment="Left" Margin="0"/>
        </StackPanel>

        <Label x:Name="label04" Content="国籍" Margin="0" VerticalAlignment="Center" HorizontalAlignment="Right" Grid.Row="3"/>
        <ComboBox x:Name="comboBoxCountry" HorizontalAlignment="Left" Margin="0" VerticalAlignment="Center" Grid.Row="3" Grid.Column="1" Width="100"/>
        
        <Label x:Name="label05" Content="年齢" Margin="0" VerticalAlignment="Center" HorizontalAlignment="Right" Grid.Row="4"/>
        <TextBox x:Name="textAge" Margin="0" TextWrapping="Wrap" VerticalAlignment="Center" Grid.Column="1" Grid.Row="4" Width="50" HorizontalAlignment="Left" />

        <Button x:Name="buttonRegist" Content="登録" Margin="0" VerticalAlignment="Center" Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="6" />
        <TextBlock x:Name="textBlock" HorizontalAlignment="Left" Margin="0" TextWrapping="Wrap" VerticalAlignment="Top" Grid.ColumnSpan="2" Grid.Row="7"/>

    </Grid>
</Window>
'@

$reader = New-Object System.Xml.XmlNodeReader $xaml
$frm = [System.Windows.Markup.XamlReader]::Load($reader)

$countries = "U.S.A China Japan Germany France England Russia".split(" ")
$comboBoxCountry = $frm.FindName("comboBoxCountry")
foreach ($country in $countries) {
  [void]$comboBoxCountry.Items.Add($country)
}

$textName = $frm.FindName("textName")
$comboBoxCountry = $frm.FindName("comboBoxCountry")
$textFurigana = $frm.FindName("textFurigana")
$stackGender = $frm.FindName("stackGender")
$textAge = $frm.FindName("textAge")
$textBlock = $frm.FindName("textBlock")

function getChecked($parent) {
    $checked = ""
    foreach ($child in $parent.Children) {
        if ($child.isChecked) {
            $checked += $child.Content
        }
    }
    return $checked
}

function regist {
    $name = $textName.Text
    $furigata = $textFurigana.Text
    $gender = getChecked $stackGender
    $country = $comboBoxCountry.SelectedValue
    $age = $textAge.Text

    $msg = ""
    $msg += "名前:" + $name + "`n" 
    $msg += "ふりがな:" + $furigata + "`n" 
    $msg += "性別:" + $gender + "`n" 
    $msg += "国籍:" + $country + "`n" 
    $msg += "年齢:" + $age + "`n" 

    $textBlock.Text = $msg
}

$buttonRegist =  $frm.FindName("buttonRegist")
$buttonRegist.Add_Click({regist})

$result = $frm.ShowDialog()
  • 画面表示例

f:id:Itsukara:20170326021108p:plain