Qt5.3 で SIGNALの振り分け

ボタングループを用いて排他的なボタンを作成することに成功したのですが、ボタンを押す毎に、そのボタンに応じた個別の処理をしたいのです。それにはもちろん Qt Framework独自の SIGNAL/SLOTを用いるのですが、これがなかかな難しい このページには詳細な解説があり、数通りのやり方があるようですが、内容が難しいのです 一番理解し易い sender()を用いることにしました

#ifndef MYMAINWINDOW_H
#define MYMAINWINDOW_H

#include <QMainWindow>
#include <QtGui>
#include <QtWidgets>

class MyMainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MyMainWindow(QWidget *parent = 0);
    ~MyMainWindow();
    QCheckBox *chk[4];
public slots:
    void dispatch();
};

#endif // MYMAINWINDOW_H

そしてこれに応じた .cpp fileです

#include "mymainwindow.h"

MyMainWindow::MyMainWindow(QWidget *parent): QMainWindow(parent)
{
    this->resize(400,400);
    QVBoxLayout *layout = new QVBoxLayout();
    QVBoxLayout *layout1 = new QVBoxLayout();
    QGroupBox *group = new QGroupBox(this);
    group->resize(300,300);
    group->setLayout(layout);
    group->setAlignment(Qt::AlignHCenter);
    group->setCheckable(true);
    QButtonGroup *bg = new QButtonGroup(this);
    chk[1] = new QCheckBox();chk[1]->setText("CAG");
    chk[2] = new QCheckBox("PCI", this);
    chk[3] = new QCheckBox("TAVI", this);
    bg->addButton(chk[1]);
    bg->addButton(chk[2]);
    bg->addButton(chk[3]);
    group->setTitle("Cardiology");
    layout1->addWidget(group);
    layout->addWidget(chk[1]);
    layout->addWidget(chk[2]);
    layout->addWidget(chk[3]);
    group->setStyleSheet("*{background-color:rgb(0, 0, 255); padding: 7px ; color:red;}");
    this->setStyleSheet("*{background-color:rgb(150,147,88); padding: 7px ; color:brown}");
    for (int i=1; i<4; i++) {
        connect(chk[i], SIGNAL(clicked()), this, SLOT(dispatch()));
    }
}

MyMainWindow::~MyMainWindow()
{

}

void MyMainWindow::dispatch() {
    QCheckBox *checkbox = (QCheckBox *)sender();
    QString msg = QString::fromStdString(checkbox->text().toStdString());
    msg += " was pushed!";
    QMessageBox *mb = new QMessageBox("Button", msg, QMessageBox::Critical, QMessageBox::Ok
                                      ||QMessageBox::Default, QMessageBox::Cancel||QMessageBox::Escape, 0);
    mb->show();

}

これにより以下のようにボタンに応じた messageboxを表示することができました 正直スマートではなく、ダサい感じしますが、何より動作することが重要ですPCIボタンが押されたTAVIボタンが押された

なあんだ Qt5.3で QButtonGroupと QGroupBoxを用いてタイトルつきボタン組をつくる

ついに解決しました 以下のようにすれば良かったのです

MyMainWindow::MyMainWindow(QWidget *parent): QMainWindow(parent)
{
    this->resize(300,300);
    QVBoxLayout *layout = new QVBoxLayout();
    QVBoxLayout *layout1 = new QVBoxLayout();
    QGroupBox *group = new QGroupBox(this);
    group->resize(300,200);
    group->setLayout(layout);
    group->setAlignment(Qt::AlignHCenter);
    group->setCheckable(true);
    QButtonGroup *bg = new QButtonGroup(this);
    QCheckBox *chk1 = new QCheckBox("CAG");
    QCheckBox *chk2 = new QCheckBox("PCI");
    QCheckBox *chk3 = new QCheckBox("TAVI");
    bg->addButton(chk1);
    bg->addButton(chk2);
    bg->addButton(chk3);
    group->setTitle("Cardiology");
    layout1->addWidget(group);
    layout->addWidget(chk1);
    layout->addWidget(chk2);
    layout->addWidget(chk3);
    group->setStyleSheet("*{background-color:rgb(0, 0, 255); padding: 7px ; color:red;}");
    this->setStyleSheet("*{background-color:rgb(150,147,88); padding: 7px ; color:rgb(255,255,255)}");
}

これで排他的ボタングルーブをタイトルつきで表示および機能させることに成功しました ざっとこんな感じです
Qt5.3 Button Group

Qt5.3で QGroupBoxを用いてボタングルーブを作成する

この方法がスタンダードなようですが、問題は排他的ボタングループを作れず、いくつもチェックできてしまうのです

QVBoxLayout *layout = new QVBoxLayout();
QVBoxLayout *layout1 = new QVBoxLayout();
QGroupBox *group = new QGroupBox(this);
group->resize(300,200);
group->setLayout(layout);
group->setAlignment(Qt::AlignHCenter);
group->setCheckable(true);

QCheckBox *chk1 = new QCheckBox("CAG");
QCheckBox *chk2 = new QCheckBox("PCI");
QCheckBox *chk3 = new QCheckBox("TAVI");
group->setTitle("Cardiology");
layout1->addWidget(group);
layout->addWidget(chk1);
layout->addWidget(chk2);
layout->addWidget(chk3);
this->setStyleSheet("*{background-color:rgb(150,147,88); padding: 7px ; color:rgb(255,255,255)}");

これを用いれば以下のようにいくつものボタンをチェックできてしまいます 排他的ボタンにするメソッドはありませんでした
QGroupBox

Qt5.3でButtonGroupにタイトルをつけるには

Qt4.0以降、QButtonGroupは QWidget派生クラスではなくなったため、QButtonGroup(const *char, *parent=0); というコンストラクタが無くなりました

このため、Qt3まででは簡単にボタングルーブにタイトルつけれたのに、それができなくなったのです これは僕らにしてみれば非常に使いにくくなりました すったもんだの末以下のようにして何とかタイトルつけれるようになりました

    QVBoxLayout *layout = new QVBoxLayout();
    QGroupBox *group = new QGroupBox(this);
    group->resize(200, 100);
    group->setLayout(layout2);
    group->setTitle(tr("Cardiology Fields"));
    group->setCheckable(false);
    this->setStyleSheet("*{background-color:rgb(150,147,88); padding: 7px ; color:rgb(255,255,255)}");

    QButtonGroup *bg = new QButtonGroup(this);
    bg->setExclusive(true);
    QCheckBox *b1 = new QCheckBox(tr("CAG"), this);
    QCheckBox *b2 = new QCheckBox(tr("PCI"), this);
    b1->move(10, 20);
    b2->move(10, 50);
    bg->addButton(b1);
    bg->addButton(b2);

これを実行すると次のようになります なお、QButtonGroupを用いないと排他的ボタングルーブ(どれか一つしかチェックできないもの)を作るのは大変なのですQButtonGroup in Qt5.3

Qt5.3 button group

これも苦労しましたがこれで可能です

MyMainWindow::MyMainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    setGeometry(100, 100, 150, 140);
    group = new QButtonGroup(this);
    b1 = new QCheckBox("Check1", this);
    b1->move(20, 20);
    b2 = new QCheckBox("Check2", this);
    b2->move(20, 50);
    b3 = new QCheckBox("Check3", this);
    b3->move(20, 80);
    group->addButton(b1);
    group->addButton(b2);
    group->addButton(b3);
}

これで以下のようなボタングルーブが作成され、排他的に選択可能となります
button group

Qt 4.0より廃止

Qtプログラミング 24時間集中講座という2001年発売の訳書を読んでいます なかなか良い内容なのですが、何しろ10年以上前の内容なので なかなか大変です

そこでは普通に書かれている setMainWindow()という関数が現在使用していする Qt5.3ではエラーになります Googleしてみると、どうやらこの関数は Qt 3.0までで、4.0以降は廃止されたらしいのです だって当たり前に main windowとなるので不要、という考えのようです というわけで簡単なプログラムボタンを押せばこのプログラムが終了するというものがかけました

#ifndef MYMAINWINDOW_H
#define MYMAINWINDOW_H

#include <QMainWindow>
#include <QtWidgets>
#include <QtGui>

class MyMainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MyMainWindow(QWidget *parent = 0);
    ~MyMainWindow();
private:
    QPushButton *b1;
};

#endif // MYMAINWINDOW_H


#include "mymainwindow.h"

MyMainWindow::MyMainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    setGeometry(10, 100, 200, 120);
    b1 = new QPushButton("This is a Button", this);
    b1->setGeometry(20, 20, 160, 80);
    b1->setFont(QFont("Times", 24, QFont::Bold));
    connect(b1, SIGNAL(clicked()), qApp, SLOT(quit()));
}

MyMainWindow::~MyMainWindow()
{

}


#include "mymainwindow.h"
#include <QApplication>
#include <QtWidgets>
#include <QtGui>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MyMainWindow w;

    w.show();

    return a.exec();
}

お盆の季節はとても忙しい

何でしょうか 会社が休みだからでしょうか あるいは クリニックの多くもお休みをとられているからでしょうか まあその両方でしょうか この季節 外来診療をやっているととても忙しく また重症例が多いのです 今日の僕の外来診療だけでも入院指示どうでしょうか 20名ぐらいに発行しました その内の 3例は今日緊急入院です 一人は冠動脈にステントが入り、一人は巨大な易破裂腹部大動脈瘤に対して ステントグラフトが入り、お二人ともあっという間に元気に回復です

そうかお盆は既に旅立たれた人の魂との交流ですから、呼ばれるのでしょうか

僕も明日から週末まで短い休みを取ろうと思っていたのですが、急遽休みを取られた同僚の代わりに外来診療を行います でも緊急例が多い時期なのでやり甲斐がありますね

とわ言ってもプログラミングが中断したままです しかも悪いことに僕の浮気性が出てきて、それは何かと言えば、日本発の完全オブジェクト指向言語である Rubyの勉強なのです 実はこれまで数回行おうとしたのですが、なかなか進まず挫折していたのです その大きな原因は Windows環境での Ruby Programmingが相当やりにくい、ということがあったのです でもその初めてとりかかってから既に 10年以上が経過する間に状況は一変し、 Windows環境でもバッチリとなっていました それに何より僕の現在のプログラミング環境は OSXであり、Unixであるので Rubyはすいすい走るのです それに世界は Web開発は Ruby一色になりつつあります そんなこんなで再び Rubyの勉強を始めたので Qtによる DIB programmingは中断しています 結局こんな自分では何もものにならないのかも知れませんね

QtでのDIBクラスの実現

なかなかQtに馴染めない状態が続いいるのですが、ようやく DIBクラスの雛形ができてきました

DIBクラスとは Device-Independant Bitmapクラスのことであり、これを作らないことには DICOM XA viewerは作成できないのです

今まで作成してきたものは、所詮 Windows環境で作動するものであり、OSXのような Unixや Linuxでは作動しませんでした これをマルチプラットフォームの Qt Frameworkにより C++を用いて実現しようとしているのです

まずは DIB Class部分を これは以前 Windowsで作成したように headerにコードも記述し、これによりinline展開するようにすると共に、ライブラリのリンクという形式でなく、コードそのものを埋め込むようにしたいと思います

#ifndef CDIB_H
#define CDIB_H

#include <QtWidgets>
#include <QtGui>
#include <QImage>

// DIB Class
// cdib.h
//

class CDib : public QWidget
{
    Q_OBJECT
public:
    explicit CDib(QWidget *parent = 0) {
        resize(400, 400);
        image = new QImage(width(), height(), QImage::Format_ARGB32);
    }

    ~CDib() {
        delete image;
    }

    void update() {
        x++; y++;
        for (int i=1; i<400; i++){
            for (int j=1; j<400; j++){
                image->setPixel(i, j, qRgb(55, j%255, j%255));
            }
        }
    }

    QImage *image;

private:
    int x, y;

};

#endif // CDIB_H

これを呼ぶ時にはどうすれば良いかと言えば main windowを作成してその中でこの DIB classを実体化するのです たとえば次のようにです

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QtWidgets>
#include <QtGui>
#include "cdib.h"

// mainwindow.h

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = 0);
    ~MainWindow();

protected:
    void paintEvent(QPaintEvent *event);
private:
    CDib *dib;


};

#endif // MAINWINDOW_H

そして cpp fileは以下のようにたとえばなります

#include "mainwindow.h"
#include <stdlib.h>

// mainwindow.cpp

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    this->resize(800, 800);
    dib = new CDib(this);
    QTimer *timer = new QTimer();
    QObject::connect(timer, SIGNAL(timeout()), this, SLOT(update()));
    timer->start(500);


}

MainWindow::~MainWindow()
{
    delete dib;

}

void MainWindow::paintEvent(QPaintEvent *event){

    QPainter pen(this);

    int pos_x = random()%800;
    int pos_y = random()%800;
    dib->update();
    pen.drawImage(pos_x, pos_y, *dib->image);

}

これで 500 mSec毎に場所がかわる graduationの四角形が書かれます
要するに、画面表示部分と、画面に論理的に書き込む部分が分離できたということです 即ち DICOM XA fileを読み込んで暗号解読してから、ビットマップ・イメージをこの DIB classに書き込めば後は自動的に動画となる、ということなのです 我ながら素晴らしいアイディアだと思いますよ

どうも未だQtの文化に馴染めない

うーん これは問題です どうも Qtの文化になかなか馴染めないのです 簡単なプログラム書いてもエラーの嵐なのです

これまで C++ Frameworkと言えば、Windows標準文化の MFCにすっかり馴染んできましたが、Qtは全く別の文化なのです

そこになかなか馴染めず、「どうして?」とかいう疑問が次から次へと浮かんでくるのです これを克服するためには、どんどん小さなプログラム書いて馴染むしかないと思います

新しい世界への旅立ち

最近 ここ2週間以上にわたり Qtにはまっています Qtはその最初の開発が1997年頃から始まったようです 要するに C++が世に出た頃からなのですね 少なくとも過去15年間の天才たちの叡智が込められた Frameworkなのです

Frameworkというのは、要するに「独自の世界」です 何故その独自の世界に入ろうとするのか? と問われれば、人生を考えれば良いのです たとえば、何故 あなたは小学校に入りましたか? もちろん、日本においては義務教育だからです でも、小学校に入らなければ基礎的な読み書きを習得したり、友人を作ったり、遊びを覚えたり、そのようなことを習得することは大変だったでしょう

僕の場合、何故医学部に入ったか? 模範的回答は「医者になって、たくさんの病める人々を治すため」でしょうか いやいや僕の場合実際には、安田講堂事件により、その年の東大入試が突然キャンセルとなったから なのです

でも、そのようにして貧弱な動機で医学部に入っても、その世界の中で感化され、次第に医師として生きていく自覚が目覚めてきたのです

そうです Frameworkというのは「独自の世界」なのです その中に動機はどうであれ、どっぷりと浸かれば、次第に感化され、その世界で生きていく覚悟が出来てくるのです

C++の世界には主として User Interfaceを改善するために作られた Frameworkがたくさん存在します Windows programmerにとって最も有名なものは、MFC (Microsoft Foundation Class)です 僕もずいぶんこれは勉強してそれを用いてブロック崩しを作ったり、DICOM XA Viewerを作ったりしてきました そうやってMFCの世界観を体験してきたのです

それ以外にも、MacOSではもう15年以上前から Cocoa Foundationという User Interfaceに特化した Frameworkが存在します その APIは Objective-Cのためのものです

そして、これらよりも古い歴史を有するのが、C/C++のために書かれてきた OpenGLというものです

ただ、難しい!! 一人で独学して習得するには若い頭脳が必要で、僕のような 60歳を越した頭脳では無理無理無理無理

さて、Qtは? これも大変に難しく、MFCと異なり世の中に教材があまり出ていません Amazonに行ってみて下さい、Qtで検索して一体全体何冊の日本語書籍をあなたは見つけることができますか? しかもその大多数は 10年以上昔に出版されたものです

あーーー どうやってそんな中 60越えの頭脳で Qtを習得できるのでしょうか?

やるしか無いのです 果敢に挑戦していくしか無いのです さすれば、徐々に世界は開けていくのです 新しい世界が その向こうには素晴らしい世界がきっとあるのです

ということで、頑張って頑張ってようやく Qtを用いて OSX上で bitmapの動画を動かすことができました これで DICOM XA Viewer作成は射程距離範囲内になりました 頑張るぞーー