「Qtの基礎 - CUIソフトウェア」の版間の差分

提供:MochiuWiki : SUSE, EC, PCB
ナビゲーションに移動 検索に移動
(文字列「__FORCETOC__」を「{{#seo: |title={{PAGENAME}} : Exploring Electronics and SUSE Linux | MochiuWiki |keywords=MochiuWiki,Mochiu,Wiki,Mochiu Wiki,Electric Circuit,Electric,pcb,Mathematics,AVR,TI,STMicro,AVR,ATmega,MSP430,STM,Arduino,Xilinx,FPGA,Verilog,HDL,PinePhone,Pine Phone,Raspberry,Raspberry Pi,C,C++,C#,Qt,Qml,MFC,Shell,Bash,Zsh,Fish,SUSE,SLE,Suse Enterprise,Suse Linux,openSUSE,open SUSE,Leap,Linux,uCLnux,Podman,電気回路,電子回路,基板,プリント基板 |description={{PAGENAME}} - 電子回路とSUSE Linuxに関する情報 | This pag…)
 
(同じ利用者による、間の3版が非表示)
3行目: 3行目:
ただし、CUIは[閉じる]ボタンのように終了する機能が無いため、ソフトウェアから適当なタイミングで閉じるようにしなければならない。<br>
ただし、CUIは[閉じる]ボタンのように終了する機能が無いため、ソフトウェアから適当なタイミングで閉じるようにしなければならない。<br>
<br>
<br>
ここでは、Qtにおける基本的なCUIソフトウェアの開発手順を記載する。<br>
CUIソフトウェアの開発において、重要なことは以下に示す3つである。<br>
* <code>QCoreApplication::exit</code>メソッドを実行する場合、CUIソフトウェアを終了させることができる。<br>ただし、<code>QCoreApplication::exit</code>を実行するタイミングは、イベントループが実行されている時のみである。
*: <br>
* <code>QTimer::singleShot</code>からランナークラスを実行する。
*: <br>
* ランナークラスにメイン処理を記述して、任意の地点で<code>QCoreApplication::exit</code>メソッドを実行する。
<br><br>
<br><br>


== CUIソフトウェアの開発手順 ==
== CUIソフトウェアの開発手順 ==
例えば、以下のようなCUIソフトウェアのソースコードを記述したとする。<br>
例えば、以下に示すようなコンソールアプリケーションがあるとする。<br>
<br>
<br>
以下のソースコードにおいて、CUIソフトウェアは、永遠に終了しないプログラムになってしまう。<br>
このコンソールアプリケーションは、<code>QCoreApplication</code>クラスの<code>exec</code>メソッドによりアプリケーションは待機状態となり、<br>
なぜなら、<code>QCoreApplication</code>クラスの<code>exec</code>メソッドは、<code>exit</code>メソッドが呼ばれるまでループし続けるからである。<br>
<code>exit</code>メソッドを呼ぶまで待機を続ける。<br>
  <syntaxhighlight lang="c++">
  <syntaxhighlight lang="c++">
  int main(int argc, char * argv[])
  int main(int argc, char * argv[])
17行目: 22行目:
   
   
     int count = 1000;
     int count = 1000;
     while(--count)
     while(--count) {
    {
       printf("Count = %d\n", count);
       printf("Count = %d\n", count);
     }
     }
26行目: 30行目:
  </syntaxhighlight>
  </syntaxhighlight>
<br>
<br>
これを解決するには、主の処理が終了する時、任意の地点で<code>exit</code>関数を呼び出すランナークラスを作成すればよい。<br>
この待機状態が不要の場合は、アプリケーションを終了する時に任意の地点で<code>exit</code>メソッドを呼ぶランナークラスを作成すればよい。<br>
<br>
<br>
例えば、以下のようなCUIRunnerクラスを定義する。<br>
例えば、以下に示すようなRunnerクラスを定義する。<br>
そして、CUIRunnerクラスのrunスロット内にメイン処理を記述して、処理を終了する時に<code>QCoreApplication</code>クラスの<code>exit</code>メソッドを呼び出せばよい。<br>
そして、Runnerクラスのrunスロット内にアプリケーションのメイン処理を記述して、処理を終了する時に<code>QCoreApplication</code>クラスの<code>exit</code>メソッドを呼び出す。<br>
  <syntaxhighlight lang="c++">
  <syntaxhighlight lang="c++">
  // CUIRunner.h
  // Runner.h
   
   
  #ifndef CUIRUNNER_H
  #ifndef RUNNER_H
  #define CUIRUNNER_H
  #define RUNNER_H
   
   
  #include <QObject>
  #include <QObject>
   
   
  class CUIRunner : public QObject
  class Runner : public QObject
  {
  {
     Q_OBJECT
     Q_OBJECT
   
   
  public slots:
  public slots:
     void run();  // runスロットメソッド内部でメイン処理を実行する
     void run();  // runスロットメソッドにアプリケーションのメイン処理を記述する
  };
  };
   
   
  #endif // CUIRUNNER_H
  #endif // RUNNER_H
  </syntaxhighlight>
  </syntaxhighlight>
<br>
<br>
  <syntaxhighlight lang="c++">
  <syntaxhighlight lang="c++">
  // runメソッドの定義
  // Runner.cppファイル
  #include <QCoreApplication>
  #include <QCoreApplication>
  #include <CUIRunner.h>
  #include <Runner.h>
   
   
  void CUIRunner::run()
  void Runner::run()
  {
  {
     // メイン処理
     // アプリケーションのメイン処理
     // ...略
     // ...略
   
   
     QCoreApplication::exit(0);  // 閉じる(ループから抜ける)
     QCoreApplication::exit(0);  // アプリケーションを終了する
  }
  }
  </syntaxhighlight>
  </syntaxhighlight>
<br>
<br>
ここで重要なことは、<code>QTimer</code>クラスの<code>singleShot</code>メソッドのタイムアウト時間を0に設定していることである。<br>
重要なことは、<code>QTimer</code>クラスの<code>singleShot</code>メソッドのタイムアウト時間を<code>0</code>に設定することである。<br>
このように記述することにより、ウインドウシステムの全てのイベント(描画処理等)が処理された後に、runメソッドで定義した処理が実行される。<br>
これは、アプリケーションの全てのイベント (描画処理等) が処理された後に、runメソッドで定義した処理が実行される。<br>
  <syntaxhighlight lang="c++">
  <syntaxhighlight lang="c++">
  #include <QCoreApplication>
  #include <QCoreApplication>
  #include <QTimer>
  #include <QTimer>
  #include "CUIRunner.h"
  #include "Runner.h"
   
   
  int main(int argc, char *argv[])
  int main(int argc, char *argv[])
75行目: 81行目:
   
   
     // ランナー開始
     // ランナー開始
     CUIRunner runner;
     Runner runner;
     QTimer::singleShot(0, &runner, SLOT(run()));
     QTimer::singleShot(0, &runner, SLOT(run()));
   
   
83行目: 89行目:
<br><br>
<br><br>


== まとめ ==
== 注釈 ==
上記のセクションにおいて、CUIソフトウェアの開発手順について記載したが、重要なことは以下の3つである。<br>
Qt Creatorでコンソールアプリケーションのプロジェクトを新規作成する場合、main関数内において、以下に示すような注釈が記載されている。<br>
* <code>QApplication::exit</code>を呼び出すとCUIソフトウェアが終了できる。
<br>
* <code>QTimer::singleShot</code>からランナークラスを実行する。
<syntaxhighlight lang="c++">
* ランナークラスにメイン処理を記述して、任意の地点で<code>exit</code>関数を実行する。
// A not very useful example would be including
// #include <QTimer>
// near the top of the file and calling
// QTimer::singleShot(5000, &a, &QCoreApplication::quit);
// which quits the application after 5 seconds.
// If you do not need a running Qt event loop, remove the call
// to a.exec() or use the Non-Qt Plain C++ Application template.
</syntaxhighlight>
<br>
* "A not very useful example" (あまり有用ではない例)
*: 注釈の例は、Qtのイベントループの基本的な使用方法を示している。
*: 注釈の例は、単にコンソールアプリケーションを起動して5秒後に終了させるだけなので、実用的なアプリケーションとしては意味がない。
<br>
<syntaxhighlight lang="c++">
// 例として挙げられているコード
// アプリケーションを5秒後に終了させるタイマを設定する
#include <QTimer>
QTimer::singleShot(5000, &a, &QCoreApplication::quit);
</syntaxhighlight>
<br>
* 注釈の主旨
*: もし、Qtのイベントループを実行する必要がない場合 (Qtの非同期機能やシグナル / スロットを使用しない場合)、
*: a.execメソッドの呼び出しを削除する、あるいは、「Non-Qt Plain C++ Application」テンプレートを使用することを提案している。
<br>
* 注釈の意図
** 開発者に、プロジェクトの要件を考慮してもらうこと。
** Qtの機能 (イベントループ等) が本当に必要かどうかを検討してもらうこと。
** 不必要にQtの機能を使用することにより、アプリケーションが複雑化、または、パフォーマンスに悪影響が出ることを避けること。
<br>
* 開発者への指針
*: もし、Qtの高度な機能 (シグナル / スロット、非同期処理等) を使用する予定がある場合は、a.execメソッドを保持してイベントループを実行する。
*: 単純なコンソールアプリケーションで、Qtの特別な機能が不要な場合は、a.execメソッドを削除する、または、純粋なC++アプリケーションとして開発することを検討する。
<br>
この注釈は、開発者がプロジェクトの要件を適切に理解して、必要に応じてQtの機能を使用する、あるいは、より単純な構造を選択するかを判断する助けとなる。<br>
<br><br>
<br><br>
{{#seo:
|title={{PAGENAME}} : Exploring Electronics and SUSE Linux | MochiuWiki
|keywords=MochiuWiki,Mochiu,Wiki,Mochiu Wiki,Electric Circuit,Electric,pcb,Mathematics,AVR,TI,STMicro,AVR,ATmega,MSP430,STM,Arduino,Xilinx,FPGA,Verilog,HDL,PinePhone,Pine Phone,Raspberry,Raspberry Pi,C,C++,C#,Qt,Qml,MFC,Shell,Bash,Zsh,Fish,SUSE,SLE,Suse Enterprise,Suse Linux,openSUSE,open SUSE,Leap,Linux,uCLnux,Podman,電気回路,電子回路,基板,プリント基板
|description={{PAGENAME}} - 電子回路とSUSE Linuxに関する情報 | This page is {{PAGENAME}} in our wiki about electronic circuits and SUSE Linux
|image=/resources/assets/MochiuLogo_Single_Blue.png
}}


__FORCETOC__
__FORCETOC__
[[カテゴリ:Qt]]
[[カテゴリ:Qt]]

2024年10月14日 (月) 10:58時点における最新版

概要

Qtは、GUIソフトウェアを開発するために使用されているが、CUIソフトウェアも開発できる。
ただし、CUIは[閉じる]ボタンのように終了する機能が無いため、ソフトウェアから適当なタイミングで閉じるようにしなければならない。

CUIソフトウェアの開発において、重要なことは以下に示す3つである。

  • QCoreApplication::exitメソッドを実行する場合、CUIソフトウェアを終了させることができる。
    ただし、QCoreApplication::exitを実行するタイミングは、イベントループが実行されている時のみである。

  • QTimer::singleShotからランナークラスを実行する。

  • ランナークラスにメイン処理を記述して、任意の地点でQCoreApplication::exitメソッドを実行する。



CUIソフトウェアの開発手順

例えば、以下に示すようなコンソールアプリケーションがあるとする。

このコンソールアプリケーションは、QCoreApplicationクラスのexecメソッドによりアプリケーションは待機状態となり、
exitメソッドを呼ぶまで待機を続ける。

 int main(int argc, char * argv[])
 {
    QCoreApplication a(argc, argv);
 
    int count = 1000;
    while(--count) {
       printf("Count = %d\n", count);
    }
 
    return a.exec();
 }


この待機状態が不要の場合は、アプリケーションを終了する時に任意の地点でexitメソッドを呼ぶランナークラスを作成すればよい。

例えば、以下に示すようなRunnerクラスを定義する。
そして、Runnerクラスのrunスロット内にアプリケーションのメイン処理を記述して、処理を終了する時にQCoreApplicationクラスのexitメソッドを呼び出す。

 // Runner.h
 
 #ifndef RUNNER_H
 #define RUNNER_H
 
 #include <QObject>
 
 class Runner : public QObject
 {
    Q_OBJECT
 
 public slots:
    void run();  // runスロットメソッドにアプリケーションのメイン処理を記述する
 };
 
 #endif // RUNNER_H


 // Runner.cppファイル
 
 #include <QCoreApplication>
 #include <Runner.h>
 
 void Runner::run()
 {
    // アプリケーションのメイン処理
 
    // ...略
 
    QCoreApplication::exit(0);  // アプリケーションを終了する
 }


重要なことは、QTimerクラスのsingleShotメソッドのタイムアウト時間を0に設定することである。
これは、アプリケーションの全てのイベント (描画処理等) が処理された後に、runメソッドで定義した処理が実行される。

 #include <QCoreApplication>
 #include <QTimer>
 #include "Runner.h"
 
 int main(int argc, char *argv[])
 {
    QCoreApplication a(argc, argv);
 
    // ランナー開始
    Runner runner;
    QTimer::singleShot(0, &runner, SLOT(run()));
 
    return a.exec();
 }



注釈

Qt Creatorでコンソールアプリケーションのプロジェクトを新規作成する場合、main関数内において、以下に示すような注釈が記載されている。

 // A not very useful example would be including
 // #include <QTimer>
 // near the top of the file and calling
 // QTimer::singleShot(5000, &a, &QCoreApplication::quit);
 // which quits the application after 5 seconds.
 
 // If you do not need a running Qt event loop, remove the call
 // to a.exec() or use the Non-Qt Plain C++ Application template.


  • "A not very useful example" (あまり有用ではない例)
    注釈の例は、Qtのイベントループの基本的な使用方法を示している。
    注釈の例は、単にコンソールアプリケーションを起動して5秒後に終了させるだけなので、実用的なアプリケーションとしては意味がない。


 // 例として挙げられているコード
 // アプリケーションを5秒後に終了させるタイマを設定する
 
 #include <QTimer>
 QTimer::singleShot(5000, &a, &QCoreApplication::quit);


  • 注釈の主旨
    もし、Qtのイベントループを実行する必要がない場合 (Qtの非同期機能やシグナル / スロットを使用しない場合)、
    a.execメソッドの呼び出しを削除する、あるいは、「Non-Qt Plain C++ Application」テンプレートを使用することを提案している。


  • 注釈の意図
    • 開発者に、プロジェクトの要件を考慮してもらうこと。
    • Qtの機能 (イベントループ等) が本当に必要かどうかを検討してもらうこと。
    • 不必要にQtの機能を使用することにより、アプリケーションが複雑化、または、パフォーマンスに悪影響が出ることを避けること。


  • 開発者への指針
    もし、Qtの高度な機能 (シグナル / スロット、非同期処理等) を使用する予定がある場合は、a.execメソッドを保持してイベントループを実行する。
    単純なコンソールアプリケーションで、Qtの特別な機能が不要な場合は、a.execメソッドを削除する、または、純粋なC++アプリケーションとして開発することを検討する。


この注釈は、開発者がプロジェクトの要件を適切に理解して、必要に応じてQtの機能を使用する、あるいは、より単純な構造を選択するかを判断する助けとなる。