nprogram’s blog

気ままに、プログラミングのトピックについて書いていきます

Qtで、ユーザー定義クラスのデータを保存する方法

作成環境について

Qt Creator 4.3.1で、以下の設定で、プロジェクトを作成しております。以下の設定でクラス名、cppファイル名、hファイル名はすべてデフォルトを使用しています。

  • Qtウィジェットアプリケーション
  • 基底クラスは、QMainWindows
  • フォームを生成する

ユーザー定義クラス(独自クラス)であるPaintクラスの情報をファイルに保存できるようにする

まず、ユーザー定義クラスであるPaintクラスを作成します。 方法は、プロジェクトを選択して、右クリック。

f:id:nprogram:20170806201927p:plain

新しいファイルの追加を選択して、C++クラスを選択します。

f:id:nprogram:20170806201958p:plain

後は、クラス名を入力すると、paint.cppとpaint.hがともに作成されます。

f:id:nprogram:20170806202110p:plain

修正するコードは以下の3つです。

  • paint.cpp
    • QDataStreamクラスの >>と << の演算子オーバーロードの実装のみ、こちらに記載しています。なぜ、cppファイルに記載したかというとどこかのページで、このメソッドは、cppファイルに実装すべきだと記載されていたためです。
  • paint.h
    • Paintクラスの宣言・実装を記載します。
  • main.cpp
    • in.txtファイルに、Paintクラスの情報を書き込みます。その後、in.txtファイルから、Paintクラスの情報を取り出し、標準出力させています。

[paint.h]

#ifndef PAINT_H
#define PAINT_H

#include <QString>
#include <QDataStream>

class Paint
{
public:
    QString _title;
    int _year;

public:
    Paint(){}
    Paint(QString title, int year) {
        _title = title;
        _year = year;
    }
};

QDataStream &operator << (QDataStream &out, const Paint &paint);
QDataStream &operator >> (QDataStream &in, Paint &paint);

#endif // PAINT_H

[paint.cpp]

#include "paint.h"

QDataStream &operator << (QDataStream &out, const Paint &paint)
{
    out << paint._title << qint32(paint._year);
    return out;
}

QDataStream &operator >> (QDataStream &in, Paint &paint)
{
    QString title;
    qint32 year;

    in >> title >> year;

    paint = Paint(title, static_cast<int>(year));

    return in;
}

[main.cpp]

#include "mainwindow.h"
#include <QApplication>
#include <QFile>
#include <QDataStream>
#include <iostream>
#include <String>
#include "paint.h"

int main(int argc, char *argv[])
{
    QFile file("in.txt");
    file.open(QIODevice::WriteOnly);

    Paint paint("picaso", 1932);
    QDataStream out(&file);
    out.setVersion(QDataStream::Qt_4_5);
    out << paint;
    file.close();

    file.open(QIODevice::ReadOnly);

    Paint readInfo;
    out.setVersion(QDataStream::Qt_4_5);
    out >> readInfo;

    std::cout << "title : " << readInfo._title.toStdString() << std::endl << "age : " << readInfo._year << std::endl;

    QApplication a(argc, argv);
    MainWindow w;
    w.show();

    return a.exec();
}

注意ポイント

Qtの最新のドキュメントに記載されているオーバーロード演算子の記載に合うように、演算子オーバーロードしないと、エラーになるので、注意してください。

[Qt最新ドキュメントのオーバーロード宣言]

QDataStream &operator<<(QDataStream &, const QXxx &);
QDataStream &operator>>(QDataStream &, QXxx &);

[ユーザー定義クラスのオーバーロード宣言]

QDataStream &operator << (QDataStream &out, const Paint &paint);
QDataStream &operator >> (QDataStream &in, Paint &paint);
  • Qt5 公式ドキュメント QDataStream

http://doc.qt.io/qt-5/qdatastream.html

実行結果

上記プロジェクトを実行した結果は以下のとおりです。

f:id:nprogram:20170806210627p:plain

  • この記事は、入門 Qt4 プログラミングのP314の内容を参考にしています。
    • 上記の書籍は購入はしましたが、この本は、Qt4の情報なので、内容は少し古いです。(´;ω;`)

QtのQCombBoxの使い方 [Qt]

作成環境について

Qt Creator 4.3.1で、以下の設定で、プロジェクトを作成しております。以下の設定でクラス名、cppファイル名、hファイル名はすべてデフォルトを使用しています。

  • Qtウィジェットアプリケーション
  • 基底クラスは、QMainWindows
  • フォームを生成する

ComboBoxを設置して、実際に使ってみる

  • mainwindow.uiに、ComboBoxとPushButtonを設置
  • PushButtonを選択して、右クリックして、スロットへ移動を選択して、clicked()を選択

f:id:nprogram:20170803072412p:plain

  • mainwindow.cppにコードを記載します。
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QMessageBox>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);


    ui->comboBox->addItem("Fox1");
    ui->comboBox->addItem("Fox2");
    ui->comboBox->addItem("Fox3");
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_pushButton_clicked()
{
    QString strIndex = QString::number(ui->comboBox->currentIndex());   // This property holds the index of the current item in the combobox.
    
    QMessageBox::information(this, "title", strIndex);
}
  • 最初のComboBoxの値を選択したときに、ボタンを押したときのメッセージ表示

f:id:nprogram:20170803073154p:plain

  • 2番目のComboBoxの値を選択したときに、ボタンを押したときのメッセージ表示

f:id:nprogram:20170803073231p:plain

  • 3番目のComboBoxの値を選択したときに、ボタンを押したときのメッセージ表示

f:id:nprogram:20170803073214p:plain

以下の動画を参考に本記事を記載しました。

www.youtube.com

ComboBoxにおいて、指定した箇所にアイテムを挿入する

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QMessageBox>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);


    ui->comboBox->addItem("Fox1");
    ui->comboBox->addItem("Fox2");
    ui->comboBox->addItem("Fox3");

    ui->comboBox->insertItem(1, "homing missile");
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_pushButton_clicked()
{
    QString strIndex = QString::number(ui->comboBox->currentIndex());   // This property holds the index of the current item in the combobox.

    QMessageBox::information(this, "title", strIndex);
}

f:id:nprogram:20170803073816p:plain

Qtで、画像をLabelに埋め込む方法 [Qt]

作成環境について

Qt Creator 4.3.1で、以下の設定で、プロジェクトを作成しております。以下の設定でクラス名、cppファイル名、hファイル名はすべてデフォルトを使用しています。

  • Qtウィジェットアプリケーション
  • 基底クラスは、QMainWindows
  • フォームを生成する

Labelに画像を埋め込む

  • mainwindow.uiに、Labelを設置したのみです f:id:nprogram:20170803060843p:plain

  • mainwindow.cppでQPixmpをインクルードしています。

#include <QPixmap>

f:id:nprogram:20170803060949p:plain

表示結果は以下のようになります。

f:id:nprogram:20170803061602p:plain

Labelに埋め込む画像を拡大表示する

以下のように書き換えます。

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QPixmap>
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    QPixmap pix("C:/StudyQt/img/login.jpg");
    ui->label->setPixmap(pix.scaled(100, 100));
}

MainWindow::~MainWindow()
{
    delete ui;
}

表示結果は以下のようになりました。

f:id:nprogram:20170803062120p:plain

以下の動画の内容を参考に記載しました。

www.youtube.com

Labelのサイズを考慮して、縦横比を維持しながら、画像を拡大表示する

  • enum Qt::AspectRatioMode
    • Qt::KeepAspectRatio ⇒ サイズは、アスペクト比を維持し、所定の矩形内部できるだけ大きい矩形にスケーリングされます。
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QPixmap>
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    QPixmap pix("C:/StudyQt/img/login.jpg");
    int w = ui->label->width();
    int h = ui->label->height();
    ui->label->setPixmap(pix.scaled(w, h, Qt::KeepAspectRatio));
}

MainWindow::~MainWindow()
{
    delete ui;
}

Qt Creator ショートカット

以下の環境で、便利なショートカットを記載します。

便利なショートカット
  • 実行 ⇒ 実行させるときに使用します。ただし、qmakeも一緒にされるわけではないため、注意

    • Ctrl + R
  • ソース/フォームの切り替え ⇒ Qt Designerを使用していると、コードとデザインを交互に見る機会が増えるため、重宝します

    • Shift + F4
  • コメントアウト ⇒ 複数行を選択していれば、複数行まとめて、スラッシュスラッシュでコメントアウトされます。

    • Ctrl + /

Qt5 Designer学習

youtubeのこの動画の説明が非常にわかりやすいです。

英語ですが、動画で丁寧に説明しており、以下が丁寧に説明されています。

以下の動画は、Qt5 Designerを使用した内容となっています。

  • UIの配置方法
  • 編集モード(Edit Mode)とデザインモードの変更方法

www.youtube.com

  • SIGNALとSLOTの設定

www.youtube.com

  • QMessageBoxの使い方の説明

www.youtube.com

  • レイアウトの説明
    • horizontal layout
    • vertical layout
    • form layout
    • grid layout

www.youtube.com

  • スペーサー、スプリッター、バディ、タブの説明

www.youtube.com

  • How to Show Another Window From MainWindow in QT

www.youtube.com

<スタック領域に別画面の情報を持たせる方法>

void MainWindow::on_pushButton_clicked()
{
    Dialog secDialog;
    secDialog.setModal(true);
    secDialog.exec();
}

<ヒープに別画面の情報を持たせる方法> mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "dialog.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:
    void on_pushButton_clicked();

private:
    Ui::MainWindow *ui;
    Dialog *secDialog;
};

#endif // MAINWINDOW_H

mainwindow.cpp

void MainWindow::on_pushButton_clicked()
{
      secDialog = new Dialog(this);
      secDialog->show();
}

品質を向上させるために、テストクラスを記載しよう [C++]

このように記載すれば、製品のソースコードと、テストクラスのソースコードを分離できます。

#include "box.h"
#include <climits>
#include <cassert>
#include <iostream>

class Test {

public:
        Test() {
            Run();
        }
        static void Run() {
          // 正常ケース
            assert(Test(0,0,0,0));
          // 異常ケース
            assert(Test(2,2,2,100));
          // 例外がスローされるケース
            assert(Test(INT_MAX, INT_MAX, INT_MAX, INT_MAX));
        }
        static bool Test(int x, int y, int z, int r) {
          try {
                //検証したいコードをここに記載する
          } catch (std::exception& ex) {
            return false;
          }
        }
};

static const Test test;

Qt Creator4.3 トラブルバスター

自分がQt Creator4.3を使用する際に直面した問題の対処方法について記録します。

エラー(LNK1158)が発生

<症状> fatal error LNK1158: cannot run ‘rc.exe’が発生する

<解決策> C:\Program Files (x86)\Windows Kits\8.0\bin\x64 の rc.exe と rcdll.dll を C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\amd64 にコピーする

以下のページを参考にさせていただきました。

http://motchy99.blog.fc2.com/blog-entry-97.html

LNK2005が発生

<症状> fatal error LNK2005 * mainwindow.obj:-1: エラー: LNK2005: “class QDataStream & __cdecl operator<<(class QDataStream &,class Person const &)” (??6@YAAEAVQDataStream@@AEAV0@AEBVPerson@@@Z) は既に main.obj で定義されています。

<解決策> * 多重インクルードが発生していることが問題 * 多重インクルードを回避すること