はじめに (書籍の紹介)
HeadFirstデザインパターンの本のコードのサンプルは、GitHubにあります。
http://www.wickedlysmart.com/headfirstdesignpatterns/code.htmlgithub.com
リンク1
パターン指向リファクタリング 読書メモ - mookjp.io
HeadFirstデザインパターンの本のコードのサンプルは、GitHubにあります。
http://www.wickedlysmart.com/headfirstdesignpatterns/code.htmlgithub.com
パターン指向リファクタリング 読書メモ - mookjp.io
QTextStreamを用いることで、csvファイルに保存することが可能です。
csvファイル保存の形式に合わせるため、データごとにカンマで区切ります。今回は、10個のデータごとに改行します。
今回使用するデータは、日本語文字列データを使用しました。
以下がコードです。
#include "mainwindow.h" #include "ui_mainwindow.h" #include <QString> #include <QDebug> #include <QFile> #include <QTextStream> #include <QFileDialog> #include <QMessageBox> #define Jstr(str) QString::fromLocal8Bit(str) MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); } MainWindow::~MainWindow() { delete ui; } void MainWindow::on_pushButton_clicked() { // csvファイルに書き込むQStringListを作成 QStringList writeList; QString str = Jstr("日本語"); for (int i = 1; i <= 100; i++) { if (i % 10){ writeList.append(str + " : " + QString::number(i) + ","); } else { // 改行コードはLFです writeList.append(str + " : " + QString::number(i) + "\n"); } } // fileNameとfile pathを求める QString fileName = QFileDialog::getSaveFileName(this, tr("Save Paint Info"), "", tr("Paint info (*.csv);;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; } // デバッグ表示 foreach (QString item, writeList) { qDebug() << item; } // csvファイルに書き込む QTextStream out(&file); foreach (QString item, writeList) { out << item; } }
不明なコンパイル時の出力はありますが、無事、csvファイルにデータを書き込むことができました。
Qt5では文字列リテラルを QString へ変換するには主に以下のメソッドを使用可能。
QString::fromLatin1()
QString::fromLocal8Bit()
QString::fromUtf8()
以下にマクロを使用しないパターンと使用するパターンを記載します。
[マクロ未使用パターン]
#include "mainwindow.h" #include "ui_mainwindow.h" #include <QString> #include <QDebug> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); } MainWindow::~MainWindow() { delete ui; } void MainWindow::on_pushButton_clicked() { QStringList qStrList; // QString::fromLocal8Bit() ⇒ 現在のロケールに合わせたコーデックを使用して QString を生成します QString temp = QString::fromLocal8Bit("日本語"); for (int i = 0; i < 100; i++) { QString qStrTest = temp; qStrList.append(qStrTest); } foreach (QString item, qStrList) { qDebug() << item; } }
[マクロ使用パターン]
#include "mainwindow.h" #include "ui_mainwindow.h" #include <QString> #include <QDebug> #define Jstr(str) QString::fromLocal8Bit(str) MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); } MainWindow::~MainWindow() { delete ui; } void MainWindow::on_pushButton_clicked() { QStringList qStrList; QString temp = Jstr("日本語"); for (int i = 0; i < 100; i++) { QString qStrTest = temp; qStrList.append(qStrTest); } foreach (QString item, qStrList) { qDebug() << item; } }
実行結果は、以下のとおりです。日本語文字列を使用しても、文字化けが発生しません。
以下の記事のサイトを参考にさせていただきました。ありがとうございます。
Qt Creator 4.3.1で、以下の設定で、プロジェクトを作成しております。以下の設定でクラス名、cppファイル名、hファイル名はすべてデフォルトを使用しています。
メインウィンドウ終了時に、ユーザー定義クラスのリストをQDataStreamにセーブします。
再度、アプリケーションを実行したときに、前回終了時に保存したユーザー定義クラスのリストの情報を取り出すプログラムです。
変更ファイルは以下のとおり。
新規追加ファイルは以下のとおり。Paintクラスはユーザー定義クラス(独自クラス)となります。 * paint.cpp * paint.h
[mainwindow.cpp]
#include "mainwindow.h" #include "ui_mainwindow.h" #include <QMessageBox> #include <QSettings> #include <QSize> #include <QDataStream> #include <QFile> #include <QDebug> #include <iostream> #include "paint.h" const QString FILE_NAME = "out.txt"; MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); QFile file(FILE_NAME); file.open(QIODevice::ReadOnly); QDataStream in (&file); in.setVersion(QDataStream::Qt_5_9); // QDataStreamから、paintListの要素数を読み出す int paintListSize = 0; in >> paintListSize; // QDataStreamから、paintListの要素数分、ユーザー定義クラス(Paintクラス)の情報を読み出す for (int i = 0; i < paintListSize; i++) { Paint paint; in >> paint; std::cout << "title : " << paint._title.toStdString() << std::endl; std::cout << "age : " << paint._year << std::endl; } } MainWindow::~MainWindow() { delete ui; } // Qtでは、closeEventをオーバーライドする事で実現可能です。 void MainWindow::closeEvent( QCloseEvent *event ){ // ユーザー定義クラス(Paintクラス)をQLinkedListに追加する for (int i = 0; i < 5; i++) { Paint paint("Paint", i + 1900); QVariant vPaint = QVariant::fromValue(paint); paintList.append(vPaint); } QFile file(FILE_NAME); file.open(QIODevice::WriteOnly); QDataStream out (&file); out.setVersion(QDataStream::Qt_5_9); // QDataStreamに、paintListの要素数を格納する out << paintList.size(); // QDataStreamに、ユーザー定義クラス(Paintクラス)を格納する foreach (QVariant item, paintList) { Paint paint = item.value<Paint>(); out << paint; } }
[mainwindow.h]
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QLinkedList> namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); private: Ui::MainWindow *ui; protected: virtual void closeEvent( QCloseEvent *event ); QLinkedList<QVariant> paintList; }; #endif // MAINWINDOW_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; }
[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; } }; // Q_DECLARE_METATYPEマクロにより、QMetaTypeに独自の型を登録 Q_DECLARE_METATYPE(Paint) QDataStream &operator << (QDataStream &out, const Paint &paint); QDataStream &operator >> (QDataStream &in, Paint &paint); #endif // PAINT_H
以下のように、前回終了時に保存したユーザー定義クラスのリストの情報を取り出すができました。
Qt Creator 4.3.1で、以下の設定で、プロジェクトを作成しております。以下の設定でクラス名、cppファイル名、hファイル名はすべてデフォルトを使用しています。
画面終了時の画面の幅と高さをQSettingsに格納します。
再度、アプリケーションを実行したときに、前回起動時の画面の幅と高さを再現するプログラムです。
修正コードは以下の2か所
[mainwindow.cpp]
#include "mainwindow.h" #include "ui_mainwindow.h" #include <QMessageBox> #include <QSettings> #include <QSize> const QString ORG_NAME = "My Company"; const QString APP_NAME = "My Tool"; MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); QSettings settings("My Company", "My Tool"); int width = settings.value("window/width").toInt(); int height = settings.value("window/height").toInt(); this->resize(QSize(width, height)); } MainWindow::~MainWindow() { delete ui; } // Qtでは、closeEventをオーバーライドする事で実現可能です。 void MainWindow::closeEvent( QCloseEvent *event ){ int width = this->geometry().width(); int height = this->geometry().height(); QMessageBox::information(this, "Finish Timing", tr("window width : %1 \nwindow height : %2").arg(width).arg(height)); QSettings settings("My Company", "My Tool"); settings.setValue("window/width", width); settings.setValue("window/height", height); }
[mainwindow.h]
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); private: Ui::MainWindow *ui; protected: virtual void closeEvent( QCloseEvent *event ); }; #endif // MAINWINDOW_H
前回の画面サイズが、起動時に再現することができました。
<アプリケーション終了時>
<アプリケーション起動時>
Qt Creator 4.3.1で、以下の設定で、プロジェクトを作成しております。以下の設定でクラス名、cppファイル名、hファイル名はすべてデフォルトを使用しています。
ユーザー定義クラスとして、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(); }
Qt Creator 4.3.1で、以下の設定で、プロジェクトを作成しております。以下の設定でクラス名、cppファイル名、hファイル名はすべてデフォルトを使用しています。
以下のような簡単なアプリを作成します
以下はmainwindow.hの登録されたスロット
[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