Qt はイベント駆動型フレームワークである
イベントについて正しく理解していないと、マルチスレッドやシグナル・スロットでハマル場合がある。
正しく理解して、正しく使いましょう。
┌──────────┐
│ イベントキュー・ │ ┌─────────┐
│ ディスパッチャ │ │ イベントハンドラ │
└────┬─────┘ └────┬────┘
event-1 │ │
─────→│────────────→┌┴┐
event-2 │ │ │event-1 の処理
─────→│ │ │
│ └┬┘
│────────────→┌┴┐
│ │ │event-2 の処理
│ │ │
│ └┬┘
event-3 │ │
─────→│────────────→┌┴┐
│ │ │event-3 の処理
│ │ │
│ └┬┘
│ │
↓ ↓
┌──────────┐
│ イベントキュー・ │┌─────────┐┌─────────┐┌─────────┐
│ ディスパッチャ ││ QObject::event() ││ keyPressEvent() ││ paintEvent() │
└────┬─────┘└────┬────┘└────┬────┘└────┬────┘
key-event │ │ │ │
─────→│─────────→┌┴┐───────→┌┴┐ │
paint-event │ │ │ │ │ │
─────→│ │ │ │ │ │
: │ └┬┘ └┬┘ │
: │─────────→┌┴┐─────────│────────→┌┴┐
│ │ │ │ │ │
│ │ │ │ │ │
│ └┬┘ │ └┬┘
│ │ │ │
↓ ↓ ↓ ↓
sendEvent(), postEvent() によりイベントを QObject 派生クラスのオブジェクトに送信できる。
bool QCoreApplication::sendEvent ( QObject * receiver, QEvent * event ) は、イベントが処理されるまでブロッキングされる。
event オブジェクトはハンドラによりデリートされることはない。
void QCoreApplication::postEvent ( QObject * receiver, QEvent * event ) は、イベントをキューに積み、直ぐに処理を終える。
event オブジェクトは new でヒープ上に確保されなくてはいけない。
paintEvent(QPaintEvent *) をリインプリメントして描画をカスタマイズ
1: class MainWindow : public QWidget
2: {
3: .....
4: protected:
5: void paintEvent(QPaintEvent * event); // 描画のためのイベントハンドラ宣言
6: .....
7: };
1: void MainWindow::paintEvent(QPaintEvent * event)
2: {
3: QPainter painter(this);
4: painter.setPen(Qt::blue);
5: painter.setFont(QFont("Arial", 20));
6: painter.drawText(rect(), Qt::AlignCenter, "Hello, world.");
7: }
update() で画面が無効化された場合等、画面再描画が必要になった場合に paintEvent() がコールされる。
QPainter(QPaintDevice *) で描画オブジェクトを生成し、描画メソッドを使って画面を描画する。
QPaintDevice 派生クラス:QGLFramebufferObject, QGLPixelBuffer, QImage, QPicture, QPixmap, QPrinter, QSvgGenerator, QWidget
QPainter 主な描画メソッド:
| 円弧 | drawArc( const QRectF & rectangle, int startAngle, int spanAngle ) drawArc ( const QRect & rectangle, int startAngle, int spanAngle ) drawArc ( int x, int y, int width, int height, int startAngle, int spanAngle ) |
| 閉円弧 | drawChord ( const QRectF & rectangle, int startAngle, int spanAngle ) |
| 凸ポリゴン | drawChord ( const QRectF & rectangle, int startAngle, int spanAngle ) |
| 楕円 | drawEllipse ( const QRectF & rectangle ), ... |
| イメージ | drawImage ( const QRectF & target, const QImage & image, const QRectF & source, ... ), ... |
| 直線 | drawLine ( const QLineF & line ), ... |
| 直線群 | drawLines ( const QLineF * lines, int lineCount ) |
| 連続直線・曲線 | drawPath ( const QPainterPath & path ), ... |
| ピクチャ | drawPicture ( const QPointF & point, const QPicture & picture ), ... |
| パイ | drawPie ( const QRectF & rectangle, int startAngle, int spanAngle ), ... |
| ピックスマップ | drawPixmap ( const QRectF & target, const QPixmap & pixmap, const QRectF & source ), ... |
| 点 | drawPoint ( const QPointF & position ), ... |
| 点群 | drawPoints ( const QPointF * points, int pointCount ), ... |
| (閉)ポリゴン | drawPolygon ( const QPointF * points, int pointCount, Qt::FillRule fillRule = Qt::OddEvenFill ), ... |
| 連続直線 | drawPolyline ( const QPointF * points, int pointCount ), ... |
| 矩形 | drawRect ( const QRectF & rectangle ), ... |
| 角丸矩形 | drawRoundedRect ( const QRectF & rect, qreal xRadius, qreal yRadius, Qt::SizeMode mode = Qt::AbsoluteSize ), ... |
| 静的テキスト | rawStaticText ( const QPointF & topLeftPosition, const QStaticText & staticText ), ... |
| テキスト | drawText ( const QPointF & position, const QString & text ), ... |
| ピックスマップ敷詰 | drawTiledPixmap ( const QRectF & rectangle, const QPixmap & pixmap, const QPointF & position = QPointF() ), ... |
※ イメージ(QImage):ハードウェア非依存画像、ピックスマップ(QPixmap):スクリーンに描画するために最適化
※ ピクチャ(QPicture):描画処理を保存・再生するためのもの
※ 静的テキスト(QStaticText):文字列やフォントなどの変更が稀なもの。表示情報をキャッシュし処理を高速化。
QPainter 属性:
| 背景 | setBackground ( const QBrush & brush ) |
| 背景モード | setBackgroundMode ( Qt::BGMode mode ) ※ 透明・非透明 |
| ブラシ | setBrush ( const QBrush & brush ) |
| クリッピングパス | setClipPath ( const QPainterPath & path, Qt::ClipOperation operation = Qt::ReplaceClip ) |
| クリッピング矩形 | setClipRect ( const QRectF & rectangle, Qt::ClipOperation operation = Qt::ReplaceClip ) |
| クリッピング領域 | setClipRegion ( const QRegion & region, Qt::ClipOperation operation = Qt::ReplaceClip ) |
| クリッピングモード | setClipping ( bool enable ) |
| コンポジションモード | setCompositionMode ( CompositionMode mode ) ※ src, dst, src & dst, ... |
| フォント | setFont ( const QFont & font ) |
| レイアウト方向 | setLayoutDirection ( Qt::LayoutDirection direction ) |
| 透明度 | setOpacity ( qreal opacity ) |
| ペン | setPen ( const QPen & pen ) |
| 描画ヒント | setRenderHint ( RenderHint hint, bool on = true ) ※ アンチエイリアス、スムース、... |
| 座標変換 | setTransform ( const QTransform & transform, bool combine = false ) |
| ビューポート | setViewport ( const QRect & rectangle ) |
| ウィンドウ | setWindow ( const QRect & rectangle ) |
■ 演習問題
mousePressEvent(QMouseEvent *), mouseReleaseEvent(QMouseEvent *), mouseDoubleClickEvent(QMouseEvent *) でマウス操作を実装
QMouseEvent の以下のメソッドでマウスの状態を参照することができる。
| 押されたボタン種別 | Qt::MouseButton QMouseEvent::button () const |
| マウスポインタ位置(グローバル座標系) | const QPoint & QMouseEvent::globalPos () const |
| マウスポインタ位置(オブジェクト座標系) | const QPoint & QMouseEvent::pos () const |
| マウスポインタX座標(オブジェクト座標系) | int QMouseEvent::x () const |
| マウスポインタY座標(オブジェクト座標系) | int QMouseEvent::y () const |
■ 演習問題
keyPressEvent ( QKeyEvent * event ), keyReleaseEvent ( QKeyEvent * event )
QKeyEvent の以下のメソッドで押されたキーの情報を取得できる。
| オートリピートか? | bool QKeyEvent::isAutoRepeat () const |
| キーコード | int QKeyEvent::key () const |
| スタンダードキーか? | bool QKeyEvent::matches ( QKeySequence::StandardKey key ) const |
| Shift キー等の状態 | Qt::KeyboardModifiers QKeyEvent::modifiers () const |
| テキスト | QString QKeyEvent::text () const |
■ 演習問題
イベントフィルターをインストールするこで、ソースの無いウィジットでも、動的に動作をカスタマイズ出来るぞ。
手順:
installEventFilter(filterObj) で、filterObj へイベントフィルターをインストールする。 filterObj にイベントが発生すると、まず eventFilter() がコールされる。 eventFilter() でイベントが処理されなかった場合は、通常のイベント処理が行われる。
eventFilter ( QObject * watched, QEvent * event ) の第1引数は、どのオブジェクトへのイベントかを識別するためのもの。
第2引数はイベントオブジェクト。event->type() でイベント種別を判定可能。
eventFilter() でイベントを処理した場合は true を返す。false を返した場合は、通常のイベント処理が行われる。
使用例:QPlainTextEdit の左側に行番号表示
ViEditView::ViEditView(QWidget *parent)
: m_mode(CMD), QPlainTextEdit(parent)
{
m_lineNumberArea = new QWidget(this);
m_lineNumberArea->installEventFilter(this);
}
bool ViEditView::eventFilter(QObject *obj, QEvent *event)
{
if( obj == m_lineNumberArea && event->type() == QEvent::Paint ) {
drawLineNumbers();
return true;
}
return false;
}
void ViEditView::drawLineNumbers()
{
QPainter painter(m_lineNumberArea);
.....
}