TesseractOCRアプリケーションの作成について<手順2.WPFアプリケーションの画面作成方法(1.BaseWindow作成)>


 <Windowの構成について>

 F1~F12キーをファンクションキーとして利用する構成に慣れているので、なんとか慣れ親しんだ操作法で作れるように構成を考える。

 業務用のソフトを作る期間が長かったので、ついついこの構成で作るように考えてしまう。

 

<イメージ>

 Webブラウザみたいな感じでWindowの中にFrameコントロールを設置し、各画面の設計はPageクラスを派生したCsPageで行う。

 WindowコントロールはコンストラクタでFrameに渡されたCsPageクラスをNavigateメソッドで呼び出す。

 ※Windowがブラウザ、PageがWebページのイメージ

<手順1 必要な継承コントロールの作成>

 WPF(.Net Core)のプロジェクトを作成し、プロジェクトを右クリックして「新しいフォルダー」を作成し、「controls」と名前を付ける。次にこのフォルダを右クリックして「クラス」を追加していく。


 クラスの名前はそれぞれ「CsButton」「CsCheckBox」「CsComboBox」「CsDataGrid」「CsPage」「CsTextBox」「CsWindow」で合計7つ。

 次にそれぞれのクラスファイルに対して継承元のクラスを記述していく。

           例)修正前の「CsCheckBox」

修正後の「CsCheckBox」
 ※CsWindowだけはUsingが「using System.Windows;」

 内容の記述については今後の手順で必要に応じて行っていく。

<手順2 BaseWindowの作成>

 次にPageを表示する大本となるWindowを作成する。


 作成した「controls」フォルダを右クリックして、Windowを追加し、名前を「BaseWindow」とする。Xamlを修正します。
           修正前)
           修正後)
エラーが出まくって見づらいですが、「xmlns:controls="clr-namespace:TesseractOCR.controls"」を追加し、「<Window」の部分を「<controls:CsWindow」に修正しています。
次にBaseWindow.csの内容を修正します。
修正前)

修正後)

リビルドをするとXAML側のエラーが消えます。
次にXAMLを修正していきます。

BaseWindow.xaml

<controls:CsWindow x:Class="TesseractOCR.controls.BaseWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:TesseractOCR.controls"
        xmlns:controls="clr-namespace:TesseractOCR.controls"
        mc:Ignorable="d"
        Title="BaseWindow" Height="840" Width="990">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="5"/>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="5"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="5"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="5"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="60"/>
            <RowDefinition Height="5"/>
        </Grid.RowDefinitions>

        <DockPanel Grid.Row="3" Grid.Column="1" >
            <Frame HorizontalAlignment="Stretch"  VerticalAlignment="Stretch" Name="MainFrame" Focusable="False" ></Frame>
        </DockPanel>

        <Grid Name="gdFunctionKey" Grid.Column="1" Grid.Row="4">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="12"/>
                <ColumnDefinition Width="70"/>
                <ColumnDefinition Width="5"/>
                <ColumnDefinition Width="70"/>
                <ColumnDefinition Width="5"/>
                <ColumnDefinition Width="70"/>
                <ColumnDefinition Width="5"/>
                <ColumnDefinition Width="70"/>
                <ColumnDefinition Width="5"/>
                <ColumnDefinition Width="20"/>
                <ColumnDefinition Width="5"/>
                <ColumnDefinition Width="70"/>
                <ColumnDefinition Width="5"/>
                <ColumnDefinition Width="70"/>
                <ColumnDefinition Width="5"/>
                <ColumnDefinition Width="70"/>
                <ColumnDefinition Width="5"/>
                <ColumnDefinition Width="70"/>
                <ColumnDefinition Width="5"/>
                <ColumnDefinition Width="20"/>
                <ColumnDefinition Width="5"/>
                <ColumnDefinition Width="70"/>
                <ColumnDefinition Width="5"/>
                <ColumnDefinition Width="70"/>
                <ColumnDefinition Width="5"/>
                <ColumnDefinition Width="70"/>
                <ColumnDefinition Width="5"/>
                <ColumnDefinition Width="70"/>
                <ColumnDefinition Width="10"/>
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="5"/>
                <RowDefinition Height="13"/>
                <RowDefinition Height="2"/>
                <RowDefinition Height="30"/>
                <RowDefinition Height="5"/>
            </Grid.RowDefinitions>

            <TextBlock Grid.Column="1" Grid.Row="1" Text="F1" HorizontalAlignment="Center"></TextBlock>
            <controls:CsButton x:Name="btnF1" Content="" Grid.Column="1" Grid.Row="3"  />
            <TextBlock Grid.Column="3" Grid.Row="1" Text="F2" HorizontalAlignment="Center"></TextBlock>
            <controls:CsButton  x:Name="btnF2" Content="" Grid.Column="3" Grid.Row="3"  />
            <TextBlock Grid.Column="5" Grid.Row="1" Text="F3" HorizontalAlignment="Center"></TextBlock>
            <controls:CsButton x:Name="btnF3" Content="" Grid.Column="5" Grid.Row="3"  />
            <TextBlock Grid.Column="7" Grid.Row="1" Text="F4" HorizontalAlignment="Center"></TextBlock>
            <controls:CsButton  x:Name="btnF4" Content="" Grid.Column="7" Grid.Row="3"  />

            <TextBlock Grid.Column="11" Grid.Row="1" Text="F5" HorizontalAlignment="Center"></TextBlock>
            <controls:CsButton  x:Name="btnF5" Content="" Grid.Column="11" Grid.Row="3"  />
            <TextBlock Grid.Column="13" Grid.Row="1" Text="F6" HorizontalAlignment="Center"></TextBlock>
            <controls:CsButton  x:Name="btnF6" Content="" Grid.Column="13" Grid.Row="3"  />
            <TextBlock Grid.Column="15" Grid.Row="1" Text="F7" HorizontalAlignment="Center"></TextBlock>
            <controls:CsButton  x:Name="btnF7" Content="" Grid.Column="15" Grid.Row="3"  />
            <TextBlock Grid.Column="17" Grid.Row="1" Text="F8" HorizontalAlignment="Center"></TextBlock>
            <controls:CsButton  x:Name="btnF8" Content="" Grid.Column="17" Grid.Row="3"  />

            <TextBlock Grid.Column="21" Grid.Row="1" Text="F9" HorizontalAlignment="Center"></TextBlock>
            <controls:CsButton  x:Name="btnF9" Content="" Grid.Column="21" Grid.Row="3"  />
            <TextBlock Grid.Column="23" Grid.Row="1" Text="F10" HorizontalAlignment="Center"></TextBlock>
            <controls:CsButton  x:Name="btnF10" Content="" Grid.Column="23" Grid.Row="3"  />
            <TextBlock Grid.Column="25" Grid.Row="1" Text="F11" HorizontalAlignment="Center"></TextBlock>
            <controls:CsButton  x:Name="btnF11" Content="" Grid.Column="25" Grid.Row="3"  />
            <TextBlock Grid.Column="27" Grid.Row="1" Text="F12" HorizontalAlignment="Center"></TextBlock>
            <controls:CsButton  x:Name="btnF12" Content="" Grid.Column="27" Grid.Row="3"  />
        </Grid>
    </Grid>
</controls:CsWindow>

上記のXAMLを張り付け、次はBaseWindow.csへ移動します。

/// <summary>
    /// BaseWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class BaseWindow : CsWindow
    {
        public CsPage ThisPage { get; set; }

        public BaseWindow()
        {
            InitializeComponent();
        }

        public BaseWindow(CsPage showpage)
        {
            InitializeComponent();

            this.ThisPage = showpage;
            this.ThisPage.BaseWindow = this;
            //this.ThisPage.ButtonF01 = this.btnF1;
            this.Title = this.ThisPage.Title;

            // 画面表示後にボタンのタイトルなどが設定されるのに違和感がある。コンストラクタで文字タイトルを指定すればよいが、そこまでのものとは思えないのでVisibilityで対応
            this.gdFunctionKey.Visibility = Visibility.Collapsed;

            this.MainFrame.Navigate(this.ThisPage);
            SetEvents();

        }

        public void SetEvents()
        {
            this.MainFrame.LoadCompleted += MainFrame_LoadCompleted;
            this.PreviewKeyDown += BaseWindow_PreviewKeyDown;
        }

        private void MainFrame_LoadCompleted(object sender, System.Windows.Navigation.NavigationEventArgs e)
        {
            // 読込完了後に隠していたボタンを表示する
            this.gdFunctionKey.Visibility = Visibility.Visible;
        }

        /// <summary>
        /// ファンクションキー押下時のイベントを定義
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void BaseWindow_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            switch (e.Key)
            {
                case Key.F1:
                    this.btnF1.PerformClick();
                    break;
                case Key.F2:
                    this.btnF2.PerformClick();
                    break;
                case Key.F3:
                    this.btnF3.PerformClick();
                    break;
                case Key.F4:
                    this.btnF4.PerformClick();
                    break;
                case Key.F5:
                    this.btnF5.PerformClick();
                    break;
                case Key.F6:
                    this.btnF6.PerformClick();
                    break;
                case Key.F7:
                    this.btnF7.PerformClick();
                    break;
                case Key.F8:
                    this.btnF8.PerformClick();
                    break;
                case Key.F9:
                    this.btnF9.PerformClick();
                    break;
                case Key.F10:
                    this.btnF10.PerformClick();
                    break;
                case Key.System:
                    if (e.SystemKey == Key.F10) { this.btnF10.PerformClick(); }
                    break;
                case Key.F11:
                    this.btnF11.PerformClick();
                    break;
                case Key.F12:
                    this.btnF12.PerformClick();
                    break;
                default:
                    break;
            }

        }

    }

上記のソースを張り付けると「this.ThisPage.BaseWindow = this;」と「this.btnF1.PerformClick();」でエラーが発生します。


CsPage.csへ移動し、「public BaseWindow BaseWindow { get; set; }」を追加します。

 CsButton.csへ移動し、「using System.Windows.Automation.Peers;」「using System.Windows.Automation.Provider;」を追加し、下記のソースを追加します。


        /// <summary>

        /// Clickイベントを発生させる

        /// サンプル:https://blog.xin9le.net/entry/2013/10/27/195614

        /// </summary>

        public void PerformClick()

        {

            /// バインドしているコントロールに変更通知を送る必要があるのでフォーカスを移動

            this.Focus();

            var provider = new ButtonAutomationPeer(this) as IInvokeProvider;

            provider.Invoke();

        }


 ここまででBaseWIndowの作成は完了です。試しに呼び出してみます。
 



真っ白な画面でボタンだけが配置されています。ちょっとわかりにくいのでBaseWindow.xamlのFrameコントロール(Name=MainFrame)のBackgroundを変更します。

この黄緑色の部分がFrameコントロールになります。黄緑色の部分にCsPageクラスを表示するようにすることで、全画面で統一の見た目にそろえることができます。共通処理を入れたい場合にもBaseWindowで対応すれば何とかなることも多い、と思います。たぶん。

長くなってしまったので次回はCsPageを作成するところからスタートします。
また、スタイルの共通化もWPFの機能を使えば簡単にできるのでそちらも併せて紹介していきます。




0 件のコメント:

コメントを投稿

PowerShellでEdgeを自動化(インストール不要。参考:郵便追跡サービス自動操作)

1.経緯について  RPAのソフトをインストールできないので、これまでVBSでCreateObjectでブラウザの自動操作をすることがたまにあった。 ※いざというときの手札として持っているだけで安心感が段違い  見た目上IEがインストールされていなくても、CreateObject...