手動でメニューを作る

(サンプル一覧を表示する)


Qt Creator を使うと GUI でメニューを構築できるんですが、いったん内部の構造を把握するために手動で作ってみましょう。

プロジェクトを作成する


まず、ファイルメニューから "ファイル/プロジェクトの新規作成を選んでください。"




ここでは、 "Qt4 GUI アプリケーション" を選択します。




プロジェクト名は、 "MenuTest" としておきます。




必須モジュールの選択画面では、今のところ特に追加するものがないので
"QtCore", "QtGui" のみが選択された状態にしておきます。




クラス名はそのままでOKです。
基底クラスは "QMainWindow" としておいてください。




"完了" ボタンをクリックするとプロジェクトが作成されます。




ウインドウを編集する


プロジェクトが作成できたら、 "mainwindow.ui" を開いて、ラベルを配置してみましょう。
これはメニュー項目の選択結果の表示用に使います。
"Label" をドラッグして、ウインドウに乗せてみましょう。
ラベルはダブルクリックすると内容を編集することができます。
領域が狭くて文字が入りきらない場合は、端っこにある青い四角をつかんで伸ばしてください。




ソースコードを書く


ここまでできたら、次はソースコードを書いていきます。
はじめに "main.cpp" を開いて、少し Qt の動作を変更しましょう。
#include <QtGui/QApplication>
#include <QTextCodec>
#include "mainwindow.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QTextCodec::setCodecForTr(QTextCodec::codecForLocale());

    MainWindow w;
    w.show();
    return a.exec();
}

Qt Creator のエディタ上に直接日本語文字列を書くと文字化けするので、おまじないを書いておきます。
QTextCodec をインクルードして、

QTextCodec::setCodecForTr(QTextCodec::codecForLocale());

という行を追加してください。他の部分に変更はありません。
これは、tr() という文字コードを多言語対応にするための関数の動作を変更するもので、 tr() で解釈される文字コードを OS の文字コード設定で認識するようにします。


次に "mainwindow.h" を編集します。
ここで追加するのは 19 行目から 20 行目のところです。
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

namespace Ui {
    class MainWindow;
}

class MainWindow : public QMainWindow {
    Q_OBJECT
public:
    MainWindow(QWidget *parent = 0);
    ~MainWindow();

protected:
    void changeEvent(QEvent *e);

private slots:
    void menuSelected();

private:
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H

スロットと呼ばれる、 Qt のイベント処理用メソッドを追加しています。
"スロット" というのは "シグナル" と対に使用するもので、イベント送信側がシグナル、イベント受信側がスロットと呼ばれています。デザインパターン的にはオブザーバーパターンっていうんでしょうか。イベントハンドラと言った方が分かりやすいかもしれませんね。
シグナルは GUI 部品それぞれに最初から組み込まれています。「ボタンが押された時」、「メニューが選択された時」 などのシグナルを発行することができます。


最後に "mainwindow.cpp" を編集します。
編集する箇所は、 "mainwindow.h" で追加した menuSelected() スロットのところと、コンストラクタの中身だけです。


・メニューを作るには、まず各項目を QAction オブジェクトで作成します。
・文字列のセット時は必ず tr() 関数に入れてください。そのまま文字列を使うと文字化けします。
・connect() 関数でシグナルとスロット (イベントとイベントハンドラ) を接続します。
・シグナルとスロットは、 SIGNAL() マクロ、 SLOT() マクロを必ず通す必要があります。
・設定できたら、実際にメニューを作成します (45 行目から)。this->menuBar() でウインドウのメニューバーを取得します。

メニューが選択された時に呼び出されるスロット (menuSelected) では、 sender() 関数を使ってシグナルの送信元オブジェクトを取得しています。

qobject_cast はキャスト演算子で、オブジェクトを QAction 型にキャストしています。キャストに失敗すると (たぶん) null が返るので、 if (action) で null でないときだけ処理するようにしています。

ui->label というのは "mainwindow.ui" で配置した結果表示用のラベルです。そこに、選択されたメニュー項目の名前を表示するようにしています。


動作確認


これで完成です。お疲れ様でした。
実行ボタンを押すと動作チェックができます。
エラーが出た場合は、ソースコードを見直してみてください。
エラー画面をダブルクリックすると、エディタをエラーの出た行に移動することができます。




動作画面はこんな感じになります。