4.6がやってきた-Qt最新事情2010

第8回 グラフィックスイフェクト

この記事を読むのに必要な時間:およそ 5 分

グラフィックスアイテムへのぼかし効果の適用

ぼかし効果をどのようにして,グラフィックスアイテムへの適用するかを説明します。ぼかし付きが図2ぼかしなしは図3です。

図2 ぼかし付き

図2 ぼかし付き

図3 ぼかしなし

図3 ぼかしなし

リスト1 triangles.cpp(部分)

18: Harness::Harness()
19:     : QWidget( 0 )
20: {
21:     resize( 680, 680 );
22: 
23:     QTime midnight(0, 0, 0);
24:     qsrand( midnight.secsTo( QTime::currentTime() ) );
25: 
26:     QGraphicsScene* scene = new QGraphicsScene( -200, -200, 400, 400, this );
27:     scene->setItemIndexMethod( QGraphicsScene::NoIndex );
28: 
29:     for ( int n = 0; n < 10 * 100; n++ ) {
30:         QPolygonF polygon = randomTriangle();
31:         QGraphicsPolygonItem* polygonItem = new QGraphicsPolygonItem( polygon );

31行目でグラフィックスアイテムを生成しています。このグラフィックスアイテムにグラフィックスイフェクトを設定します。

33:         QGraphicsBlurEffect* blurEffect = new QGraphicsBlurEffect;
34:         blurEffect->setBlurRadius( 0.5 + ( qrand() / double( RAND_MAX ) ) * 2 );
35:         polygonItem->setGraphicsEffect( blurEffect );

ぼかし効果を付けるためにQGraphicsBlurEffectのインスタンスを生成し,ぼかし半径を乱数設定しています。

37:         polygonItem->rotate( qrand() % 360 );
38:         polygonItem->setPen( Qt::NoPen );
39:         QColor color;
40:         while ( true ) {
41:             color = QColor( qrand() % 256, qrand() % 256, qrand() % 256 );
42:             if ( color.value() > 80 )
43:                 break;
44:         }
45:         color.setAlpha( 100 + qrand() % 156 );
46:         polygonItem->setBrush( color );
47:         scene->addItem( polygonItem );
48:     }
49: 
50:     QGraphicsView* graphicsView = new QGraphicsView( scene );
51:     graphicsView->setRenderHint( QPainter::Antialiasing );
52: 
53:     QVBoxLayout* topLayout = new QVBoxLayout;
54:     topLayout->addWidget( graphicsView );
55: 
56:     setLayout( topLayout );
57: }

ウィジェットへの影付け効果の適用

ウィジェットにもグラフィックスイフェクトを付けられ,影を付けると図4のようになります。

図4 ウィジェットに影を付ける

図4 ウィジェットに影を付ける

リスト2 widgetdropshadow.cpp(部分)

 8: int main( int argc, char** argv )
 9: {
10:     QApplication app( argc, argv );
11:     
12:     QGraphicsDropShadowEffect* shadowEffect = new QGraphicsDropShadowEffect;
13:     shadowEffect->setBlurRadius( 12 );
14:     shadowEffect->setOffset( 6, 6 );
15:     shadowEffect->setColor( QColor( 20, 20, 20 ) );

まず,影を付けるためにQGraphicsDropShadowEffectのインスタンスを生成します。影のぼかし半径を12ピクセル,影のオフセットを6ピクセルずつ,濃いめの灰色の影を付けています。

17:     QLabel* label = new QLabel( "Hello!" );
18:     QFont font = label->font();
19:     font.setPointSize( 72 );
20:     label->setFont( font );
21:     QPalette palette = label->palette();
22:     palette.setColor( QPalette::Window, QColor( "SteelBlue" ) );
23:     label->setAutoFillBackground( true );
24:     label->setPalette( palette );
25:     label->setGraphicsEffect( shadowEffect );

25行目でウィジェットにsetGraphicsEffectで,グラフィックスイフェクトを設定しています。このように,グラフィックスイフェクトを使うのはとても簡単です。

27:     QHBoxLayout* labelLayout = new QHBoxLayout;
28:     labelLayout->addStretch();
29:     labelLayout->addWidget( label );
30:     labelLayout->addStretch();
31: 
32:     QVBoxLayout* topLayout = new QVBoxLayout;
33:     topLayout->addStretch();
34:     topLayout->addLayout( labelLayout );
35:     topLayout->addStretch();
36: 
37:     QWidget top;
38:     top.setLayout( topLayout );
39: 
40:     top.show();
41: 
42:     return app.exec();
43: }

Mac OS Xではウィジェットには,どのグラフィックスイフェクトも適用できないというバグがあり,このサンプルコードを動かしてもグラフィックスイフェクトは無効です。

グラフィックスイフェクトのアニメーション

グラフィックスイフェクトのプロパティをアニメーションすれば,各効果が段階的に適用されるようなアニメーション効果を得られます。色付け効果にアニメーションを適用してみましょう。次の動画は第3回「Qt 4.6のアニメーションフレームワーク[後編⁠⁠」で用いた「グラフィックスビューのアイテムのアニメーション」に,グラフィックスイフェクトのアニメーションを追加したサンプルです。黄色いボールが移動しながら段々と赤くなって行きます。

リスト3 animatedeffect.cpp(部分)

 51: Harness::Harness()
 52:     : QWidget( 0 ), d_ptr( new HarnessPrivate )
 53: {
 54:     Q_D( Harness );
 55: 
 56:     QGraphicsScene* graphicsScene = new QGraphicsScene( 0, 0, d->movingAreaSize.width(), d->movingAreaSize.height() );
 57:     MovableGraphicsPixmapItem* yellowBallItem = createBallItem( ":/images/YellowGlassBall.png" );
 58: 
 59:     QGraphicsColorizeEffect* colorizeEffect = new QGraphicsColorizeEffect;
 60:     colorizeEffect->setColor( QColor( 192, 0, 0 ) );
 61:     colorizeEffect->setStrength( 0.0 );
 62:     yellowBallItem->setGraphicsEffect( colorizeEffect );

59行目で,今度は,色付けのためにQGraphicsColorizeEffectのインスタンスを生成しています。薄い赤色が付くように設定していますが,strength プロパティを0.0にしているので,このグラフィックスイフェクトを適用しても赤色にはならず,元々の黄色のままとなります。

 64:     QSize ballSize = yellowBallItem->pixmap().size();
 65:     int ballSpacingY = ( d->movingAreaSize.height() - ballSize.height())  / 2;
 66:     int yellowBallY = ballSpacingY;
 67:     yellowBallItem->setPos( d->horizontalOffset, yellowBallY );
 68:     graphicsScene->addItem( yellowBallItem );
 69: 
 70:     QGraphicsView* graphicsView = new QGraphicsView();
 71:     graphicsView->setScene( graphicsScene );
 72: 
 73:     QPushButton* animateButton = new QPushButton( "Animate" );
 74: 
 75:     QHBoxLayout* buttonLayout = new QHBoxLayout;
 76:     buttonLayout->addStretch();
 77:     buttonLayout->addWidget( animateButton );
 78: 
 79:     QVBoxLayout* topLayout = new QVBoxLayout;
 80:     topLayout->addWidget( graphicsView );
 81:     topLayout->addLayout( buttonLayout );
 82: 
 83:     setLayout( topLayout );
 84:     setFixedSize( sizeHint() );
 85: 
 86:     d->yellowBallAnimation = new QParallelAnimationGroup( this );

yellowBallItemのposとcolorizeEffectのstrengthの各プロパティを並列にアニメーションをすることにします。

 88:     QPropertyAnimation* posAnimation = new QPropertyAnimation( yellowBallItem, "pos", this );
 89:     d->yellowBallAnimation->addAnimation( posAnimation );
 90:     posAnimation->setDuration( 5 * 1000 );
 91:     int movableBallStartX = d->horizontalOffset;
 92:     int movableBallEndX = d->movingAreaSize.width() - ballSize.width() - d->horizontalOffset;
 93:     posAnimation->setStartValue( QPoint( movableBallStartX, yellowBallY ) );
 94:     posAnimation->setEndValue( QPoint( movableBallEndX, yellowBallY ) );
 95:     posAnimation->setEasingCurve( QEasingCurve::OutBounce );

posのアニメーションは,並列アニメーションに入れるようにする他は今まで通りです。

 97:     QPropertyAnimation* strengthAnimation = new QPropertyAnimation( colorizeEffect, "strength", this );
 98:     d->yellowBallAnimation->addAnimation( strengthAnimation );
 99:     strengthAnimation->setDuration( 5 * 1000 );
100:     strengthAnimation->setStartValue( 0.0 );
101:     strengthAnimation->setEndValue( 1.0 );

strengthのアニメーションは,0.0から1.0に変わるようにしています。このようにすれば,薄い黄色から薄い赤に変わるようにアニメーションが行われます。

103:     connect( animateButton, SIGNAL( clicked() ), SLOT( startAnimation() ) );
104: }

おわりに

2009 年末から半年以上に渡って続いた Qt 4.6 関連の連載も今回で一区切りです。しばらく間を置いて,次はQt 4.7のリリース情報やQt 4.7で最も期待されている機能のQMLについて連載をする予定です。

著者プロフィール

杉田研治(すぎたけんじ)

1955年生まれ。東京都出身。株式会社SRAに勤務。プログラマ。

仕事のほとんどをMac OS XとKubuntu KDE 4でQtと供に過ごす。