プログラムを書こう!

実務や自作アプリ開発で習得した役に立つソフトウェア技術情報を発信するブログ

C++/CLIで別スレッドからUIを操作する。

この記事は2018年08月18日に投稿しました。

f:id:paveway:20190914064630j:plain

目次

  1. はじめに
  2. 別スレッドからUIを操作する
  3. おわりに

プロフェッショナル VISUAL C++ 2010 (MSDNプログラミングシリーズ)

プロフェッショナル VISUAL C++ 2010 (MSDNプログラミングシリーズ)

1. はじめに

こんにちは、iOSのエディタアプリPWEditorの開発者の二俣です。

今回は業務で使用しているC++/CLIの話です。
前回 paveway.hatenablog.com を説明しました。
別スレッドで処理した結果を、例えばラベルに表示したりする状況はよくあると思います。
しかしラベルなどのUIコントロールはUIスレッドで処理する必要があります。
そのため別スレッドからUIを操作する方法が必要になります。

目次へ

2. 別スレッドからUIを操作する

別スレッドからUIを操作する方法は以下の通りです。

  1. 別スレッドからUIを操作するメソッドのデリゲートを定義します。
  2. 1で定義したデリゲートと同じ戻り値、引数のUIを操作するメソッドを用意します。
  3. 別スレッドで行うメソッドでは、InvokeRequiredプロパティによりこのメソッドを呼び出したスレッドが別スレッドかチェックします。
  4. 3のメソッドが別スレッドから呼び出された場合、Invokeメソッドにより、デリゲート経由でこのメソッドを実行します。
ref class SampleForm
{
private:
    // 1. 別スレッドからUIを操作するメソッドのデリゲートを定義します。
    //    戻り値、引数有りのメソッド例です。
    delegate bool SetTextDelegate(String^ text);
    //    戻り値、引数無しのメソッド例です。
    delegate void SetDisableDelegate();

    /// 別スレッドを開始します。
    void StartExecThread()
    {
        ThreadStart^ start = gcnew ThreadStart(this, &SampleForm::SetTextThread);
        Thread^ thread = gcnew Thread(start);
        thread->Start();
    }

    /// 別スレッドで行うメソッドです。
    void SetTextThread()
    {
        String^ result = <何らかの処理>;
        
        // 戻り値有り、引数有りのUIを操作するメソッドを呼び出します。
        bool result = SetText(result);
        
        // 戻り値無し、引数無しのUIを操作するメソッドを呼び出します。
        SetDisable();
    }

    /// 2. UIを操作するメソッドです。
    ///    戻り値有り、引数有りのメソッド例です。
    ///    引数の文字列をラベルに設定します。
    bool SetText(String^ result)
    {
        bool result = false;

        // 3. このメソッドを呼び出したスレッドが別スレッドかチェックします。
        //    別スレッドからこのメソッドを呼び出した場合
        if (this->InvokeRequired)
        {
            // 4. Invokeメソッドにより、デリゲート経由でこのメソッドを実行します。
            SetTextDelegate^ method = gcnew SetTextDelegate(this, &SampleForm::SetText);
            // 引数パラメータを設定します。
            // 引数が複数ある場合、複数設定します。
            array<Object^>^ args = { result };
            // Invokeメソッドを戻り値有り、引数パラメータ有りで実行します。
            // 戻り値はObject型のため、適切な型にキャストします。
            result = (bool)this->Invoke(method, args);
        }
        
        // UIスレッドからこのメソッドを呼び出した場合
        else
        {
            result = this->ResultLabel->Text(result);
        }
        
        return result;
    }
    
    // 2. UIを操作するメソッドです。
    //    戻り値、引数無しのメソッド例です。
    //    ボタンを無効にします。
    void SetDisable()
    {
        // 3. このメソッドを呼び出したスレッドが別スレッドかチェックします。
        //    別スレッドからこのメソッドを呼び出した場合
        if (this->InvokeRequired)
        {
            // 4. Invokeメソッドにより、デリゲート経由でこのメソッドを実行します。
            SetDisable^ method = gcnew SetDisableDelegate(this, &SampleForm::SetDisable);
            // Invokeメソッドを戻り値無し、引数パラメータ無しで実行します、
            this->Invoke(method);
        }
        else
        {
            this->ExecButton->Enable = false;
        }
    }
};

API Reference
InvokeRequiredプロパティ
Invokeメソッド

目次へ

3. おわりに

AndroidやiOSでも、UI操作はUIスレッドで行う必要があります。
そのためAndroid、iOSでも同じような仕組みはありますが、ほかに比べてC++/CLIの場合、

  • デリゲートの定義
  • 別スレッドかのチェック
  • Invokeメソッドによる実行

と少し煩雑です。

高単価案件が最短二日で決まる!【ポテパンフリーランス】

紹介している一部の記事のコードはGitlabで公開しています。
興味のある方は覗いてみてください。

目次へ


私が勤務しているニューラルでは、主に組み込み系ソフトの開発を行っております。
弊社製品のハイブリッドOS Bi-OSは高い技術力を評価されており、特に制御系や通信系を得意としています。
私自身はiOSモバイルアプリウィンドウズアプリを得意としております。
ソフトウェア開発に関して相談などございましたら、お気軽にご連絡ください。

また一緒に働きたい技術者の方も随時募集中です。
興味がありましたらご連絡ください。

EMAIL : info-nr@newral.co.jp / m-futamata@newral.co.jp
TEL : 042-523-3663
FAX : 042-540-1688

目次へ