Visual Basic 6.0 中級講座
VB6対応

 

Visual Basic 中学校 > VB6 中級講座 >

7.ベジェ曲線

 

完成版の全コードなどを見る               

完成版をダウンロードする(ソースコードと実行ファイル)

 

今回は予告どおりベジェ曲線を使ってスクリーンセーバーを作ります。ベジェ曲線を上手く使えば結構きれいなスクリーンセーバーができることと思います。みなさんもこの記事を読んだら自分なりのきれいなスクリーンセーバーを作ってみてください。

この回の要約

・スクリーンセーバーとは拡張子が scr なだけで中身は普通のexe

・Windowsのスクリーンセーバー選択画面と連動するように作るには少し工夫が必要。(連動しなくて良いなら簡単)。


この回の使えるサンプル

・ ベジェ曲線を使ったスクリーンセーバー。→(上のリンク「完成版の全コードなどを見る)

 

1.ベジェ曲線

 

まずは「ベジェ曲線」自体の説明からしましょう。ベジェ曲線には2次のベジェ曲線、3次のベジェ曲線など種類があって今回扱うのは3次のベジェ曲線です。

3次のベジェ曲線を描くには4つの点を指定する必要があります。これら4つの点を順にA、B、C、Dとするとベジェ曲線は点Aを始点、点Dを終点とします。つまり点Aと点Dは必ずとおります。一方点Bと点Cは必ず通りません。

線分ABおよび線分CDはベジェ曲線の接線となります。

以上の説明では分からないはずなのでいくつかベジェ曲線の画像を掲載します。参考にしてください。下の画像で赤い線がベジェ曲線で他の部分は説明のためのものです。

先ほど記述したことがお分かりいただけることでしょう。もう一度まとめると、

・ベジェ曲線を描くには4つの点(順にA、B、C、D)を指定する。

・ベジェ曲線は点A、点Dをそれぞれ始点、終点とし、この2点を必ず通る。

・ベジェ曲線は点B、点Cを通らない。

・線分AB、線分CDはベジェ曲線の接線となる。

・ベジェ曲線は四角形ABCDの内部に必ず収まる。

 

2.ベジェ曲線を描画する

 

それではVBからベジェ曲線を描画してみましょう。

まず、4つの点の指定からです。4つの点はマウスでクリックして指定できるようにしましょう。このためにフォームにピクチャーボックスを1つとリストボックスを2つ貼り付けてください。これらは次のように設定します。

コントロール 名前 プロパティ  
PictureBox(ピクチャーボックス) Picture1 BackColor 黒い色を選ぶ
ForeColor 好みで良いが、とりあえず明るい緑色を選ぶ
ScaleMode 3 - ピクセル
List(リストボックス) lstX    
lstY    

そして、ピクチャーボックスのクリックした座標がリストボックスに記録されるようにします。このためにPicture1のMouseDownイベントプロシージャに次のように記述してください。

Private Sub Picture1_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)

    '4つ以上の点を指定したら、一旦クリアして指定のやり直し。
    If lstX.ListCount = 4 Then
        lstX.Clear
        lstY.Clear
    End If

    '指定した点の場所を円で示す。
    Picture1.Circle (X, Y), 5, vbWhite
   
    '指定した点を記録する。
    lstX.AddItem X
    lstY.AddItem Y

End Sub

4つ以上の点を指定できないように、5つ目の点を指定するとそれまでの結果を一旦クリアするようにしてあります。

4つの点を指定してコマンドボタンをクリックしたらベジェ曲線が描画されるようにしましょう。手始めにこのためのボタンを配置してください。名前はCommand1のままでいいでしょう。

ベジェ曲線を描画するにはAPI関数 PolyBezier を使いますからまずこれを宣言します。また、この関数はPOINT構造体を用いるのでPOINT構造体も忘れずに宣言してください。この部分は次のようになります。

Private Declare Function PolyBezier Lib "gdi32" (ByVal hdc As Long, lppt As POINTAPI, ByVal cPoints As Long) As Long

Private Type POINTAPI
        X As Long
        Y As Long
End Type

PolyBezier関数はその名の通り複数のベジェ曲線を1回の命令で描く能力を持っています。しかし、今は最初なので1本だけ描画させることにします。この関数は3つの引数をとります。1つ目は対象となるデバイスコンテキストへのハンドル。デバイスコンテキストについては第5回でやりましたが第5回を読んでいなくても大丈夫でしょう。2つ目の引数は4つの点(複数描画する場合はもっと多くの点)の座標を表すPOINT構造体の配列へのポインタです。こう書くと難しそうですがすぐ後で出てくるサンプルを見ていただくとそうでもないことが分かるでしょう。最後の引数は点の数です。今回は4つの点を指定しているので 4 が入るわけですね。

では、いよいよコマンドボタンをクリックしたときのコードをお見せしましょう。

Private Sub Command1_Click()

    Dim K As Integer
    Dim pnt(4) As POINTAPI
    Dim ReturnAPI As Long
   
    For K = 0 To 3
        pnt(K).X = lstX.List(K)
        pnt(K).Y = lstY.List(K)
    Next K

    ReturnAPI = PolyBezier(Picture1.hdc, pnt(0), 4)

End Sub

結構短いものでしょう。

まず、POINTAPI型の変数の配列pnt(4)を宣言します。この配列に4つの点の座標を格納します。点の座標はlstXとlstYに記録されるようにしてありますから、それらのリストを見てpnt()に代入するだけです。この部分をFor〜Nextで処理しています。

そして、配列pnt()が完成したら、PolyBezier関数を呼び出します。懸念の第2引数には配列の先頭を指定すればよいわけです。

これで、あなたのプログラムでベジェ曲線が描けることを確認できたと思います。このプログラムの全コードを下に掲載しておきます。この他にPicture1のプロパティの設定を間違っていると上手く描画できない場合がありますから上手くいかない人はそちらもチェックしてみてください。

Private Declare Function PolyBezier Lib "gdi32" (ByVal hdc As Long, lppt As POINTAPI, ByVal cPoints As Long) As Long

Private Type POINTAPI
        X As Long
        Y As Long
End Type
Private Sub
Command1_Click()

    Dim K As Integer
    Dim pnt(4) As POINTAPI
    Dim ReturnAPI As Long
   
    For K = 0 To 3
        pnt(K).X = lstX.List(K)
        pnt(K).Y = lstY.List(K)
    Next K

    ReturnAPI = PolyBezier(Picture1.hdc, pnt(0), 4)

End Sub

Private Sub Picture1_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)

    '4つ以上の点を指定したら、一旦クリアして指定のやり直し。
    If lstX.ListCount = 4 Then
        lstX.Clear
        lstY.Clear
    End If

    '指定した点の場所を円で示す。
    Picture1.Circle (X, Y), 5, vbWhite
   
    '指定した点を記録する。
    lstX.AddItem X
    lstY.AddItem Y

End Sub
 

 

3.スクリーンセーバー

 

次にベジェ曲線は一旦おいておいてスクリーンセーバーの説明をしましょう。ここはうだうだ説明していると収拾がつかなくなりそうなのでどんどんコードを例にあげながら説明していきます。みなさんも説明どおりにプログラムしながら読んでください。

STEP1    エントリポイント

新しいプロジェクトを作成して、標準モジュールを追加してください。標準モジュールを追加するには[プロジェクト]メニューの「標準モジュールの追加」をクリックします。標準モジュールを追加したら次のように記述してください。

Private Sub Main()

End Sub

このプロシージャが今回のプログラムの最初に実行される部分(通常はForm_Load)となります。このプロシージャからプログラムが始まるようにするにはさらに次のような手順を踏む必要があります。[プロジェクト]メニューから「Project1のプロパティ」をクリックし、「全般」タブを押したら スタートアップの設定 の欄でSub Main を選択します。

STEP2    コマンドラインの取得

スクリーンセーバーはシステムによって自動的に起動されますが、スクリーンセーバーが起動するときシステムからコマンドラインが渡されます。そのコマンドラインに応じて処理を変えます。渡されるコマンドラインは次のどれかでしょう。

コマンドライン 意味
/A パスワードチェックモードで起動されました。
/C 設定モードで起動されました。
/P プレビューモードで起動されました。
/S 通常モードで起動されました。

パスワードチェックモードは分かりにくいかもしれませんが、これはスクリーンセーバーにパスワードをかけているときに表示されるパスワード入力画面のことです。

なお、実際のコマンドラインはこれらの後ろにパラメータが続いていますので注意が必要です。そのためこれらのコマンドラインを取得するために次のようにします。

Dim Opt As String        'この変数に上記コマンドラインを格納します。

Opt = Left(LTrim(Command), 2)

これでコマンドラインを取得できるので次はその内容によって処理を分岐させます。

Select Case Opt

    Case "/A","/a"

         'ここにパスワードチェックモードで起動されたときの処理を書く

    Case "/C","/c"

         'ここに設定モードで起動されたときの処理を書く

    Case "/P","/p"

         'ここにプレビューモードで起動されたときの処理を書く

    Case "/S","/s"

         'ここに通常モードで起動されたときの処理を書く

End Select

それから、どのモードで起動されたのか記憶しておく変数も後々必要になりますから今のうちに作っておきましょう。標準モジュールの宣言部に次のように変数を宣言してください。

Public PlayMode As String

そして、Case "/P","/p"の下の行に

PlayMode = "P"

Case "/S","/s"の下の行に

PlayMode = "S"

と記述しておけばよいでしょう。(他のモードでは起動されたモードを記録しておく必要はありません。)

 

STEP3 通常モード

なんといっても通常モードがメインですから、まず通常モードを完成させてしまいましょう。スクリーンセーバーを実行するためにフォームの方をいじりましょう。まず、フォームの名前をfrmScreenに変えてください。そして通常モードで起動されたときはこのフォームを呼び出します。このため、上記のCase "/S","/s"の項目に次のように記述してください。

Case "/S","/s"

    PlayMode = "S"

    frmScreen.WindowState = 2    'フォームを最大化します。

    frmScreen.Show                    'フォームを表示します。

さらに、話が前後しますがスクリーンセーバーは2重起動しないようにしなければなりません。この処理もここでおこないます。2重起動というのは同じプログラムが2つ以上起動することでワードやエクセルなどは2つも3つも起動させてコピーしながら作業するという人もいるでしょう。しかし、スクリーンセーバーはこれができないようにしなければなりません。なぜなら、たとえば、スクリーンセーバが起動するまでの時間を1分に設定している場合、10分後には10個のスクリーンセーバーが起動してしまうからです。これを防止するには「自分がもう起動していたら終了せよ。」との命令が必要です。

自分がすでに起動しているかどうかの判断は、AppオブジェクトのPrevInstanceプロパティを調べれば分かります。たとえば、If App.PrevInstance Then End のようにすれば良いわけです。ところが、この技はスクリーンセーバーには使えないのです。なぜなら、プレビュー画面が表示されているときに本体が起動できなくなるからです。そこで、この便利で簡単な方法をあきらめてAPI関数を使って処理することにします。使うAPIはFindWindow関数でこの関数の宣言を標準モジュールの宣言部で次のように行ってください。

Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long

この関数はフォームのキャプションを調べてそのキャプションのウィンドウが存在するかを調べることができます。その事を利用して先ほどの PlayMode = "S" のすぐ上に次のように加えてください。

If FindWindow(vbNullString, "SCREEN BY NORMAL") <> 0 Then End

frmScreen.Caption = "SCREEN BY NORMAL"

そして、プレビューモードの場合にはこれと対抗する処置を講じておきましょう。Case "/P","/p" の下に次の1行を加えてください。

Case "/P","/p"

    frmScreen.Caption = "SCREEN BY PREVIEW"

    PlayMode = "P"

これで、やっとメインとなるフォームが呼び出されたわけです。具体的な描画処理はフォーム側で行うのが良いでしょう。このフォーム側のプログラムについては後で説明することにして、先に標準モジュール側のプログラムを完成させます。

STEP4 プレビューモード

標準モジュール側で一番難しいのはこのプレビューモードで起動されたときの処理です。プレビューモードとはスクリーンセーバーの設定画面で小さく表示される画面のことです。下の画像を見れば「あぁこれか」とどなたも思われることでしょう。

この小さな窓に自分の作ったスクリーンセーバーを表示させる方法がすぐにひらめいた人は立派な上級者です。この小さな窓は画面の形をした領域(これ自身も実はウィンドウ)の子ウィンドウなのです。この辺のことは今回のテーマではないので軽くだけ説明しますが、要するに自分の作ったフォームをこのウィンドウの子ウィンドウに設定すればよいわけです。こ親フォームのウィンドウのハンドルはコマンドラインで送られてきますから、なにをするにもまず、そのハンドルを受け取る必要があります。ハンドルを受け取るには次のようにします。

Dim ParentWnd As Long        'この変数に親ウィンドウのハンドルを入れる。

Case "/P","/p"

    frmScreen.Caption = "SCREEN BY PREVIEW"

    PlayMode = "P"

    ParentWnd = Val(Mid(Command, 4))

親ウィンドウのハンドルを取ったら、まずfrmScreenのサイズを上の画面にぴったりはまるサイズに調節します。この「ぴったりはまるサイズ」とは他ならぬ「親ウィンドウと同じサイズ」ということですから、親ウィンドウのサイズを取得するのが次の課題です。これには前回も出てきたGetWindowRectを使いますから、標準モジュールの宣言部に次のように記述してください。

Private Declare Function GetWindowRect Lib "user32" (ByVal hwnd As Long, lpRect As RECT) As Long

Private Type RECT

    Left As Long

    Top As Long

    Right As Long

    Bottom As Long

End Type

さらに、Mainプロシージャに変数の宣言を

Dim PreviewRect As RECT

のように加えたら、ParentWnd = Val(Mid(Command, 4))の下に続けて次のように記述します。

Call GetWindowRect(ParentWnd, PreviewRect)

frmScreen.Left = 0

frmScreen.Top = 0

frmScreen.Width = (PreviewRect.Right - PreviewRect.Left) * Screen.TwipsPerPixelX

frmScreen.Height = (PreviewRect.Bottom - PreviewRect.Top) * Screen.TwipsPerPixelY


なんだか書くことがいろいろあってどこに何を書くのか分からなくなってしまったかもしれませんね。そういう方は先に上のほうにある完成版を眺めるのも良いでしょう。完成版は別のページにあってこのページに上のほうにそのページへのリンクがはってあります。

ともあれ、サイズの調節はこれで終了。次はやっと「自分のフォームを子ウィンドウに設定する」という難易度の高い技に挑戦です。この部分はこれだけで1回分の解説になってしまうのでここでは手順だけ示すことにします。

まず、標準モジュールの宣言部に次のように宣言します。

Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long) As Long

Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long

Private Declare Function SetParent Lib "user32" (ByVal hWndChild As Long, ByVal hWndNewParent As Long) As Long

Private Const GWL_STYLE = (-16)

Private Const WS_CHILD = &H40000000

次に、Mainプロシージャで次のように変数の宣言をします。

Dim Style As Long

Dim Ret As Long

最後に、frmScreen.Height = PreviewRect.Bottomの下に続けて次のように記述します。

Style = GetWindowLong(frmScreen.hwnd, GWL_STYLE)

Ret = SetWindowLong(frmScreen.hwnd, GWL_STYLE, Style Or WS_CHILD)

Ret = SetParent(frmScreen.hwnd, ParentWnd)

これで子ウィンドウ化に成功です。最後はフォームを表示するためのコードを追加します。

frmScreen.Show

フォームが表示されれば、後の描画処理はフォーム側で行うので標準モジュール側の使命はほぼ終わりです。

STEP5 その他のモード

パスワードチェックモードや設定モードで呼び出されたときはあまりこった処理をしなくていいので簡単です。今回は余力がないのでこのパスワードチェックモードには対応せず、設定モードもごく簡単に済ませてしまいます。

次のように記述すると良いでしょう。

Case "/A","/a"

    '今回はパスワードチェックモードには対応しない。

Case "/C","/c"

    MsgBox "自作スクリーンセーバー" & vbCrlf & vbCrlF & "提供 VISUAL BASIC中学校"

 

4.終了処理

 

煩わしい標準モジュールのプログラムを終えてもまだちょっと作業が必要です。今度は終わるときの処理を書きましょう。スクリーンセーバーはキーボードのキーを押したり、マウスを動かしたら終了ですからfrmScreenに次のようにプログラムしましょう。なお、frmScreenのScaleModeプロパティは必ず 3-ピクセル にしておいてください。

Private Sub Form_Click()

    If PlayMode = "S" Then End

End Sub
Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)

    If PlayMode = "S" Then End

End Sub

Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)

    Static IsSecond As Boolean
    Static LastX As Long
    Static LastY As Long
    
    
    If IsSecond = False Then
        LastX = X
        LastY = Y
        IsSecond = True
    Else
        If PlayMode = "S" Then
            If Abs(X - LastX) > 10 And Abs(Y - LastY) > 10 Then
                End
            Else
                LastX = X
                LastY = Y
            End If
        End If
    End If

End Sub

終わらせるだけの処理なのに以外と複雑に思われるかもしれません。クリックしたときとキーを押したときの処理は簡単です。「通常モードなら終了しろ」ということですね。プレビューモードが終了されてはこまりますから起動したモードを記録しておいたのはここのためなのです。ただ、注意することとしてfrmScreenのKeyPreviewプロパティを True にすることを忘れないでください。

マウスを動かしたら終了のほうはちょっとくせがあります。このMouseMoveイベントプロシージャはフォームが表示されると自動的に1度呼び出されるのです。だから、ここにそのまま End と書くと起動した直後に終了してしまうことになるのです。そこでこの最初の1回を無視するためにIsSecondというフラグを作り1回目の呼び出しは無効にするようにしています。

2回目以降は素直に終了させるようにプログラムしても良いと思いますが、ここではマウスを動かした距離が一定以上のときに終了するようにしています。要するにちょっとマウスが動いたくらいでは終了しないということです。

なお、このフォームが終了すると他に目に見える部品がなくなってしまう可能性があるので、メモリリークを防ぐ意味をこめて念のために次のように記述しておくことにします。

Private Sub Form_Unload(Cancel As Integer)

    End

End Sub
 

 

5.描画処理

 

長かった前処理・後処理の解説を終えてやっと本番です。ここからが楽しいところ。みなさん楽しんで自分のセンスを活用してすばらしいスクリーンセーバーを作りましょう。

今回のスクリーンセーバーはベジェ曲線がテーマですから、ベジェ曲線を描画するためにfrmScreenに次のように宣言してください。

Private Declare Function PolyBezier Lib "gdi32" (ByVal hdc As Long, lppt As POINTAPI, ByVal cPoints As Long) As Long

Private Type POINTAPI

    X As Long

    Y As Long

End Type

まずは試作品ということで単純にベジェ曲線を描画するだけにしましょう。お試しのつもりで次のコードをコピーしてみてください。

Private Sub BezierDance()

    Dim K As Integer
    Dim M As Integer
    Dim Pnt(3) As POINTAPI
   
    Do
    
    Me.ForeColor = Randome(0, 60000)
    
    For K = 1 To 2000
        
        DoEvents   'これがないと描画中にイベントが発生しないので終了できない。
        
            For M = 0 To 3
                Pnt(M).X = Randome(0, ScaleWidth * 2) - (ScaleWidth \ 2)
                Pnt(M).Y = Randome(0, ScaleHeight * 2) - (ScaleHeight \ 2)
            Next M
        
        Call PolyBezier(Me.hdc, Pnt(0), 4)
    
    Next K
    
        frmScreen.Cls
    Loop
    
End Sub
Private Function Randome(Min As Long, Max As Long) As Long

    Randomize
    Randome = Fix(Rnd() * (Max - Min + 1)) + Min

End Function

Private Sub Form_Paint()

    BezierDance
    
End Sub

この他にfrmScreenのBorderStyleプロパティを 0 - なし に、BackColorプロパティを黒い色にしておいてください。

なお、Randome関数はMin以上Max以下の整数をランダムで生成する関数です。他のプログラムにも活用できます。

これで完成といえば完成です。あまり美しくないですが・・・。コードを手直しする前にこの状態でスクリーンセーバーとしてまともに動くかどうか一度試して見ましょう。

 

6.テスト

 

試用版を使っている方は多分次のようにして試せます。まず、[プロジェクト]メニューのProject1のプロパティをクリックしたら、「実行可能ファイルの作成」タブを選択します。その中にある コマンドライン引数 の欄に 英語半角で /S と入力してください。そして、実行してみて全画面でベジェ曲線が描画されるようなら成功です。上手くいかなかった場合はここまでの過程のどれかを誤っていることになりますからもう一度チェックしてみてください。なお、申し訳ありませんが試用版を使っている方はプレビューモードを試すことはできません。(このことはこのページのコンセプトに反するのではないかとも思いましたが、スクリーンセーバー本体の方は試せるわけですから大目に見てもらえるものと判断しました)。

製品版を使っている方はコンパイルして実行可能ファイルを作ってください。名前は    Bezier.scr    です。拡張子がexeではなくscrである点に注意してください。一旦exeでコンパイルした後からscrに手動で直しても大丈夫です。コンパイルしたら実行可能ファイル(Bezier.scr)をWindowsフォルダに入れてください。そして、画面のプロパティからスクリーンセーバーの設定画面を表示させて、一覧の中にあなたのスクリーンセーバがあるか確認してみましょう。そして、ちゃんと動作するか試してみてください。

なお、失敗するとスクリーンセーバーが暴走することがありますから他のアプリケーションを終了させてから試してみてください。暴走したスクリーンセーバーは強制終了させてください。

 

7.マウスポインタを見えなくする

 

テストして見ると気が付いたかもしれませんが実はこのプログラムでは「マウスポインタを隠す」という処理をしていません。通常のスクリーンセーバーはマウスポインタも見えなくなるものです。このプログラムもマウスポインタを隠せるように変更しましょう。

マウスポインタを隠すにはAPI関数を使った面倒な処理がいるのですがそこはVB、便利な抜け道があります。透明なマウスカーソルを用意してそれを表示させれば良いのです。透明なマウスカーソルはマウスカーソルを作成できるソフトを持っているなら簡単に作成できます。もし、そのようなソフトを持っていない場合はインターネット上にそういうソフトがあるのでダウンロードしてください。私はフリーのソフトを使っています。まったくただでこのような機能を提供してくれるのですからありがたい話です。

しかし、念のため私が作った透明なマウスカーソルをここからダウンロードできるようにしておきます。

TransMs.Cur

自分で透明なマウスカーソルを作った方は名前を TranMs.Cur にしてください。

さて、ではマウスカーソルを設定するコードを記述しましょう。

まず、[アドイン]メニューのアドインマネージャをクリックしてリソースエディタを選択してください。一覧にリソースエディタが表示されていない人やアドインマネージャが利用できない人は別の方法でやりますのでとりあえず読み進めてください。

さて、リソースエディタは選択すると利用可能になりますので、リソースエディタのアイコンをクリックしてリソースエディタを起動してください。リソースエディタのアイコンを念のために掲載しておきます。

この画像の真中の緑っぽいアイコンがそれです。

リソースエディタを起動したらマウスカーソルの追加を示すアイコンをクリックしてTransMs.Curを選択してください。TransMs.Curがリソースに追加されたことを確認したらそのIDの数字(横に表示される数字)も確認してください。多分 101 になっているはずです。

もし,101になっていない人はその番号を覚えておいてこれからの説明で 101 というところをその数字に置き換えてください。

そして、標準モジュール Case "/S","/s" の中の frmScreen.Caption = "SCREEN BY NORMAL" のすぐ下に次の2行を追加します。

frmScreen.MouseIcon = LoadResPicture(101, vbResCursor)

frmScreen.MousePointer = 99

これで通常モードで起動された場合はマウスカーソルは表示されなくなります。

さて、以上のようにリソースエディタやアドインマネージャを利用できない方は次のようにしてください。まず、プログラムを一旦保存して、プロジェクトファイル(拡張子がvbpのファイル。もちろん今作成中のスクリーンセーバープログラムのプロジェクトを指しています。)のあるフォルダの中に TransMs.Cur を入れます。標準モジュール Case "/S","/s" の中の frmScreen.Caption = "SCREEN BY NORMAL" のすぐ下に次の2行を追加します。

frmScreen.MouseIcon = LoadPicture(App.Path & "\TransMs.Cur")

frmScreen.MousePointer = 99

この場合はコンパイルしてスクリーンセーバーファイルを作ったときは TransMs.Cur をWindowsフォルダに入れることを忘れないでください。そうでないとプログラムは指定されたマウスアイコンが見つからないというエラーを出してしまいます。(なお、試用版を使っている人はコンパイルできません)。

 

8.より綺麗なベジェ曲線

 

以上でひとまず完成です。あまり美しくないという以外は普通のスクリーンセーバーと変わりません。これでようやく自分のセンスでスクリーンセーバーをデザインする時間が始まります。

ではどうやって綺麗なスクリーンセーバーにしましょうか?まぁそれは人しだいなのですがここでは私の考えた3つの例を載せておきます。いずれもBezierDanceプロシージャをそっくり入れ替えるだけでOKです。

例1    色を工夫する

これはほとんど変更の必要がありません。最初に作ったBezierDanceプロシージャと異なる部分は色を変えてあります。

Private Sub BezierDance()

    Dim K As Integer
    Dim M As Integer
    Dim L As Integer
    Dim Pnt(3) As POINTAPI
  
    Do
   
    For L = 1 To 200
   
        Me.ForeColor = RGB(255 - L, 255 * (L / 100), 255 * (L / 50))
       
        For K = 1 To 100

           
        DoEvents   'これがないと描画中にイベントが発生しないので終了できない。
       
            For M = 0 To 3
                Pnt(M).X = Randome(0, ScaleWidth * 2) - (ScaleWidth \ 2)
                Pnt(M).Y = Randome(0, ScaleHeight * 2) - (ScaleHeight \ 2)
            Next M
       
        Call PolyBezier(Me.hdc, Pnt(0), 4)
   
        Next K
   
    Next L

   
        frmScreen.Cls
    Loop
   
End Sub

これで、色はまぁ綺麗になりましたね。他にも綺麗な色のパターンはあるはずです。研究してみてください。

例2    描画パターンを工夫する

やはりランダムにベジェ曲線がばばばっと表示されるだけでは物足りません。ここでは放射状に表示されるようにプログラムを変えてみました。例1と異なる部分は色を変えてあります。

Private Sub BezierDance()

    Dim K As Integer
    Dim M As Integer
    Dim L As Integer
    Dim Pnt(3) As POINTAPI
  
    Do
   
    For L = 1 To 200
   
        Me.ForeColor = RGB(255 - L, 255 * (L / 100), 255 * (L / 50))
       
        For K = 1 To 100
           
        DoEvents   'これがないと描画中にイベントが発生しないので終了できない。
       
            Pnt(0).X = ScaleWidth \ 2
            Pnt(0).Y = ScaleHeight \ 2

       
            For M = 1 To 3
                Pnt(M).X = Randome(0, ScaleWidth * 2) - (ScaleWidth \ 2)
                Pnt(M).Y = Randome(0, ScaleHeight * 2) - (ScaleHeight \ 2)
            Next M
       
        Call PolyBezier(Me.hdc, Pnt(0), 4)
   
        Next K
   
    Next L
   
        frmScreen.Cls
    Loop
   
End Sub

なんだかアニメに時々ある視覚効果みたいになりますね。

例3    シックなスクリーンセーバー

今までの例は綺麗かどうかはおいておいてもとにかく派手でした。今度はもっと落ち着いた感じにしてみました。今度は上の例から大幅に変わっていますから注意してください。

Private Sub BezierDance()

    Dim K As Integer
    Dim M As Integer
    Dim L As Integer
    Dim Pnt(3) As POINTAPI
    Dim Target As Integer
    Dim WaitTime As Single
    Dim RecTime As Single
    Dim XDistance As Long
    Dim YDistance As Long
   
    WaitTime = 0.01
  
    Do
   
    For M = 0 To 3
        Pnt(M).X = Randome(0, ScaleWidth \ 2)
        Pnt(M).Y = Randome(0, ScaleHeight \ 2)
    Next M
   
    For L = 1 To 100
   
        Me.ForeColor = RGB(255 - L, 255 * (L / 100), 255 * (L / 50))
       
        Target = Target + 1
        If Target = 4 Then Target = 0
        With Pnt(Target)
       
        '点の移動距離をランダムで決める
        XDistance = Randome(-20, 20)
        YDistance = Randome(-20, 20)
       
        For K = 1 To 40
           
            DoEvents   'これがないと描画中にイベントが発生しないので終了できない。
 
            '点の移動
            .X = .X + XDistance
            .Y = .Y + YDistance
       
            '画面から点がはみ出さないような配慮
            If .X > ScaleWidth Or .X < 0 Then XDistance = -XDistance
            If .Y > ScaleHeight Or .Y < 0 Then YDistance = -YDistance
       
            Call PolyBezier(Me.hdc, Pnt(0), 4)
           
            '時間をつぶす
            RecTime = Timer
            Do Until Timer - RecTime > WaitTime
                DoEvents
            Loop
   
        Next K
        End With
   
    Next
L
   
    frmScreen.Cls
    Loop
   
End Sub

この例ではベジェ曲線を定義する4つの点のうち3つを固定して、1つを連続的に変化させています。どの1つを動かすかは順番で、ベジェ曲線を40本描くごとに交代します。また、ベジェ曲線の描画スピードが速くてせわしないので1本のベジェ曲線を描いたら0.01秒何もしないで待機するようにしています。

 

9.最後に

 

以上で今回の説明は終了です。スクリーンセーバーを作るのって結構大変だなと感じられたと思います。でも、最初の1つさえつくってしまえば2つ目からは描画処理の部分を変えるだけなので意外と楽にスクリーンセーバーが作れます。今回作ったスクリーンセーバーを雛型にしてどんどん綺麗なまたは面白いスクリーンセーバーを作ってください。

また、今回はベジェ曲線がテーマなのでスクリーンセーバーもベジェ曲線だけを使って描画しています。けれど、もちろんベジェ曲線にこだわらない別の作り方もありますからいろいろ試してみてくださいね。

それでは失礼します。