Qt メモ

2019年8月16日

はじめに

GUI ライブラリ Qt のメモ。

環境

  • Ubuntu 16.04 LTS
  • Anaconda3
  • Qt 5.x (Anaconda3 のものを利用)

Qt を用いたプログラムのコンパイル

プロジェクトのディレクトリを用意し、その中にソースコードを置く。

$ mkdir window
$ mv window.cxx window
$ cd window

qmake を実行。

$ qmake -project

プロジェクトファイル window.pro ができる。

window.pro

TEMPLATE = app
TARGET = window
INCLUDEPATH += .

# Input
SOURCES += window.cxx

以下の内容を追記。

QT += widgets
CONFIG += c++11

1 行目は Qt のウィジットを使うためのモジュールを追加している。2 行目は C++11 を使うための設定である。

オプションなしで qmake を実行。

$ qmake

Makefile ができる。make でコンパイル。

$ make

ウインドウ

ウインドウを表示するプログラム。

window.cxx

#include <QtWidgets>


class Main : public QMainWindow
{
public:
    Main(void)
    {
        setWindowTitle("window");
        resize(320, 240);
        centerOnScreen();
        show();
    }

    void centerOnScreen()
    {
        auto res = QDesktopWidget().screenGeometry();
        move((res.width()/2.) - (frameSize().width()/2.),
                (res.height()/2.) - (frameSize().height()/2.));
    }
};


int main(int argc, char **argv)
{
    QApplication app(argc, argv);
    Main win;
    return app.exec();
}

マウス

mouse.cxx

#include <iostream>
#include <QtWidgets>

using namespace std;


class Main : public QMainWindow
{
public:
    Main()
    {
        setMouseTracking(true);
        setWindowTitle("mouse");
        resize(320, 240);
        show();
    }

    void mouseButtonKind(Qt::MouseButtons buttons)
    {
        if(buttons & Qt::LeftButton){
            cout << "LEFT" << endl;
        }
        if(buttons & Qt::MidButton){
            cout << "MIDDLE" << endl;
        }
        if(buttons & Qt::RightButton){
            cout << "RIGHT" << endl;
        }
    }

    void mousePressEvent(QMouseEvent *e) override
    {
        cout << "BUTTON PRESS" << endl;
        mouseButtonKind(e->buttons());
    }

    void mouseReleaseEvent(QMouseEvent *e) override
    {
        cout << "BUTTON RELEASE" << endl;
        mouseButtonKind(e->buttons());
    }

    void wheelEvent(QWheelEvent *e) override
    {
        cout << "wheel" << endl;
        cout << "(" << e->angleDelta().x() << " " << e->angleDelta().y() << ")" << endl;
    }

    void mouseMoveEvent(QMouseEvent *e) override
    {
        cout << "(" << e->x() << " " << e->y() << ")" << endl;
    }
};


int main(int argc, char **argv)
{
    QApplication app(argc, argv);
    Main win;
    return app.exec();
}

キー入力

key.cxx

#include <iostream>
#include <algorithm>
#include <QtWidgets>

using namespace std;


class Main : public QMainWindow
{
public:
    Main()
    {
        setWindowTitle("key");
        resize(320, 240);
        show();
    }

    bool isPrintable(Qt::Key key)
    {
        auto printable = {
            Qt::Key_Space,
            Qt::Key_Exclam,
            Qt::Key_QuoteDbl,
            Qt::Key_NumberSign,
            Qt::Key_Dollar,
            Qt::Key_Percent,
            Qt::Key_Ampersand,
            Qt::Key_Apostrophe,
            Qt::Key_ParenLeft,
            Qt::Key_ParenRight,
            Qt::Key_Asterisk,
            Qt::Key_Plus,
            Qt::Key_Comma,
            Qt::Key_Minus,
            Qt::Key_Period,
            Qt::Key_Slash,
            Qt::Key_0,
            Qt::Key_1,
            Qt::Key_2,
            Qt::Key_3,
            Qt::Key_4,
            Qt::Key_5,
            Qt::Key_6,
            Qt::Key_7,
            Qt::Key_8,
            Qt::Key_9,
            Qt::Key_Colon,
            Qt::Key_Semicolon,
            Qt::Key_Less,
            Qt::Key_Equal,
            Qt::Key_Greater,
            Qt::Key_Question,
            Qt::Key_At,
            Qt::Key_A,
            Qt::Key_B,
            Qt::Key_C,
            Qt::Key_D,
            Qt::Key_E,
            Qt::Key_F,
            Qt::Key_G,
            Qt::Key_H,
            Qt::Key_I,
            Qt::Key_J,
            Qt::Key_K,
            Qt::Key_L,
            Qt::Key_M,
            Qt::Key_N,
            Qt::Key_O,
            Qt::Key_P,
            Qt::Key_Q,
            Qt::Key_R,
            Qt::Key_S,
            Qt::Key_T,
            Qt::Key_U,
            Qt::Key_V,
            Qt::Key_W,
            Qt::Key_X,
            Qt::Key_Y,
            Qt::Key_Z,
            Qt::Key_BracketLeft,
            Qt::Key_Backslash,
            Qt::Key_BracketRight,
            Qt::Key_AsciiCircum,
            Qt::Key_Underscore,
            Qt::Key_QuoteLeft,
            Qt::Key_BraceLeft,
            Qt::Key_Bar,
            Qt::Key_BraceRight,
            Qt::Key_AsciiTilde,
        };

        auto ib = printable.begin();
        auto ie = printable.end();

        if(::find(ib, ie, key) != ie){
            return true;
        }else{
            return false;
        }
    }

    void keyPressEvent(QKeyEvent *e) override
    {
        auto control = false;

        if(e->modifiers() & Qt::ControlModifier){
            cout << "Control" << endl;
            control = true;
        }

        if(e->modifiers() & Qt::ShiftModifier){
            cout << "Shift" << endl;
        }

        if(e->modifiers() & Qt::AltModifier){
            cout << "Alt" << endl;
        }

        if(e->key() == Qt::Key_Delete){
            cout << "Delete" << endl;
        }else if(e->key() == Qt::Key_Backspace){
            cout << "Backspace" << endl;
        }else if(e->key() == Qt::Key_Return ||
                 e->key() == Qt::Key_Enter){
            cout << "Enter" << endl;
        }else if(e->key() == Qt::Key_Escape){
            cout << "Escape" << endl;
        }else if(e->key() == Qt::Key_Right){
            cout << "Right" << endl;
        }else if(e->key() == Qt::Key_Left){
            cout << "Left" << endl;
        }else if(e->key() == Qt::Key_Up){
            cout << "Up" << endl;
        }else if(e->key() == Qt::Key_Down){
            cout << "Down" << endl;
        }

        if(!control && isPrintable((Qt::Key)e->key())){
            cout << qPrintable(e->text()) << endl;
        }
    }
};


int main(int argc, char **argv)
{
    QApplication app(argc, argv);
    Main win;
    return app.exec();
}

メニュー

menu.cxx

#include <iostream>
#include <QtWidgets>

using namespace std;


class Main : public QMainWindow
{
public:
    Main()
    {
        auto exitAction = new QAction("&Exit", this);
        exitAction->setShortcut(tr("Ctrl+Q"));
        connect(exitAction, &QAction::triggered, this, qApp->quit);

        auto doAction = new QAction("&Do", this);
        connect(doAction, &QAction::triggered, this, &Main::doSubmenu);

        auto menubar = menuBar();

        auto fileMenu = menubar->addMenu("&File");
        auto subMenu = fileMenu->addMenu("&Sub");
        subMenu->addAction(doAction);

        fileMenu->addSeparator();
        fileMenu->addAction(exitAction);

        setWindowTitle("menu");
        show();
    }

    void doSubmenu()
    {
        cout << "Do" << endl;
    }
};


int main(int argc, char **argv)
{
    QApplication app(argc, argv);
    Main win;
    return app.exec();
}

ポップアップメニュー

popup.cxx

#include <QtWidgets>


class Main : public QMainWindow
{
public:
    Main()
    {
        setWindowTitle("popup");
        resize(320, 240);
        show();
    }

    void contextMenuEvent(QContextMenuEvent *e) override
    {
        QMenu menu(this);
        auto aQuit = menu.addAction("Quit");
        auto action = menu.exec(e->globalPos());

        if(action == aQuit){
            qApp->quit();
        }
    }
};


int main(int argc, char **argv)
{
    QApplication app(argc, argv);
    Main win;
    return app.exec();
}

ファイルの選択

#include <iostream>
#include <QtWidgets>

using namespace std;


class Main : public QMainWindow
{
public:
    Main()
    {
        auto exitAction = new QAction("&Exit", this);
        exitAction->setShortcut(tr("Ctrl+Q"));
        connect(exitAction, &QAction::triggered, this, qApp->quit);

        auto openAction = new QAction("&Open", this);
        openAction->setShortcut(tr("Ctrl+O"));
        connect(openAction, &QAction::triggered, this, &Main::open);

        auto saveAction = new QAction("&Save", this);
        saveAction->setShortcut(tr("Ctrl+S"));
        connect(saveAction, &QAction::triggered, this, &Main::save);

        auto menubar = menuBar();

        auto fileMenu = menubar->addMenu("&File");
        fileMenu->addAction(openAction);
        fileMenu->addAction(saveAction);

        fileMenu->addSeparator();
        fileMenu->addAction(exitAction);

        setWindowTitle("file select");
        show();
    }

    void open()
    {
        auto filename = QFileDialog::getOpenFileName(this, "Open File",
                nullptr, "C++ Files (*.cxx)");
        if(filename != ""){
            cout << qPrintable(filename) << endl;
        }

//        auto path = QFileDialog::getExistingDirectory(this, "Open Directory",
//                "", QFileDialog::DontUseNativeDialog);
//        if(path != ""){
//            cout << qPrintable(path) << endl;
//        }
    }

    void save()
    {
//        auto filename = QFileDialog::getSaveFileName(this, "Save File",
//                nullptr, "C++ Files (*.cxx)");
//        if(filename != ""){
//            cout << qPrintable(filename) << endl;
//        }

        QFileDialog dialog(this);
        dialog.setWindowTitle("Save File");
        dialog.setNameFilters({"C++ Files (*.cxx)", "All Files (*)"});
        if(dialog.exec()){
            auto filenames = dialog.selectedFiles();
            cout << qPrintable(filenames[0]) << endl;
        }
    }
};


int main(int argc, char **argv)
{
    QApplication app(argc, argv);
    Main win;
    return app.exec();
}

ツールバー

tool_bar.cxx

#include <iostream>
#include <QtWidgets>

using namespace std;


class Main : public QMainWindow
{
public:
    Main()
    {
        auto toolbar = addToolBar("");
        auto aButtonIcon = new QAction(
                style()->standardIcon(QStyle::SP_DirOpenIcon),
                "button",
                this);

        //aButtonIcon->setCheckable(true);

        connect(aButtonIcon, &QAction::triggered, this,
                &Main::buttonIconPress);
        toolbar->addAction(aButtonIcon);

        setWindowTitle("tool bar");
        resize(320, 240);
        show();
    }

    void buttonIconPress(bool active)
    {
        if(active){
            cout << "Active: TRUE" << endl;
        }else{
            cout << "Active: FALSE" << endl;
        }
    }
};


int main(int argc, char **argv)
{
    QApplication app(argc, argv);
    Main win;
    return app.exec();
}

ボタン

button.cxx

#include <iostream>
#include <QtWidgets>

using namespace std;


class Main : public QDialog
{
public:
    Main()
    {
        auto button = new QPushButton("Button");
        connect(button, &QPushButton::clicked, this, &Main::buttonClicked);

        auto layout = new QVBoxLayout();
        layout->addWidget(button);
        setLayout(layout);

        setWindowTitle("button");
        show();
    }

    void buttonClicked()
    {
        auto obj = (QPushButton *)sender();
        cout << qPrintable(obj->text()) << endl;
    }
};


int main(int argc, char **argv)
{
    QApplication app(argc, argv);
    Main win;
    return app.exec();
}

メッセージボックス

message_box.cxx

#include <iostream>
#include <QtWidgets>

using namespace std;


class Main : public QDialog
{
public:
    Main()
    {
        auto button = new QPushButton("Show message box");
        connect(button, &QPushButton::clicked, this, &Main::buttonClicked);

        auto layout = new QVBoxLayout();
        layout->addWidget(button);
        setLayout(layout);

        setWindowTitle("message box");
        show();
    }

    void buttonClicked()
    {
        auto reply = QMessageBox::question(this, "Message", "Yes/No?",
                QMessageBox::Yes | QMessageBox::No, QMessageBox::No);

        if(reply == QMessageBox::Yes){
            cout << "Yes" << endl;
        }else{
            cout << "No" << endl;
        }
    }
};


int main(int argc, char **argv)
{
    QApplication app(argc, argv);
    Main win;
    return app.exec();
}

チェックボックス

check_box.cxx

#include <iostream>
#include <QtWidgets>

using namespace std;


class Main : public QDialog
{
private:
    QCheckBox *check1;
    QCheckBox *check2;

public:
    Main()
    {
        check1 = new QCheckBox("Check1");
        check2 = new QCheckBox("Check2");
        check1->setChecked(true);

        auto button = new QPushButton("Check");
        connect(button, &QPushButton::clicked, this, &Main::buttonClicked);

        auto layout = new QVBoxLayout();
        layout->addWidget(check1);
        layout->addWidget(check2);
        layout->addWidget(button);
        setLayout(layout);

        setWindowTitle("check box");
        show();
    }

    void buttonClicked()
    {
        cout << "Check1: " << check1->isChecked() << endl;
        cout << "Check2: " << check2->isChecked() << endl;
    }
};


int main(int argc, char **argv)
{
    QApplication app(argc, argv);
    Main win;
    return app.exec();
}

ラジオボタン

radio_button.cxx

#include <iostream>
#include <QtWidgets>

using namespace std;


class Main : public QDialog
{
private:
    QButtonGroup *group;

public:
    Main()
    {
        auto radio1 = new QRadioButton("Radio1");
        auto radio2 = new QRadioButton("Radio2");

        group = new QButtonGroup();
        group->addButton(radio1, 1);
        group->addButton(radio2, 2);
        radio1->toggle();

        auto button = new QPushButton("Check");
        connect(button, &QPushButton::clicked, this, &Main::buttonClicked);

        auto layout = new QVBoxLayout();
        layout->addWidget(radio1);
        layout->addWidget(radio2);
        layout->addWidget(button);
        setLayout(layout);

        setWindowTitle("radio button");
        show();
    }

    void buttonClicked()
    {
        cout << "Radio: " << group->checkedId() << endl;
    }
};


int main(int argc, char **argv)
{
    QApplication app(argc, argv);
    Main win;
    return app.exec();
}

コンボボックス

combo_box.cxx

#include <iostream>
#include <QtWidgets>

using namespace std;


class Main : public QDialog
{
private:
    QComboBox *combo;

public:
    Main()
    {
        auto label = new QLabel("Select");

        combo = new QComboBox(this);
        combo->addItem("apple");
        combo->addItem("banana");
        combo->addItem("lemon");
        combo->addItem("orange");

        auto button = new QPushButton("Check");
        connect(button, &QPushButton::clicked, this, &Main::buttonClicked);

        auto layout = new QVBoxLayout();
        layout->addWidget(label);
        layout->addWidget(combo);
        layout->addWidget(button);
        setLayout(layout);

        setWindowTitle("combo box");
        show();
    }

    void buttonClicked()
    {
        cout << "Combo: " << combo->currentIndex() << " " <<
            qPrintable(combo->currentText()) << endl;
    }
};


int main(int argc, char **argv)
{
    QApplication app(argc, argv);
    Main win;
    return app.exec();
}

入力

input.cxx

#include <iostream>
#include <QtWidgets>

using namespace std;


class Main : public QDialog
{
private:
    QLineEdit *edit;

public:
    Main()
    {
        auto label = new QLabel("Input");
        edit = new QLineEdit();

        auto button = new QPushButton("Check");
        connect(button, &QPushButton::clicked, this, &Main::buttonClicked);

        auto layout = new QVBoxLayout();
        layout->addWidget(label);
        layout->addWidget(edit);
        layout->addWidget(button);
        setLayout(layout);

        setWindowTitle("input");
        show();
    }

    void buttonClicked()
    {
        cout << qPrintable(edit->text()) << endl;
    }
};


int main(int argc, char **argv)
{
    QApplication app(argc, argv);
    Main win;
    return app.exec();
}

テキスト

#include <iostream>
#include <QtWidgets>

using namespace std;


class Main : public QDialog
{
private:
    QTextEdit *text;

public:
    Main()
    {
        text = new QTextEdit();

        auto button = new QPushButton("Check");
        connect(button, &QPushButton::clicked, this, &Main::buttonClicked);

        auto layout = new QVBoxLayout();
        layout->addWidget(text);
        layout->addWidget(button);
        setLayout(layout);

        setWindowTitle("text");
        show();
    }

    void buttonClicked()
    {
        cout << qPrintable(text->toPlainText()) << endl;
    }
};


int main(int argc, char **argv)
{
    QApplication app(argc, argv);
    Main win;
    return app.exec();
}

テーブル

table.cxx

#include <iostream>
#include <QtWidgets>

using namespace std;


class Main : public QDialog
{
private:
    QTableWidget *table;

public:
    Main()
    {
        table = new QTableWidget(2, 3);

        QStringList header = {"A", "B", "C"};
        QStringList data[3] = {{"apple", "1", "100"}, {"banana", "2", "200"}};

        table->setHorizontalHeaderLabels(header);

        for(int i = 0; i < data->size(); i++){
            for(int j = 0; j < data[i].size(); j++){
                table->setItem(i, j, new QTableWidgetItem(data[i][j]));
            }
        }

        auto button = new QPushButton("Check");
        connect(button, &QPushButton::clicked, this, &Main::buttonClicked);

        auto layout = new QVBoxLayout();
        layout->addWidget(table);
        layout->addWidget(button);
        setLayout(layout);

        setWindowTitle("table");
        show();
    }

    void buttonClicked()
    {
        for(int i = 0; i < table->rowCount(); i++){
            for(int j = 0; j < table->columnCount(); j++){
                cout << qPrintable(table->item(i, j)->text()) << " ";
            }
            cout << endl;
        }
    }
};


int main(int argc, char **argv)
{
    QApplication app(argc, argv);
    Main win;
    return app.exec();
}

リスト

list.cxx

#include <iostream>
#include <QtWidgets>

using namespace std;


class Main : public QDialog
{
private:
    QListWidget *listWidget;

public:
    Main()
    {
        listWidget = new QListWidget();

        listWidget->addItem("apple");
        listWidget->addItem("banana");
        listWidget->addItem("lemon");
        listWidget->addItem("orange");

        auto button = new QPushButton("Check");
        connect(button, &QPushButton::clicked, this, &Main::buttonClicked);

        auto layout = new QVBoxLayout();
        layout->addWidget(listWidget);
        layout->addWidget(button);
        setLayout(layout);

        setWindowTitle("list");
        show();
    }

    void buttonClicked()
    {
        for(int i = 0; i < listWidget->count(); i++){
            cout << qPrintable(listWidget->item(i)->text()) << endl;
        }
    }
};


int main(int argc, char **argv)
{
    QApplication app(argc, argv);
    Main win;
    return app.exec();
}

ツリー

tree.cxx

#include <iostream>
#include <QtWidgets>

using namespace std;


class Main : public QDialog
{
private:
    QTreeWidget *treeWidget;

public:
    Main()
    {
        treeWidget = new QTreeWidget();
        treeWidget->setAlternatingRowColors(true);

        auto branch1 = new QTreeWidgetItem();
        branch1->setText(0, "branch1");

        auto branch2 = new QTreeWidgetItem();
        branch2->setText(0, "branch2");

        addItem(branch1, "apple", 1, 100);
        addItem(branch1, "banana", 2, 100);
        addItem(branch2, "lemon", 3, 100);
        addItem(branch2, "orange", 4, 100);

        treeWidget->addTopLevelItem(branch1);
        treeWidget->addTopLevelItem(branch2);
        treeWidget->setColumnCount(3);
        treeWidget->setHeaderLabels({"A", "B", "C"});

        branch1->setExpanded(true);
        branch2->setExpanded(true);

        auto button = new QPushButton("Check");
        connect(button, &QPushButton::clicked, this, &Main::buttonClicked);

        auto layout = new QVBoxLayout();
        layout->addWidget(treeWidget);
        layout->addWidget(button);
        setLayout(layout);

        setWindowTitle("tree");
        show();
    }

    void addItem(QTreeWidgetItem *branch, string name, int num, int num2)
    {
        auto item = new QTreeWidgetItem(branch);
        item->setFlags(item->flags() | Qt::ItemIsEditable);
        item->setText(0, QString::fromStdString(name));
        item->setText(1, QString::number(num));
        item->setText(2, QString::number(num2));
    }

    void buttonClicked()
    {
        for(int i = 0; i < treeWidget->topLevelItemCount(); i++){
            auto branch = treeWidget->topLevelItem(i);
            cout << qPrintable(branch->text(0)) << endl;
            for(int j = 0; j < branch->childCount(); j++){
                auto item = branch->child(j);
                cout << " ";
                for(int k = 0; k < item->columnCount(); k++){
                    cout << qPrintable(item->text(k)) << " ";
                }
                cout << endl;
            }
        }

        cout << "find: lemon" << endl;
        auto items = treeWidget->findItems("lemon", Qt::MatchRecursive);
        auto item = items[0];
        cout << " ";
        for(int k = 0; k < item->columnCount(); k++){
            cout << qPrintable(item->text(k)) << " ";
        }
        cout << endl;
    }
};


int main(int argc, char **argv)
{
    QApplication app(argc, argv);
    Main win;
    return app.exec();
}

チェックボックス付きツリー

check_tree.cxx

#include <iostream>
#include <QtWidgets>

using namespace std;


class Main : public QDialog
{
private:
    QTreeWidget *treeWidget;

public:
    Main()
    {
        treeWidget = new QTreeWidget();
        treeWidget->setAlternatingRowColors(true);

        treeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
        connect(treeWidget, &QTreeWidget::customContextMenuRequested,
                this, &Main::contextMenu);

        auto branch1 = new QTreeWidgetItem();
        branch1->setData(0, Qt::CheckStateRole, Qt::Checked);
        branch1->setText(0, "branch1");

        auto branch2 = new QTreeWidgetItem();
        branch2->setData(0, Qt::CheckStateRole, Qt::Checked);
        branch2->setText(0, "branch2");

        addItem(branch1, "apple", 1, 100);
        addItem(branch1, "banana", 2, 100);
        addItem(branch2, "lemon", 3, 100);
        addItem(branch2, "orange", 4, 100);

        treeWidget->addTopLevelItem(branch1);
        treeWidget->addTopLevelItem(branch2);
        treeWidget->setColumnCount(3);
        treeWidget->setHeaderLabels({"A", "B", "C"});

        connect(treeWidget, &QTreeWidget::itemClicked, this, &Main::selectItem);
        connect(treeWidget, &QTreeWidget::itemChanged, this, &Main::changedItem);

        branch1->setExpanded(true);
        branch2->setExpanded(true);

        auto layout = new QVBoxLayout();
        layout->addWidget(treeWidget);
        setLayout(layout);

        setWindowTitle("check tree");
        show();
    }

    void addItem(QTreeWidgetItem *branch, string name, int num, int num2)
    {
        auto item = new QTreeWidgetItem(branch);
        item->setData(0, Qt::CheckStateRole, Qt::Checked);
        item->setText(0, QString::fromStdString(name));
        item->setText(1, QString::number(num));
        item->setText(2, QString::number(num2));
    }

    void selectItem()
    {
        if(treeWidget->selectedItems().size() == 0){
            return;
        }
        auto item = treeWidget->selectedItems()[0];
        cout << qPrintable(item->text(0)) << endl;
    }

    void changedItem(QTreeWidgetItem *item)
    {
        if(item->childCount() > 0){
            checkBranch(item, item->checkState(0));
        }

        for(int i = 0; i < treeWidget->topLevelItemCount(); i++){
            auto branch = treeWidget->topLevelItem(i);
            cout << qPrintable(branch->text(0));
            for(int j = 0; j < branch->childCount(); j++){
                auto item = branch->child(j);
                if(item->checkState(0)){
                    cout << " ";
                    for(int k = 0; k < item->columnCount(); k++){
                        cout << qPrintable(item->text(k)) << " ";
                    }
                    cout << endl;
                }
            }
        }
    }

    void checkBranch(QTreeWidgetItem *branch, Qt::CheckState check=Qt::Checked){
        for(int i = 0; i < branch->childCount(); i++){
            auto item = branch->child(i);
            item->setCheckState(0, check);
        }
    }

    void checkAll(Qt::CheckState check=Qt::Checked){
        for(int i = 0; i < treeWidget->topLevelItemCount(); i++){
            auto branch = treeWidget->topLevelItem(i);
            branch->setCheckState(0, check);
            checkBranch(branch, check);
        }
    }

    void contextMenu(const QPoint &point){
        QMenu menu;
        auto check_all = menu.addAction("Check all");
        auto uncheck_all = menu.addAction("Uncheck all");

        auto action = menu.exec(mapToGlobal(point));

        if(action == check_all){
            checkAll();
        }else if(action == uncheck_all){
            checkAll(Qt::Unchecked);
        }
    }
};


int main(int argc, char **argv)
{
    QApplication app(argc, argv);
    Main win;
    return app.exec();
}

タブ

tab.cxx

#include <iostream>
#include <QtWidgets>

using namespace std;


class RadioWidget : public QWidget
{
    QButtonGroup *group;

public:
    RadioWidget(QWidget *parent)
        : QWidget(parent)
    {
        auto radio1 = new QRadioButton("Radio1");
        auto radio2 = new QRadioButton("Radio2");

        group = new QButtonGroup();
        group->addButton(radio1, 1);
        group->addButton(radio2, 2);
        radio1->toggle();

        auto button = new QPushButton("Check");
        connect(button, &QPushButton::clicked, this,
                &RadioWidget::buttonClicked);

        auto layout = new QVBoxLayout();
        layout->addWidget(radio1);
        layout->addWidget(radio2);
        layout->addWidget(button);
        setLayout(layout);
    }

    void buttonClicked(){
        cout << "Radio: " << group->checkedId() << endl;
    }
};


class CheckWidget : public QWidget
{
    QCheckBox *check1;
    QCheckBox *check2;

public:
    CheckWidget(QWidget *parent)
        : QWidget(parent)
    {
        check1 = new QCheckBox("Check1");
        check2 = new QCheckBox("Check2");
        check1->setChecked(true);

        auto button = new QPushButton("Check");
        connect(button, &QPushButton::clicked, this,
                &CheckWidget::buttonClicked);

        auto layout = new QVBoxLayout();
        layout->addWidget(check1);
        layout->addWidget(check2);
        layout->addWidget(button);
        setLayout(layout);
    }

    void buttonClicked(){
        cout << "Check1: " << check1->isChecked() << endl;
        cout << "Check2: " << check2->isChecked() << endl;
    }
};


class ComboWidget : public QWidget
{
    QComboBox *combo;

public:
    ComboWidget(QWidget *parent)
        : QWidget(parent)
    {
        auto label = new QLabel("Select");

        combo = new QComboBox(this);
        combo->addItem("apple");
        combo->addItem("banana");
        combo->addItem("lemon");
        combo->addItem("orange");

        auto button = new QPushButton("Check");
        connect(button, &QPushButton::clicked, this,
                &ComboWidget::buttonClicked);

        auto layout = new QVBoxLayout();
        layout->addWidget(label);
        layout->addWidget(combo);
        layout->addWidget(button);
        setLayout(layout);
    }

    void buttonClicked(){
        cout << "Combo: " << combo->currentIndex()
             << ", " << qPrintable(combo->currentText()) << endl;
    }
};


class Main : public QWidget
{
public:
    Main()
    {
        auto widget1 = new RadioWidget(this);
        auto widget2 = new CheckWidget(this);
        auto widget3 = new ComboWidget(this);

        auto tab = new QTabWidget();
        tab->addTab(widget1, "radio");
        tab->addTab(widget2, "check");
        tab->addTab(widget3, "combo");

        auto layout = new QHBoxLayout(this);
        layout->addWidget(tab);

        setWindowTitle("tab");
        show();
    }
};


int main(int argc, char **argv)
{
    QApplication app(argc, argv);
    Main win;
    return app.exec();
}

ウインドウの分割

splitter.cxx

#include <iostream>
#include <QtWidgets>

using namespace std;


class RadioFrame : public QFrame
{
    QButtonGroup *group;

public:
    RadioFrame(QWidget *parent)
        : QFrame(parent)
    {
        auto radio1 = new QRadioButton("Radio1");
        auto radio2 = new QRadioButton("Radio2");

        group = new QButtonGroup();
        group->addButton(radio1, 1);
        group->addButton(radio2, 2);
        radio1->toggle();

        auto button = new QPushButton("Check");
        connect(button, &QPushButton::clicked, this,
                &RadioFrame::buttonClicked);

        auto layout = new QVBoxLayout();
        layout->addWidget(radio1);
        layout->addWidget(radio2);
        layout->addWidget(button);
        setLayout(layout);
    }

    void buttonClicked(){
        cout << "Radio: " << group->checkedId() << endl;
    }
};


class CheckFrame : public QFrame
{
    QCheckBox *check1;
    QCheckBox *check2;

public:
    CheckFrame(QWidget *parent)
        : QFrame(parent)
    {
        check1 = new QCheckBox("Check1");
        check2 = new QCheckBox("Check2");
        check1->setChecked(true);

        auto button = new QPushButton("Check");
        connect(button, &QPushButton::clicked, this,
                &CheckFrame::buttonClicked);

        auto layout = new QVBoxLayout();
        layout->addWidget(check1);
        layout->addWidget(check2);
        layout->addWidget(button);
        setLayout(layout);
    }

    void buttonClicked(){
        cout << "Check1: " << check1->isChecked() << endl;
        cout << "Check2: " << check2->isChecked() << endl;
    }
};


class ComboFrame : public QFrame
{
    QComboBox *combo;

public:
    ComboFrame(QWidget *parent)
        : QFrame(parent)
    {
        auto label = new QLabel("Select");

        combo = new QComboBox(this);
        combo->addItem("apple");
        combo->addItem("banana");
        combo->addItem("lemon");
        combo->addItem("orange");

        auto button = new QPushButton("Check");
        connect(button, &QPushButton::clicked, this,
                &ComboFrame::buttonClicked);

        auto layout = new QVBoxLayout();
        layout->addWidget(label);
        layout->addWidget(combo);
        layout->addWidget(button);
        setLayout(layout);
    }

    void buttonClicked(){
        cout << "Combo: " << combo->currentIndex()
             << ", " << qPrintable(combo->currentText()) << endl;
    }
};


class Main : public QWidget
{
public:
    Main()
    {
        auto hbox = new QHBoxLayout(this);

        auto frame1 = new RadioFrame(this);
        frame1->setFrameShape(QFrame::Panel);

        auto frame2 = new CheckFrame(this);
        frame2->setFrameShape(QFrame::Panel);

        auto splitter1 = new QSplitter(Qt::Horizontal);
        splitter1->addWidget(frame1);
        splitter1->addWidget(frame2);
        splitter1->setHandleWidth(10);

        auto frame3 = new ComboFrame(this);
        frame3->setFrameShape(QFrame::Panel);

        auto splitter2 = new QSplitter(Qt::Vertical);
        splitter2->addWidget(splitter1);
        splitter2->addWidget(frame3);

        hbox->addWidget(splitter2);
        setLayout(hbox);

        setWindowTitle("splitter");
        show();
    }
};


int main(int argc, char **argv)
{
    QApplication app(argc, argv);
    Main win;
    return app.exec();
}

グリッドレイアウト

grid_layout.cxx

#include <iostream>
#include <QtWidgets>

using namespace std;


class Main : public QDialog
{
    QLineEdit *edit;

public:
    Main()
    {
        auto label = new QLabel("Input");
        edit = new QLineEdit();

        auto button = new QPushButton("Check");
        connect(button, &QPushButton::clicked, this, &Main::buttonClicked);

        auto layout = new QGridLayout();
        layout->setSpacing(10);
        layout->addWidget(label, 0, 0);
        layout->addWidget(edit, 0, 1);
        layout->addWidget(button, 1, 0, 1, 2);

        setLayout(layout);

        setWindowTitle("grid layout");
        show();
    }

    void buttonClicked()
    {
        cout << qPrintable(edit->text()) << endl;
    }
};


int main(int argc, char **argv)
{
    QApplication app(argc, argv);
    Main win;
    return app.exec();
}

絵の描画

draw.cxx

#include <QtWidgets>


class Main : public QMainWindow
{
public:
    Main()
    {
        setWindowTitle("draw");
        resize(320, 240);
        centerOnScreen();
        show();
    }

    void centerOnScreen()
    {
        auto res = QDesktopWidget().screenGeometry();
        move((res.width()/2.) - (frameSize().width()/2.),
                (res.height()/2.) - (frameSize().height()/2.));
    }

    void paintEvent(QPaintEvent *e) override
    {
        (void)e;

        auto w = frameSize().width();
        auto h = frameSize().height();

        QPainter painter(this);
        painter.setPen(Qt::white);
        painter.setBrush(Qt::white);
        painter.drawRect(0, 0, w, h);

        QPen pen(Qt::black);
        pen.setWidth(2);
        painter.setPen(pen);
        for(int y = 0; y < (int)(240./5.); y++){
            painter.drawPoint(20, y*5);
        }

        painter.setPen(Qt::red);
        painter.setBrush(Qt::red);
        painter.drawRect(50, 50, 100, 50);

        painter.setPen(QColor(0, 0, 255));
        painter.setBrush(QColor(0, 0, 255, 128));
        painter.drawRect(80, 80, 100, 60);

        QPen pen2(Qt::DashLine | Qt::black);
        pen2.setWidth(2);
        painter.setPen(pen2);
        painter.setBrush(QColor(0, 0, 0, 0));
        painter.drawEllipse(130, 156, 100, 50);

        painter.setPen(Qt::black);
        painter.setFont(QFont("SansSerif", 24));
        painter.drawText(200, 100, "Text");
    }
};


int main(int argc, char **argv)
{
    QApplication app(argc, argv);
    Main win;
    return app.exec();
}

タイマー

timer.cxx

#include <iostream>
#include <QtWidgets>

using namespace std;


class Main : public QMainWindow
{
    QTimer *timer;

public:
    Main()
    {
        timer = new QTimer(this);
        connect(timer, &QTimer::timeout, this, &Main::update);
        timer->start(1000); // msec

        setWindowTitle("timer");
        resize(320, 240);
        show();
    }

    void update()
    {
        cout << "*" << endl;
    }
};


int main(int argc, char **argv)
{
    QApplication app(argc, argv);
    Main win;
    return app.exec();
}

matplotlib の利用

Python モジュール matplotlib を使いたい。そのために、Python の呼び出しを行う。Qt の GUI に組み込む方法としては、グラフの絵を作ってそれを貼り付ける方法をとる。

plot.pro に Python の設定を追加。

INCLUDEPATH += /home/xxxx/anaconda3/include/python3.6m
LIBS += -L/home/xxxx/anaconda3/lib -lpython3.6m

plot.cxx

#include <iostream>
#include <vector>
#include <Python.h>
#include <QtWidgets>

using namespace std;


PyObject* getString(const string str)
{
    return PyUnicode_FromString(str.c_str());
}


PyObject* getFloat(double v)
{
    return PyFloat_FromDouble(v);
}


PyObject* getArray(const vector<double> array)
{
    auto ret = PyList_New(array.size());
    for(int i = 0; i < (int)array.size(); i++){
        PyList_SetItem(ret, i, getFloat(array[i]));
    }
    return ret;
}


PyObject* importModule(const string name)
{
    auto module = PyImport_ImportModule(name.c_str());

    if(!module){
        throw runtime_error("Error loading module " + name);
    }

    return module;
}


PyObject* getAttr(PyObject* obj, const string name)
{
    auto attr = PyObject_GetAttrString(obj, name.c_str());

    if(!attr){
        throw runtime_error("Error get " + name);
    }

    return attr;
}


PyObject* callFunction(
        PyObject* obj,
        const string name,
        PyObject* args = Py_BuildValue("()"),
        PyObject* keywords = nullptr
)
{
    auto func = getAttr(obj, name);
    auto res = PyObject_Call(func, args, keywords);

    if(!res){
        throw runtime_error("Error call function " + name);
    }

    Py_DECREF(args);

    if(keywords){
        Py_DECREF(keywords);
    }

    return res;
}


class Main : public QDialog
{
public:
    Main()
    {
        Py_Initialize();

        PyObject *res;

        auto mod_plt = importModule("matplotlib.pyplot");

        auto mod_seaborn = importModule("seaborn");
        res = callFunction(mod_seaborn, "set");
        Py_DECREF(res);

        auto mod_io = importModule("io");

        res = callFunction(mod_plt, "figure",
                Py_BuildValue("()"),
                Py_BuildValue("{s:(i, i), s:i}", "figsize", 8, 6, "dpi", 80));
        Py_DECREF(res);

        vector<double> x;
        vector<double> y;
        for(double v = 0.; v <= 2.*M_PI; v += 0.1){
            x.push_back(v);
            y.push_back(sin(v));
        }

        res = callFunction(mod_plt, "plot",
                Py_BuildValue("(N, N)", getArray(x), getArray(y)),
                Py_BuildValue("{s:s}", "label", "sin"));
        Py_DECREF(res);

        res = callFunction(mod_plt, "xlabel", Py_BuildValue("(s)", "x"));
        Py_DECREF(res);

        res = callFunction(mod_plt, "ylabel", Py_BuildValue("(s)", "y"));
        Py_DECREF(res);

        res = callFunction(mod_plt, "legend");
        Py_DECREF(res);

        auto output = callFunction(mod_io, "BytesIO");

        res = callFunction(mod_plt, "savefig",
                Py_BuildValue("(O)", output),
                Py_BuildValue("{s:s}", "format", "png"));
        Py_DECREF(res);

        auto data = callFunction(output, "getvalue");
        unsigned char *s;
        Py_ssize_t len;
        PyBytes_AsStringAndSize(data, (char **)&s, &len);

        auto image = new QImage();
        image->loadFromData(s, len, "png");

        auto label = new QLabel();
        label->setPixmap(QPixmap::fromImage(*image));

        auto layout = new QVBoxLayout();
        layout->addWidget(label);

        setLayout(layout);

        setWindowTitle("plot");
        show();
    }
};


int main(int argc, char **argv)
{

    QApplication app(argc, argv);
    Main win;

    return app.exec();
}

VTK の利用

VTK ライブラリは別途コンパイルしておく。VTK を用いたプログラムのコンパイルには、cmake を用いる。そのために CMakeLists.txt を用意する。

CMakeLists.txt

cmake_minimum_required(VERSION 2.8)

find_package(VTK REQUIRED)
include(${VTK_USE_FILE})

find_package(Qt5Widgets REQUIRED)

file(GLOB CXX_FILES *.cxx)

add_executable(qvtk ${CXX_FILES})
target_link_libraries(qvtk ${VTK_LIBRARIES} ${Qt5Widgets_LIBRARIES})

qvtk.cxx

#include <QtWidgets>
#include <QVTKOpenGLWidget.h>
#include <vtkSmartPointer.h>
#include <vtkCylinderSource.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkProperty.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkCamera.h>
#include <vtkRenderWindowInteractor.h>


class Main : public QMainWindow
{
public:
    Main()
    {
        // source
        auto cylinder = vtkSmartPointer<vtkCylinderSource>::New();
        cylinder->SetResolution(20);

        // mapper
        auto mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
        mapper->SetInputConnection(cylinder->GetOutputPort());

        // actor
        auto actor = vtkSmartPointer<vtkActor>::New();
        actor->SetMapper(mapper);
        actor->GetProperty()->SetColor(1., .3882, .2784 );
        actor->RotateX(30.);
        actor->RotateY(-45.);

        // renderer
        auto ren = vtkSmartPointer<vtkRenderer>::New();
        ren->AddActor(actor);
        ren->SetBackground(0.1, 0.2, 0.4);

        // QVTK widget
        auto qvtk = new QVTKOpenGLWidget();

        auto renWin = qvtk->GetRenderWindow();
        renWin->AddRenderer(ren);

        auto inter = qvtk->GetInteractor();

        ren->ResetCamera();
        ren->GetActiveCamera()->Zoom(1.5);

        renWin->Render();
        inter->Initialize();

        auto layout = new QVBoxLayout();
        layout->addWidget(qvtk);

        auto frame = new QFrame();
        frame->setLayout(layout);
        setCentralWidget(frame);

        setWindowTitle("qvtk");
        resize(320, 240);
        centerOnScreen();
        show();
    }

    void centerOnScreen()
    {
        auto res = QDesktopWidget().screenGeometry();
        move((res.width()/2.) - (frameSize().width()/2.),
                (res.height()/2.) - (frameSize().height()/2.));
    }
};


int main(int argc, char **argv)
{
    QApplication app(argc, argv);
    Main win;
    return app.exec();
}

コンパイル

$ mkdir build
$ cd build
$ cmake ..
$ make