ぼっちの夜には知らないクラスについて調べてみよう

# ぼっちの夜には知らないクラスについて調べてみよう

クリスマスイブにも関わらずボッチで過ごしている同士諸君、こんばんは。
ぼっちで生きてるQtおやつ部部長のhermit4です。

どうせ、多くの人が楽しく浮かれている日でしょうから、ビューもさほど伸びないことでしょう。そんな寂しい夜なので、Qt5.4の1170のクラスの中から、ほとんどの人には関係なさそうな、寂しいクラスについてちらほらと調べてみようかと思います。

実は、候補をいくつか見てはいますが、何せ使い方も知らないクラス達なので、中々調査が進んで行きません。どうせ今夜は暇なので、燃え尽きて眠りにつくまで、少しずつ書き足しながら更新して行きたいと思います。

24:30 : メリークリスマス。残念伸(@kassy_kz)の呪いのせいで更新が遅れました。
26:00 : 楽園追放の再生を開始
27:00 : とりあえず、coreで見慣れない２つを動かしてみました。

## extras
### [x11extras](http://doc-snapshot.qt-project.org/qt5-5.4/qtx11extras-index.html)
#### [QX11Info](http://doc-snapshot.qt-project.org/qt5-5.4/qx11info.html)
さて、Xmasにちなんで、まずはXからということで、QX11Infoから行きましょうか。
Qtというとクロスプラットフォームが売りなので、見落としがちですが、いくつか、プラットフォーム依存のクラスというものが存在しています。

QX11Infoは、X Window Systemの環境で利用できるクラスです。
すべてstaticなメンバ関数で、数も少ないので一覧を抜き出しておきましょう。

```cpp:
int appDpiX(int screen = -1)
int appDpiY(int screen = -1)
unsigned long appRootWindow(int screen = -1)
int appScreen()
unsigned long appTime()
unsigned long appUserTime()
xcb_connection_t* connection()
Display* display()
unsigned long getTimestamp()
bool isPlatformX11()
QByteArray nextStartupId()
void setAppTime(unsigned long time)
void setAppUserTime(unsigned long time)
void setNextStartupId(const QByteArray & id)
```

あえて、これを使うときというと、Display*が必要な場合でしょうか。
殆どの事はQtのみで実現可能なのですが、あえてXSendEventしたい場合とか、どうしても・・・という時に使う事になるかもといった程度の寂しいクラスです。

追記：　よく使うって人もいるようですが
<blockquote class="twitter-tweet" lang="ja"><p>Android Extras 飛ばしたなーｗ QX11Extras はなんだかんだでよく使うなぁ。libva とかの外部のライブラリを使ったりなんだりかんだり… <a href="https://twitter.com/hashtag/qtjp?src=hash">#qtjp</a></p>&mdash; Tasuku Suzuki (@task_jp) <a href="https://twitter.com/task_jp/status/547745541925257217">2014, 12月 24</a></blockquote> <script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

### [macextras](http://doc-snapshot.qt-project.org/qt5-5.4/qtmacextras-index.html)
X11があるなら、Macはどうなの？というわけですが、当然あります。
#### [QMacPasteboardMime](http://doc-snapshot.qt-project.org/qt5-5.4/qmacpasteboardmime.html)
Qtではドラッグ＆ドロップやクリップボードを使う時は、ファイル種別の識別にMIME Typeが利用されています。これに対し、Macでは、Apple UTI formatという形式があるのですが、QMacPasteboardMimeはこのUTIとMIME Typeを相互変換するのに利用できます。

#### [QMacToolBar](http://doc-snapshot.qt-project.org/qt5-5.4/qmactoolbar.html)/[QMacToolBarItem](http://doc-snapshot.qt-project.org/qt5-5.4/qmactoolbaritem.html)
QMacToolBarは、QtのNative Tool BarのNSToolbarのラッパーとの事なのですが、QToolBarとの違いはいまいちわかりません。Nativeで実装されているので、OS側の更新に従ってUIも変動するといった当たりなんでしょうかねぇ。

使い方は特に難しくありません。以下のようなコードでToolBarをウィンドウに追加できます。

```cpp:

QMacToolBar *toolBar = new QMacToolBar(this);
QMacToolBarItem *toolBarItem = toolBar->addItem(QIcon(), QStringLiteral("foo"));
connect(toolBarItem, SIGNAL(activated()), this, SLOT(fooClicked()));
toolBar->attachToWindow(window()->windowHandle());

```

### [winextras](http://doc-snapshot.qt-project.org/qt5-5.4/qtwinextras-index.html)
Xmときたらaだろ！というツッコミは心に刺さるのでしないで下さい。
X11(Linux), MacときたらWindowsです。X11, Macともすごく微妙なクラスばかりだったのですが、Windows側はあるとちょっと嬉しい機能とかが存在しています。

#### [QWinJumpList](http://doc-snapshot.qt-project.org/qt5-5.4/qwinjumplist.html)/[QWinJumpListCategory](http://doc-snapshot.qt-project.org/qt5-5.4/qwinjumplistcategory.html)/[QWinJumpListItem](http://doc-snapshot.qt-project.org/qt5-5.4/qwinjumplistitem.html)
Windowsのタスクバーのアイコンを右クリックすると開くウィンドウをジャンプリストと言いますが、Qtでこれを制御する事ができます。

でまぁ、簡単に利用できるか・・・と思ったのですが、これが意外と難しい。思った通りに動きません。WindowsのNativeの機能を使うためか、FileTypeをSupportTypeとしてレジストリに登録したり、色々準備がいるようです。

とりあえず、ExampleにあるMusic Playerのexampleを見てみましょう。

```cpp:main.cpp

static void associateFileTypes(const QStringList &fileTypes)
{
    QString displayName = QGuiApplication::applicationDisplayName();
    QString filePath = QCoreApplication::applicationFilePath();
    QString fileName = QFileInfo(filePath).fileName();

    QSettings settings("HKEY_CURRENT_USER\\Software\\Classes\\Applications\\" + fileName, QSettings::NativeFormat);
    settings.setValue("FriendlyAppName", displayName);

    settings.beginGroup("SupportedTypes");
    foreach (const QString& fileType, fileTypes)
        settings.setValue(fileType, QString());
    settings.endGroup();

    settings.beginGroup("shell");
    settings.beginGroup("open");
    settings.setValue("FriendlyAppName", displayName);
    settings.beginGroup("Command");
    settings.setValue(".", QChar('"') + QDir::toNativeSeparators(filePath) + QString("\" \"%1\""));
}

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    app.setApplicationName("MusicPlayer");
    app.setOrganizationName("QtWinExtras");
    app.setOrganizationDomain("qt-project.org");
    app.setApplicationDisplayName("QtWinExtras Music Player");
    app.setWindowIcon(QIcon(":/logo.png"));

    associateFileTypes(QStringList(".mp3"));

    MusicPlayer player;
    const QStringList arguments = QCoreApplication::arguments();
    if (arguments.size() > 1)
        player.playFile(arguments.at(1));
    player.resize(300, 60);
    player.show();

    return app.exec();
}

```

SupportedTypesに.mp3を登録し、openのshellとして、自分に引数を１つ引き渡すようコマンドを登録しています。

この指定をした上で、最近使ったファイルを可視設定にしています。

```cpp:musicplayer.cpp

    QWinJumpList jumplist;
    jumplist.recent()->setVisible(true);

```

これで、QFileDialogでopenすれば、最近使ったファイルにリストされてリストが表示されるようになるようです。

![menu.png](https://qiita-image-store.s3.amazonaws.com/0/58828/d46e92bf-d249-cdea-d06b-29b7525dcf0e.png)


#### [QWinMime](http://doc-snapshot.qt-project.org/qt5-5.4/qwinmime.html)
Macの時にも記述しましたが、QtのクリップボードはMIME typeを利用しています。このクラスはWindowsのクリップボード形式とMIME typeとを変換するためのクラスです。

#### [QWinTaskbarButton](http://doc-snapshot.qt-project.org/qt5-5.4/qwintaskbarbutton.html)
QWinTaskBarButtonは、タスクバーに表示されるアイコンそのものを表すクラスです。

```cpp:musicplayer.cpp
void MusicPlayer::createTaskbar()
{
    taskbarButton = new QWinTaskbarButton(this);
    taskbarButton->setWindow(windowHandle());
```

MusicPlayerでは、状態に応じてアイコン上にsetOverlayIconを使ってStateを示す画像を表示しています。

```cpp:musicplayer.cpp
void MusicPlayer::updateTaskbar()
{
    switch (mediaPlayer.state()) {
    case QMediaPlayer::PlayingState:
        taskbarButton->setOverlayIcon(style()->standardIcon(QStyle::SP_MediaPlay));
        taskbarProgress->show();
        taskbarProgress->resume();
        break;
    case QMediaPlayer::PausedState:
        taskbarButton->setOverlayIcon(style()->standardIcon(QStyle::SP_MediaPause));
        taskbarProgress->show();
        taskbarProgress->pause();
        break;
    case QMediaPlayer::StoppedState:
        taskbarButton->setOverlayIcon(style()->standardIcon(QStyle::SP_MediaStop));
        taskbarProgress->hide();
        break;
    }
}
```

![buttons.png](https://qiita-image-store.s3.amazonaws.com/0/58828/208e008c-0903-8b03-ca02-dbfe5d555623.png)

#### [QWinTaskbarProgress](http://doc-snapshot.qt-project.org/qt5-5.4/qwintaskbarprogress.html)
QWkinTaskbarButtonには進捗バーが表示できます。QProgressBarと同じで、RangeとValueを設定して利用します。

```cpp:musicplayer.cpp

void MusicPlayer::createTaskbar()
{
    taskbarButton = new QWinTaskbarButton(this);
    taskbarButton->setWindow(windowHandle());

    taskbarProgress = taskbarButton->progress();
    connect(positionSlider, SIGNAL(valueChanged(int)), taskbarProgress, SLOT(setValue(int)));
    connect(positionSlider, SIGNAL(rangeChanged(int,int)), taskbarProgress, SLOT(setRange(int,int)));

```

![progress1.png](https://qiita-image-store.s3.amazonaws.com/0/58828/3ea7e186-1945-6af9-3fc1-553bbb99fce2.png)
![progress2.png](https://qiita-image-store.s3.amazonaws.com/0/58828/d968e71d-043b-2bdf-e90b-b8be200a25fa.png)

WindowsでQtCreatorを使ってコンパイルかけてる時にも使われていますよね。

#### [QWinThumbnailToolBar](http://doc-snapshot.qt-project.org/qt5-5.4/qwinthumbnailtoolbar.html)/[QWinThumbnailToolButton](http://doc-snapshot.qt-project.org/qt5-5.4/qwinthumbnailtoolbutton.html)
サムネイルというのは、アイコンにマウスカーソルを当てた時に表示される小さなウィンドウです。ここにはツールバー領域があります。

```cpp:musicplayer.cpp

void MusicPlayer::createThumbnailToolBar()
{
    thumbnailToolBar = new QWinThumbnailToolBar(this);
    thumbnailToolBar->setWindow(windowHandle());

    playToolButton = new QWinThumbnailToolButton(thumbnailToolBar);
    playToolButton->setEnabled(false);
    playToolButton->setToolTip(tr("Play"));
    playToolButton->setIcon(style()->standardIcon(QStyle::SP_MediaPlay));
    connect(playToolButton, SIGNAL(clicked()), this, SLOT(togglePlayback()));

    forwardToolButton = new QWinThumbnailToolButton(thumbnailToolBar);
    forwardToolButton->setEnabled(false);
    forwardToolButton->setToolTip(tr("Fast forward"));
    forwardToolButton->setIcon(style()->standardIcon(QStyle::SP_MediaSeekForward));
    connect(forwardToolButton, SIGNAL(clicked()), this, SLOT(seekForward()));

    backwardToolButton = new QWinThumbnailToolButton(thumbnailToolBar);
    backwardToolButton->setEnabled(false);
    backwardToolButton->setToolTip(tr("Rewind"));
    backwardToolButton->setIcon(style()->standardIcon(QStyle::SP_MediaSeekBackward));
    connect(backwardToolButton, SIGNAL(clicked()), this, SLOT(seekBackward()));

    thumbnailToolBar->addButton(backwardToolButton);
    thumbnailToolBar->addButton(playToolButton);
    thumbnailToolBar->addButton(forwardToolButton);

    connect(&mediaPlayer, SIGNAL(positionChanged(qint64)), this, SLOT(updateThumbnailToolBar()));
    connect(&mediaPlayer, SIGNAL(durationChanged(qint64)), this, SLOT(updateThumbnailToolBar()));
    connect(&mediaPlayer, SIGNAL(stateChanged(QMediaPlayer::State)), this, SLOT(updateThumbnailToolBar()));
}

```

![thumbnail.png](https://qiita-image-store.s3.amazonaws.com/0/58828/b666b840-2e05-171b-10fc-e1677ebc127c.png)

さて、この他にも、たすくさんにツッコミされた、[androidextras](http://doc-snapshot.qt-project.org/qt5-5.4/qtandroidextras-module.html)もあるのですが、これは環境構築とまとめて、Android系の勉強会か何かで発表したいので、また後日という事で。

ちなみにクラス名だけでAndroidクラスタの方は何に使うかわかりそうなので、クラス名だけリストしておきましょう。

- [QAndroidActivityResultReceiver](http://doc-snapshot.qt-project.org/qt5-5.4/qandroidactivityresultreceiver.html)
- [QAndroidJniEnvironment](http://doc-snapshot.qt-project.org/qt5-5.4/qandroidjnienvironment.html)
- [QAndroidJniObject](http://doc-snapshot.qt-project.org/qt5-5.4/qandroidjniobject.html)

## core
続いて、Qtのメイン機能であるcoreから見慣れないクラスをあげていきます。

### [QAssociativeIterable](http://doc-snapshot.qt-project.org/qt5-5.4/qassociativeiterable.html)
QVariant型に格納された連想コンテナをQVariantとして反復処理するためのイテレータです。

```cpp:main.cpp
#include <QHash>
#include <QAssociativeIterable>
#include <QVariant>
#include <QDebug>

int main(int argc, char *argv[])
{
    Q_UNUSED(argc);
    Q_UNUSED(argv);
    QHash<int, QString> mapping;
    mapping.insert(7, "Seven");
    mapping.insert(11, "Eleven");
    mapping.insert(42, "Forty-two");

    QVariant variant = QVariant::fromValue(mapping);
    if (variant.canConvert<QVariantHash>()) {
        QAssociativeIterable iterable = variant.value<QAssociativeIterable>();

        qDebug() << "foreach";
        foreach (const QVariant &v, iterable) {
            qDebug() << v;
        }

        qDebug() << "for loop";
        QAssociativeIterable::const_iterator it = iterable.begin();
        const QAssociativeIterable::const_iterator end = iterable.end();
        for ( ; it != end; ++it) {
            qDebug() << "*it : " << *it;
            qDebug() << "key : " << it.key();
            qDebug() << "value : " << it.value();
        }
    }
    return 0;
}
```

QHashを生成後、QVariantに入れた後、QVariant型でkeyや値を取り出し反復処理を行う事ができます。

     foreach
     QVariant(QString, "Forty-two")
     QVariant(QString, "Eleven")
     QVariant(QString, "Seven")
     for loop
     *it :  QVariant(QString, "Forty-two")
     key :  QVariant(int, 42)
     value :  QVariant(QString, "Forty-two")
     *it :  QVariant(QString, "Eleven")
     key :  QVariant(int, 11)
     value :  QVariant(QString, "Eleven")
     *it :  QVariant(QString, "Seven")
     key :  QVariant(int, 7)
     value :  QVariant(QString, "Seven")



### [QException](http://doc-snapshot.qt-project.org/qt5-5.4/qexception.html)

QExceptionは、Threadを超えてWorker Threadから例外を届ける事ができるExceptionです。12月３日に実装したQtConcurrentの例をちょっと改造してみましょう。

```cpp:

#include <QCoreApplication>
#include <QtConcurrent>
#include <QVector>
#include <QThread>
#include <QDebug>
#include <QException>

class MyException : public QException
{
public:
    void raise() const { throw *this; }
    MyException *clone() const { return new MyException(*this); }
};

struct Increment
{
    Increment() : i_(0) {}
    int operator()() { return i_++; }

    int i_;
};

struct Calc
{
    typedef void result_type;

    Calc(const int& a, const int&  b) :a_(a), b_(b) {}
    result_type operator()(int& x)
    {
        x = a_*x+b_;
        qDebug() << "thread : " << x;
        QThread::usleep(800);
        if (x > 512) {
            MyException exception;
            exception.raise();
        }
    }
    int a_;
    int b_;
};

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);
    QVector<int> data(100);

    // vectorを0-99で設定する
    std::generate(data.begin(), data.end(), Increment());
    foreach (int i, data) {
        qDebug() << i;
    }

    int a = 12;
    int b = 3;
    qDebug() << " --- Calc " << a << " * data[n] + " << b;
    try {
        QFuture<void> ret = QtConcurrent::map(data,Calc(a,b));
        ret.waitForFinished();
        foreach (int i, data) {
            qDebug() << i;
        }
    } catch (const MyException& e) {
        Q_UNUSED(e);
        qDebug() << "Exception";
    }
    return 0;
}

```

Exceptionを追加する前の結果は以下の通りでした。

    0
    1
    2
    3
    4
    ：
    ：
    95
    96
    97
    98
    99
     --- Calc  12  * data[n] +  3 
    3
    15
    27
    39
    51
    ：
    ：
    1143
    1155
    1167
    1179
    1191

これを、512でExceptionが起きるようにすると

    0
    1
    2
    3
    4
    ：
    ：
    95
    96
    97
    98
    99
     --- Calc  12  * data[n] +  3 
    thread :  3
    thread :  27
    thread :  15
    thread :  39
    thread :  51
    thread :  63
    thread :  75
    thread :  99
    thread :  87
     :
     :
    thread :  447
    thread :  471
    thread :  495
    thread :  483
    thread :  507
    thread :  519
    thread :  531
    thread :  543
    Exception

waitForFinished()が最後まで終わらず、main threadのcatchへ移行して終了します。
QtConcurrentを使うときの悩み事が、途中で深刻なエラーが起きた時にどう止めるかなんですが、これで解決かな。

何せ、いままで使ってこなかったクラスを動かしながら、試しながらで進めてきたので、当初期待していた半分も進まなかったですが、そろそろ世の中も寝静まっているでしょうし、ここらへんにしておきましょうか。

ちなみに、特に利用方法がよくわからなかったものとしては

- QCollator
- QCollatorSortKey
- QGlobalStatic

といった当たりがありました。QCollatorあたりはうまく利用すると、文字列中の数字の並びをうまい事sortできるようになるとか・・・・。使い方をよくご存知の方、教えてくれるとうれしいです。

利用方法はわかるけど、動かすまでが面倒だなってのが

- QAx.* 

でしょうか。Windowsオンリーの機能ですが、ActiveXとかCOMを利用したり、あるいは逆に提供したりといったクラスも存在しています。

他にも、OpenGL系が刷新されてたり、QBackingStoreですとか、QOffscreenSurfaceとか、まぁ、色々見慣れないクラスも多い事。いくつかサンプルを書いてみたものの、いまいちなできなので、もう少し調査が必要そうです。本当、最近のものは、Exampleもあまり用意されてないものもあったりするので、どう使うのか悩ましかったりしますね。

Qtは、特にQt5以降、猛烈な勢いで変化が起こっています。なかなか追いついて行くのも難儀なものですが、あるいは、あなたが必要としていたクラスもこっそり追加されているかもしれません。
寝付けない、やる事の無い、暇なぼっちの夜には、ぜひQtのクラス一覧を開いて、ちらほらとクラス名一覧を眺めてみてあげて下さい。

そんなこんなで、なるほど４時じゃねーのって当たりで、24日を超えた、ぐだぐだであまり役にたたなさそうなネタ記事を終了します。こんなぐだぐだな適当記事でもいいんだって思って、来年は新規で参加してくれる人が増えるとうれしいなぁ・・・。

前日の記事がまだまとまっていないようではありますが、とりあえず、カレンダーとしては残す所あと１日分。最終日は、Qtユーザー会発足の引き金を引いた現役高校生 @luyikei 君による記事となりますので、あと一日、おつきあいください。