nprogram’s blog

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

QSettingsクラスに、ユーザー定義クラス(独自クラス)の情報を格納する・読み出す方法について [Qt]

作成環境について

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

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

コードについて

ユーザー定義クラスとして、Paintクラスを作成しました。Paintクラスの記載[paint.cpp][paint.h]は、直前の記事から変更ありません。

[main.cpp]

#include "mainwindow.h"
#include <QApplication>
#include <QSettings>
#include <iostream>
#include <string>

int main(int argc, char *argv[])
{
    qRegisterMetaTypeStreamOperators<Paint>("Paint");
    QSettings settings("Organization", "Application");

    Paint paint("Picaso", 1932);

    // Write
    settings.setValue("custom", QVariant::fromValue(paint));

    // Read
    QVariant vInfo = settings.value("custom", QVariant());
    Paint pInfo = vInfo.value<Paint>();
    
    // Debug表示
    std::cout << "title : " << pInfo._title.toStdString() << std::endl << "year : " << pInfo._year << std::endl;

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

    return a.exec();
}

実行結果

f:id:nprogram:20170806232106p:plain

  • 以下のサイトを参考にさせていただきました。ありがとうございます。
    • QSettingsでアプリケーションの設定を保存したい

taurano.hatenablog.com

Qtで、ユーザー定義クラスのデータを保存する・読み出す方法 (Qt Designer使用)

作成環境について

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

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

Qt Designerを使用して、ユーザー定義クラスのデータをセーブ・ロードを読み出す

以下のような簡単なアプリを作成します

f:id:nprogram:20170806224700p:plain

  • mainwindow.uiのレイアウトは以下のようになります。TitleとAgeを入力するLine EditとPush Buttonが2つあれば問題ありません。

f:id:nprogram:20170806225114p:plain

  • セーブボタンとロードボタンを押したときのClickedイベントをスロットに登録しておいてください

以下はmainwindow.hの登録されたスロット

f:id:nprogram:20170806225729p:plain

[main.cpp]

  • 記載を初期状態に戻してあります

セーブロード機能は、すべてMainWindowクラスのClickedイベントメソッドで実現するようにしました。 セーブボタンを押したときは、TitleとAgeが入力されたLine Editのテキストを取得して、ユーザー定義クラスの情報を、QDataStreamに << 演算子を用いて格納しています。格納後は、テキストをクリアしました。 ロードボタンを押したときは、>> 演算子を用いて、QDataStreamに格納されたユーザー定義クラスの情報を取り出して、TitleとAgeのLine Editのテキストに反映させます。

[mainwindow.cpp]

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QFile>
#include <QDataStream>
#include <QFileDialog>
#include <QMessageBox>
#include <iostream>
#include <String>
#include "paint.h"

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

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

void MainWindow::on_pushButton_clicked()
{
    QString fileName = QFileDialog::getSaveFileName(this,
        tr("Save Paint Info"), "",
        tr("Paint info (*.txt);;All Files (*)"));

    if (fileName.isEmpty()) return;

    QFile file(fileName);

    if (!file.open(QIODevice::WriteOnly)) {
            QMessageBox::information(this, tr("Unable to open file"),
                file.errorString());
            return;
    }

    // Line Editウィジェット(オブジェクト名はlineTitle)から文字列titleを取得
    QString title = ui->lineTitle->text();

    // Line Editウィジェット(オブジェクト名はlineAge)から数値ageを取得
    int age = ui->lineAge->text().toInt();

    Paint paint(title, age);
    QDataStream out(&file);
    out.setVersion(QDataStream::Qt_4_5);
    out << paint;
    file.close();

    ui->lineTitle->clear();
    ui->lineAge->clear();
}

void MainWindow::on_pushButton_2_clicked()
{
    QString fileName = QFileDialog::getOpenFileName(this,
        tr("Load Paint Info"), "",
        tr("Paint info (*.txt);;All Files (*)"));

    if (fileName.isEmpty()) return;

    QFile file(fileName);

    if (!file.open(QIODevice::ReadOnly)) {
        QMessageBox::information(this, tr("Unable to open file"),
            file.errorString());
        return;
    }

    QDataStream in(&file);
    in.setVersion(QDataStream::Qt_4_5);

    Paint paint;
    in >> paint;
    ui->lineTitle->setText(paint._title);
    ui->lineAge->setText(QString::number(paint._year));
}

[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;
}

[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

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();
}