C++で実際にGUIアプリを作ってみたい。フレームワークはQtを使用したい。
こんなご要望にお応えします。
・C++で実際にアプリを作成したい
・Qtを使用してみたい
エンジニア歴15年のうましが解説します。
Qtを使ってGUIの電卓アプリを作成
開発環境
・OS : Windows10 64bit
・Qt Creator 7.0.2/Based on Qt 6.2.3 (MSVC 2019, 64 bit)
※Qtのオープンソース版(無償版)
Qt(オープンソース版)のインストール
以下のリンクから『オープンソース版利用時の義務』を確認し、オープンソース版(無償版)をダウンロードします。
オープンソースは商用ではなくフリーソフトのような開発が目的のライセンスになります。そのため、コードの開示も必要に応じて行う義務があります。営利目的でのソフトウェア開発が目的の方は商用をご検討ください。
規約に同意したら『Download the Qt Online Installer』に進んでください。
『Download』をクリックしてください。
オンライン用のインストーラーがダウンロードされます。実行するとインストールが始まります。Qtアカウントをお持ちでない方はアカウント作成を行う必要がありますが簡単に終わります。メールアドレスとパスワードを入力して『次へ』をクリックしてください。
規約が表示されますので同意したら2か所にチェックを入れて『次へ』で進みます。しばらく流れに従って進めていきます。
インストールするディレクトリ(フォルダ)を指定して、『Qt6.2 for desktop development』にチェックを入れて『次へ』をクリックしてください。その後は画面の指示に従って進みます。
問題なければ次の画面になりますので、『インストール』をクリックしてください。環境によりますが、10~20分くらいかかります。
『完了』をクリックしてインストール終了です。
まずは簡単なGUI電卓を作成してみる
C++で実際に簡単なGUI電卓の作成を行います。完成する電卓は以下のものです。
まずは簡略化のために「1+1+1」のような計算は禁止して「1+1=」のように「数値」→「演算子」→「数値」→「=」と入力する電卓を作成します。
プロジェクトの作成
ファイル→『New Project…』を選択
プロジェクトの『Application(Qt)』→『Qt Widgets Application』→『Choose…』と進みます。『プロジェクトパス』の名前を今回は『calculator』とします(お好みで構いません)
その後は全てデフォルトで『次へ』で進み、キットの選択:『Desktop Qt6.2.4MinGW 64-bit』にチェックを入れて『完了』まで進んでください。
プロジェクトエクスプローラーの『mainwindow.ui』を開いてください。
Buttonsの『Push Button』を16個ドラッグアンドドロップで配置します。きっちりと配置する必要はありません。おおまかに以下のように配置します。
左上から左クリックしたまま右下まで移動して全てを選択してから左クリックを離します。
全てのPush Buttonを選択した状態で『格子状に並べる』をクリックします。下の図と違う配置で整列した場合はずれたPush Buttonをドラッグアンドドロップして配置します。
Push Buttonを1個ずつダブルクリックして表記を変更します。
以下のように16個の表記を変更します。
右のオブジェクトの欄が縮んでいる場合は右に広げてください。
Push Bottunを選択すると右の欄の対応するオブジェクトが反応します。
オブジェクトをダブルクリックして変更しますが、まず注意点をご紹介します。
※注意 同じオブジェクト名は付けられません。例えばすでに別のボタンに『pushButton_0』が割り当てられている状態で重複して別のボタンをpushButton_0にすることはできません。一旦、仮でpushButton_Aなどにするなど工夫が必要になります。
次のように全てを変更してください。
ボタン:オブジェクト
1:pushButton_1
2:pushButton_2
3:pushButton_3
4:pushButton_4
5:pushButton_5
6:pushButton_6
7:pushButton_7
8:pushButton_8
9:pushButton_9
0:pushButton_0
+ :pushButton_plus
– :pushButton_minus
× :pushButton_mult
÷ :pushButton_div
DEL:pushButton_del
= :pushButton_equal
※誤記があると後のソースコードをコピペしても動作できませんのでご注意ください
1を選択して「右クリック→スロットへ移動…」を選択してください。
『released()』を選択して『OK』をクリックして下さい。
『mainwindow.cpp』に『void MainWindow::on_pushButton_1_released()』が自動で追加されます。『mainwindow.ui』に戻り、同様に全てのPushBottonでこの操作を行います。
『Label』をドラッグアンドドロップして配置します。このText Labelは入力した数値や計算結果を表示します。
配置したLabelのオブジェクトを『label_view』に変更します。
Labelを選択した状態で『alignment→横方向』を右端揃えに変更してください。また、QLabel-textの『TextLabel』を空欄にしてください。電卓の結果の初期値になります。
アプリの外形を調整します(これはしなくても動作には影響ありません)
『mainwindow.cpp』を開いて以下のソースコードをコピペしてください。
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QString>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
QString view = "0"; //表示するための変数
QString func; //演算を格納する変数
QString result_memory = "0"; //結果を一時的に格納する変数
bool func_flag = false; //演算のどれかを押されたら変化するフラグ
int result; //数値の計算結果
//1を押されたときの処理
void MainWindow::on_pushButton_1_released()
{
if ((view == "0") || (func_flag == true)){
view = "1";
func_flag = false;
} else {
view += "1";
}
ui->label_view->setText(view);
}
//2を押されたときの処理
void MainWindow::on_pushButton_2_released()
{
if ((view == "0") || (func_flag == true)){
view = "2";
func_flag = false;
} else {
view += "2";
}
ui->label_view->setText(view);
}
//3を押されたときの処理
void MainWindow::on_pushButton_3_released()
{
if ((view == "0") || (func_flag == true)){
view = "3";
func_flag = false;
} else {
view += "3";
}
ui->label_view->setText(view);
}
//4を押されたときの処理
void MainWindow::on_pushButton_4_released()
{
if ((view == "0") || (func_flag == true)){
view = "4";
func_flag = false;
} else {
view += "4";
}
ui->label_view->setText(view);
}
//4を押されたときの処理
void MainWindow::on_pushButton_5_released()
{
if ((view == "0") || (func_flag == true)){
view = "5";
func_flag = false;
} else {
view += "5";
}
ui->label_view->setText(view);
}
//6を押されたときの処理
void MainWindow::on_pushButton_6_released()
{
if ((view == "0") || (func_flag == true)){
view = "6";
func_flag = false;
} else {
view += "6";
}
ui->label_view->setText(view);
}
//7を押されたときの処理
void MainWindow::on_pushButton_7_released()
{
if ((view == "0") || (func_flag == true)){
view = "7";
func_flag = false;
} else {
view += "7";
}
ui->label_view->setText(view);
}
//8を押されたときの処理
void MainWindow::on_pushButton_8_released()
{
if ((view == "0") || (func_flag == true)){
view = "8";
func_flag = false;
} else {
view += "8";
}
ui->label_view->setText(view);
}
//9を押されたときの処理
void MainWindow::on_pushButton_9_released()
{
if ((view == "0") || (func_flag == true)){
view = "9";
func_flag = false;
} else {
view += "9";
}
ui->label_view->setText(view);
}
//0を押されたときの処理
void MainWindow::on_pushButton_0_released()
{
if (view == "0"){
view = "0";
} else {
view += "0";
}
ui->label_view->setText(view);
}
//+を押されたときの処理
void MainWindow::on_pushButton_plus_released()
{
func = "+";
result_memory = view;
func_flag = true;
}
//―を押されたときの処理
void MainWindow::on_pushButton_minus_released()
{
func = "-";
result_memory = view;
func_flag = true;
}
//×を押されたときの処理
void MainWindow::on_pushButton_mult_released()
{
func = "*";
result_memory = view;
func_flag = true;
}
//÷を押されたときの処理
void MainWindow::on_pushButton_div_released()
{
func = "/";
result_memory = view;
func_flag = true;
}
//=を押されたときの処理
void MainWindow::on_pushButton_equal_released()
{
if (func == "+"){
result = result_memory.toInt() + view.toInt();
view = QString::number(result);
ui->label_view->setText(view);
result_memory = view;
} else if (func == "-"){
result = result_memory.toInt() - view.toInt();
view = QString::number(result);
ui->label_view->setText(view);
result_memory = view;
} else if (func == "*"){
result = result_memory.toInt() * view.toInt();
view = QString::number(result);
ui->label_view->setText(view);
result_memory = view;
} else if (func == "/"){
result = result_memory.toInt() / view.toInt();
view = QString::number(result);
ui->label_view->setText(view);
result_memory = view;
}
}
//DELを押されたときの処理
void MainWindow::on_pushButton_del_released()
{
result_memory = "0";
view = "0";
ui->label_view->setText(view);
}
//mainwindow.h
//うまくいかない時はこちらをコピペしてください
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
//ここがうまくいっていないことが多いです。
//ボタンを右クリック→スロットへ移動・・・
private slots:
void on_pushButton_1_released();
void on_pushButton_2_released();
void on_pushButton_3_released();
void on_pushButton_4_released();
void on_pushButton_5_released();
void on_pushButton_6_released();
void on_pushButton_7_released();
void on_pushButton_8_released();
void on_pushButton_9_released();
void on_pushButton_0_released();
void on_pushButton_plus_released();
void on_pushButton_minus_released();
void on_pushButton_mult_released();
void on_pushButton_div_released();
void on_pushButton_del_released();
void on_pushButton_equal_released();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
ビルドおよび動作確認
『実行』を選択してください。
『Save All』を選択してください。
簡易的なGUI電卓アプリの完成です。
分岐を複雑にして入力の幅を広げる
次は「1+1=」のように「数値」→「演算子」→「数値」→「=」と入力を限定して「1+1+1」のような計算は禁止していました。今回は機能を追加して「1+1+1=」のような入力も可能にします。
【注記】
今回は簡略化のために「1+1+1」のような計算は禁止して「1+1=」のように「数値」→「演算子」→「数値」→「=」と入力する電卓を作成します。
ソースコードの追加
前回のコードを以下のように変更します。『※今回修正』としている部分になります。
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QString>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
QString view = "0"; //表示するための変数
QString func; //演算を格納する変数
QString result_memory = "0"; //結果を一時的に格納する変数
bool func_flag = false; //演算のどれかを押されたら変化するフラグ
int result; //数値の計算結果
//1を押されたときの処理
void MainWindow::on_pushButton_1_released()
{
if ((view == "0") || (func_flag == true)){
view = "1";
func_flag = false;
} else {
view += "1";
}
ui->label_view->setText(view);
}
//2を押されたときの処理
void MainWindow::on_pushButton_2_released()
{
if ((view == "0") || (func_flag == true)){
view = "2";
func_flag = false;
} else {
view += "2";
}
ui->label_view->setText(view);
}
//3を押されたときの処理
void MainWindow::on_pushButton_3_released()
{
if ((view == "0") || (func_flag == true)){
view = "3";
func_flag = false;
} else {
view += "3";
}
ui->label_view->setText(view);
}
//4を押されたときの処理
void MainWindow::on_pushButton_4_released()
{
if ((view == "0") || (func_flag == true)){
view = "4";
func_flag = false;
} else {
view += "4";
}
ui->label_view->setText(view);
}
//4を押されたときの処理
void MainWindow::on_pushButton_5_released()
{
if ((view == "0") || (func_flag == true)){
view = "5";
func_flag = false;
} else {
view += "5";
}
ui->label_view->setText(view);
}
//6を押されたときの処理
void MainWindow::on_pushButton_6_released()
{
if ((view == "0") || (func_flag == true)){
view = "6";
func_flag = false;
} else {
view += "6";
}
ui->label_view->setText(view);
}
//7を押されたときの処理
void MainWindow::on_pushButton_7_released()
{
if ((view == "0") || (func_flag == true)){
view = "7";
func_flag = false;
} else {
view += "7";
}
ui->label_view->setText(view);
}
//8を押されたときの処理
void MainWindow::on_pushButton_8_released()
{
if ((view == "0") || (func_flag == true)){
view = "8";
func_flag = false;
} else {
view += "8";
}
ui->label_view->setText(view);
}
//9を押されたときの処理
void MainWindow::on_pushButton_9_released()
{
if ((view == "0") || (func_flag == true)){
view = "9";
func_flag = false;
} else {
view += "9";
}
ui->label_view->setText(view);
}
//0を押されたときの処理
void MainWindow::on_pushButton_0_released()
{
if (view == "0"){
view = "0";
} else {
view += "0";
}
ui->label_view->setText(view);
}
//+を押されたときの処理 ※今回修正
void MainWindow::on_pushButton_plus_released()
{
func = "+";
if (result_memory != "0"){
result = result_memory.toInt() + view.toInt();
view = QString::number(result);
ui->label_view->setText(view);
result_memory = view;
} else {
result = view.toInt();
result_memory = view;
}
func_flag = true;
}
//―を押されたときの処理 ※今回修正
void MainWindow::on_pushButton_minus_released()
{
func = "-";
if (result_memory != "0"){
result = result_memory.toInt() - view.toInt();
view = QString::number(result);
ui->label_view->setText(view);
result_memory = view;
} else {
result = view.toInt();
result_memory = view;
}
func_flag = true;
}
//×を押されたときの処理 ※今回修正
void MainWindow::on_pushButton_mult_released()
{
func = "*";
if (result_memory != "0"){
result = result_memory.toInt() * view.toInt();
view = QString::number(result);
ui->label_view->setText(view);
result_memory = view;
} else {
result = view.toInt();
result_memory = view;
}
func_flag = true;
}
//÷を押されたときの処理 ※今回修正
void MainWindow::on_pushButton_div_released()
{
func = "/";
if (result_memory != "0"){
result = result_memory.toInt() / view.toInt();
view = QString::number(result);
ui->label_view->setText(view);
result_memory = view;
} else {
result = view.toInt();
result_memory = view;
}
func_flag = true;
}
//=を押されたときの処理
void MainWindow::on_pushButton_equal_released()
{
if (func == "+"){
result = result_memory.toInt() + view.toInt();
view = QString::number(result);
ui->label_view->setText(view);
result_memory = view;
} else if (func == "-"){
result = result_memory.toInt() - view.toInt();
view = QString::number(result);
ui->label_view->setText(view);
result_memory = view;
} else if (func == "*"){
result = result_memory.toInt() * view.toInt();
view = QString::number(result);
ui->label_view->setText(view);
result_memory = view;
} else if (func == "/"){
result = result_memory.toInt() / view.toInt();
view = QString::number(result);
ui->label_view->setText(view);
result_memory = view;
}
}
//DELを押されたときの処理
void MainWindow::on_pushButton_del_released()
{
result_memory = "0";
view = "0";
result = 0;
ui->label_view->setText(view);
}
この変更により
・1+1+3 =
・2×3×4=
このような入力も可能になりました。
メモリを追加して過去の計算結果も表示する
今回は以下のように過去の計算結果や現在選択中の演算子を表示する電卓を作成します。
Text Labelの追加
以下を追加します。『Label』を2個ドラッグアンドドロップして配置してください。
追加した左側を『label_memory』とし、右側を『label_func』と変更します。
追加したTextLabelを1つ選択してQLabelの『text』を空欄にしてEnterキーを押して下さい。初期値を値なしにします。これを追加した2個とも行います。
ソースコード
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QString>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
QString view = "0"; //表示するための変数
QString func; //演算を格納する変数
QString result_memory = "0"; //結果を一時的に格納する変数
bool func_flag = false; //演算のどれかを押されたら変化するフラグ
int result; //数値の計算結果
//1を押されたときの処理
void MainWindow::on_pushButton_1_released()
{
if ((view == "0") || (func_flag == true)){
view = "1";
func_flag = false;
} else {
view += "1";
}
ui->label_view->setText(view);
}
//2を押されたときの処理
void MainWindow::on_pushButton_2_released()
{
if ((view == "0") || (func_flag == true)){
view = "2";
func_flag = false;
} else {
view += "2";
}
ui->label_view->setText(view);
}
//3を押されたときの処理
void MainWindow::on_pushButton_3_released()
{
if ((view == "0") || (func_flag == true)){
view = "3";
func_flag = false;
} else {
view += "3";
}
ui->label_view->setText(view);
}
//4を押されたときの処理
void MainWindow::on_pushButton_4_released()
{
if ((view == "0") || (func_flag == true)){
view = "4";
func_flag = false;
} else {
view += "4";
}
ui->label_view->setText(view);
}
//4を押されたときの処理
void MainWindow::on_pushButton_5_released()
{
if ((view == "0") || (func_flag == true)){
view = "5";
func_flag = false;
} else {
view += "5";
}
ui->label_view->setText(view);
}
//6を押されたときの処理
void MainWindow::on_pushButton_6_released()
{
if ((view == "0") || (func_flag == true)){
view = "6";
func_flag = false;
} else {
view += "6";
}
ui->label_view->setText(view);
}
//7を押されたときの処理
void MainWindow::on_pushButton_7_released()
{
if ((view == "0") || (func_flag == true)){
view = "7";
func_flag = false;
} else {
view += "7";
}
ui->label_view->setText(view);
}
//8を押されたときの処理
void MainWindow::on_pushButton_8_released()
{
if ((view == "0") || (func_flag == true)){
view = "8";
func_flag = false;
} else {
view += "8";
}
ui->label_view->setText(view);
}
//9を押されたときの処理
void MainWindow::on_pushButton_9_released()
{
if ((view == "0") || (func_flag == true)){
view = "9";
func_flag = false;
} else {
view += "9";
}
ui->label_view->setText(view);
}
//0を押されたときの処理
void MainWindow::on_pushButton_0_released()
{
if (view == "0"){
view = "0";
} else {
view += "0";
}
ui->label_view->setText(view);
}
//+を押されたときの処理
void MainWindow::on_pushButton_plus_released()
{
func = "+";
ui->label_func->setText(func);
if (result_memory != "0"){
result = result_memory.toInt() + view.toInt();
view = QString::number(result);
ui->label_view->setText(view);
result_memory = view;
ui->label_memory->setText(result_memory);
} else {
result = view.toInt();
ui->label_memory->setText(result_memory);
result_memory = view;
ui->label_memory->setText(result_memory);
}
func_flag = true;
}
//―を押されたときの処理
void MainWindow::on_pushButton_minus_released()
{
func = "-";
ui->label_func->setText(func);
if (result_memory != "0"){
result = result_memory.toInt() - view.toInt();
view = QString::number(result);
ui->label_view->setText(view);
result_memory = view;
ui->label_memory->setText(result_memory);
} else {
result = view.toInt();
result_memory = view;
ui->label_memory->setText(result_memory);
}
func_flag = true;
}
//×を押されたときの処理
void MainWindow::on_pushButton_mult_released()
{
func = "*";
ui->label_func->setText(func);
if (result_memory != "0"){
result = result_memory.toInt() * view.toInt();
view = QString::number(result);
ui->label_view->setText(view);
result_memory = view;
ui->label_memory->setText(result_memory);
} else {
result = view.toInt();
result_memory = view;
ui->label_memory->setText(result_memory);
}
func_flag = true;
}
//÷を押されたときの処理
void MainWindow::on_pushButton_div_released()
{
func = "/";
ui->label_func->setText(func);
if (result_memory != "0"){
result = result_memory.toInt() / view.toInt();
view = QString::number(result);
ui->label_view->setText(view);
result_memory = view;
ui->label_memory->setText(result_memory);
} else {
result = view.toInt();
result_memory = view;
ui->label_memory->setText(result_memory);
}
func_flag = true;
}
//=を押されたときの処理
void MainWindow::on_pushButton_equal_released()
{
if (func == "+"){
result = result_memory.toInt() + view.toInt();
view = QString::number(result);
ui->label_view->setText(view);
result_memory = "0";
} else if (func == "-"){
result = result_memory.toInt() - view.toInt();
view = QString::number(result);
ui->label_view->setText(view);
result_memory = "0";
} else if (func == "*"){
result = result_memory.toInt() * view.toInt();
view = QString::number(result);
ui->label_view->setText(view);
result_memory = "0";
} else if (func == "/"){
result = result_memory.toInt() / view.toInt();
view = QString::number(result);
ui->label_view->setText(view);
result_memory = "0";
}
}
//DELを押されたときの処理
void MainWindow::on_pushButton_del_released()
{
result_memory = "0";
view = "0";
ui->label_view->setText(view);
func = "";
ui->label_func->setText(func);
result_memory = view;
ui->label_memory->setText("");
}
これで過去の計算結果と現在選択中の演算子を表示できるようになりました。
うましブックマーク登録やブログでご紹介、拡散をしてもらえるとはげみになります!