グラフィック画面のチラツキ防止など

解決


サンデープログラマー  2006-05-10 21:44:04  No: 21440

Delphi6+Win-XPで数週間前からVBから移植しています。

下記のようなもので一旦UraImgに画像を書き上げてからImage1に画像をコピーするものを作りましたがどうしても表示画面がちらつきます。(VB6ではこの10倍以上の描画をさせても滑らかでした)この問題に関してご教示ください。

1.Imageに描いてImageに転送していますがこのような場合はImageを使うのは適していますでしょうか。このような目的にはどのような描画コントロールを使えば良いか分からないで試しています。

2.画面をクリアする方法が分からずバックカラーで塗りつぶしていますが何か良い方法があるのでしょうか?

3.作業エリアから表示画面にCopyRectを使ってみましたがチラツキの改善手段と考えてBitBltを試してみました(コード末尾の//節)が最初の画面が出るだけで画面が移動しませんが何か問題があるのか、またその改善策を教えてください。

var
  Form1: TForm1;
  imgW,imgH:integer;
  UraImg:Timage;
  ImgRect:TRect;
  YPos:integer;

implementation

(省略)

procedure TForm1.FormCreate(Sender: TObject);
begin

imgH:=800;
imgW:=800;

UraImg:=TImage.create(self);

UraImg.Width:=imgW;
UraImg.Height:=ImgH;

panel1.Width:=imgW;
Panel1.Height:=800;

ImgRect:=rect(0,0,ImgW,ImgH);

timer1.interval:=50;

end;

procedure TForm1.Timer1Timer(Sender: TObject);

var
        i,h:integer;
begin

        YPos:=YPos+1;
        If YPos>10 then Ypos:=0;

        with UraImg.canvas do
        begin
        Brush.Color:=rgb(128,192,255);
        rectangle(ImgRect)
        end;

    h:=Round(imgH/10);

    for i:=0 to h do
    begin
        UraImg.canvas.pen.color:=rgb(255,255,255);
        UraImg.canvas.MoveTo(0,YPos+i*10);
        UraImg.canvas.LineTo(imgW,Ypos+i*10);
    end;

Image1.canvas.CopyRect(ImgRect,UraImg.canvas,ImgRect);
//BitBlt(Image1.Canvas.Handle,0,0,ImgW,ImgH,UraImg.Canvas.Handle,0,0,SrcCopy);
end;

以上、よろしくご指導ください。なおこのような目的にマッチした書籍などありましたら教えてください。


DoubleBuffered  2006-05-11 02:00:33  No: 21441

>1.Imageに描いてImageに転送していますが
お好みですが、TImageとか、ごついものを使わなくてもできます。
手始めに TBitmapを使って内容を作成し、
TCanvas.Drawや Bitbltをするという手法があります。
描画の内容が、完全にTBitmapの内容と常に一致している
と保証できるのであれば、TCanvas.ClipRectを使って
必要な部分だけを再描画するといった効率的な処理ができます。

>2.画面をクリアする方法が分からずバックカラーで塗りつぶ
それ(FillCharとかFillRect)でいいと思います。
TPicture系なら、 TPicture.Graphics:=nil
で問題ないと過去に誰かに気づかされました。
白黒なら
Bitblt(dc,Left,Top,Width,Height,0,0,0,BLACKNESS)
Bitblt(dc,Left,Top,Width,Height,0,0,0,WHITENSS)
などがお手軽です。

>3.チラツキの改善手段
手っ取り早いのは、TWinControl系のキャンバスに
描画してみてはいかがでしょうか。(TFormもそうです)。

その場合、TWinControl.DoubleBuffered プロパティが使えます。

また、Controls.pas の
procedure TWinControl.WMPaint(var Message: TWMPaint);
に、ちらつき防止に関するコードがあります。

ソースをお持ちでなければ、
CreateCompatibleDC
CreateCompatibleBitmap
CreateDIBSection
Bitblt
DeleteObject
DeleteObject
この辺のキーワードでググってみてください。


訂正  2006-05-11 02:02:02  No: 21442

>DeleteObject
SelectObject


サンデープログラマー  2006-05-11 03:37:09  No: 21443

DoubleBufferd様、アドバイスをありがとうございました。
TWinControlとは?とググってみたりHELPを見たりしましたが初心者にはわからないタームで埋まっていましたのでどこから調べたら良いのやらと迷っていました。

>>手っ取り早いのは、TWinControl系のキャンバスに
>>描画してみてはいかがでしょうか。(TFormもそうです)。

現在の知識で分かるのは  
*TimageをやめてTbitmapに描かせる。
*Form1上に表示させる。
*TForm1をDoubleBufferd:=True;にしてみる
というのが最も近道そうなので試してみましたらほとんどチラツキは目立たないようになりました。また転送先がForm1になったからかBitBltも問題なく動きました。

更にDoubleBufferd:=False;にしても見ましたがこの程度の軽い描画ではTrueとFalseの差もわからないほど滑らかでした。今後重いものを実装した段階で効果を確かめながら進めようかと思います。

>>TImageとか、ごついものを使わなくてもできます。
描画できるコントロールが沢山ありそうなのでどれを採用したらよいのかが分からずにコンポーネントパレットに出てくるアイコンの絵の雰囲気でImageを使ってみましたがBitmapとFormで解決しました。各種コントロールの特徴など今後勉強してみます定番の使い方などありましたら教えてください。

現在は効果に満足しています。大変ありがとうございました。


sadoyama さどやま  URL  2006-05-11 09:55:06  No: 21444

TImage は何かと便利ですので、あまり敬遠しないほうが良いと思います。
  Delphi6 の TImage はバグがあるため、チラツキが出ることがあります。
  Update で修正されていますので、一度試されるとよいでしょう。


サンデープログラマー  2006-05-11 19:47:43  No: 21445

さどやま様、バグ情報などありがとうございました。修正版を探してみます。(HP拝見させていただきました)

>>TImage は何かと便利ですので、あまり敬遠しないほうが良いと思います。

描画できるコントロールは沢山あるようですが夫々の特長がわかりません。例えばDoubleBufferdプロパティがあるとか描画が早いとかちらつかないとかメモリが少なくて済む、など目的によってどれを使うかがロジカルに決められるようにしたいと思いますのでこのような情報がありましたら教えてください。


sadoyama さどやま  URL  2006-05-11 21:41:39  No: 21446

> 修正版を探してみます。
http://support.borland.com/entry.jspa?externalID=4324
よりダウンロードできます。


sadoyama さどやま  URL  2006-05-11 22:24:22  No: 21447

DoubleBuffer について

  チラツキを抑える効果がある反面、動作が重く(遅く)なるとされています。
  従ってどうしようもない場合にのみ使用するものと理解しています。
  私が使った事例は一度だけです。

  TScrollBox 上の TImage に大きな画像を表示し、指定サイズで描画した矩形をマウスで移動させる場合、スクロールに入るとどうしてもチラツキが出ました。
  このときだけ DoubleBuffer を使って対処しました。
  動きもスムーズで重さは感じませんでした。
  マウスで移動させるなどの人為的な動作に対応させる処理の場合には CPU の処理速度に比べれば極めてスローな動きになりますので、その間に DoubleBuffer の処理が済み、視覚的な副作用は生じないと思われます。


f  2006-05-12 05:20:11  No: 21448

>各種コントロールの特徴
TPaintBox → 謎。TCanvasの図形作成機能や塗りつぶしを使いたい時?
          使ったことが無いので、なんのためにあるのか
          いまいち理解できかねますが・・・
          ヘルプには
          >PaintBox で囲まれた特定の長方形の領域に限定
          とある。たぶんこれが理由。
          TCanvasをデザイン時から準備させる場合に使うのでしょう。
          確か、他のコントロールの上に TPaintBoxで重ねて
          表示したりとかもできたと思います。
          
TImage → フォームに貼れるので画像の表示用とか。
          AutoSize や Transparent、Stretchなどが便利?
          プログレス(Jpegとかで読みこんだ分だけ徐々に
          表示する機能?)にも対応している模様。
          また、TPictureを保持しているので、TPictureの機能も
          フルに使えます。
          
TPicture → いろんな種類の画像を扱いたい時。
          usesに TJpegImageとかTPngImageとか、その他の画像形式に
          対応したクラスのユニットを含めておけば、
          TPictureで読んだり書いたりできるようになります。
          また、TImage や TOpenImageDialogとかも TPictureを保持して
          いるので同様に usesに含めると、いろいろな画像形式に対応できる
          など TPictureを内部で保持しているコントロールは、
          利用価値が高いです。

TBitmap → とりあえず、バックバッファがほしい時。
          コントロールではありませんが、
          画像の作成段階を見せたくない場合とかに内部で利用。
          汎用的な画像処理。処理効率もそこそこよいです。
          これで満足がいかなくなって来る頃には、もういろいろ
          知ってると思います。
          (処理効率を優先する場合、TBitmapのインスタンスは、
          フォームの作成時など、処理が重複して行われない
          最初の段階で作成しておいたほうが良いです。
          再描画のたびに TBitmap.Createをすると、けっこうな
          時間がかかります。)

TPanel    →TPanel も出力先としてよく使われます。
          グラフィックコントロールでは ありませんが
          TPanelも出力先になりえるとして頭の隅にでもいれておくと
          今後、役に立つこともあるでしょう。
          Delphi製の純粋な画像処理系(ビデオキャプチャーとかOpenGL)
          のプログラムでは、たぶんトップです。
          TPanelは、独立したクライアント領域を管理できる点などから
          利用されているのだと思います。
          貼れば、画面ができる。そんな感じのニュアンスでよく利用されています。
          また、TPanelもTWinControlなので、さまざまなウィンドウの子に
          したり、いろいろメッセージをキャプチャーできるので非常に便利で
          使い道は無限にあります。

以上、主観。
レス不要。捕捉訂正は可。


f  2006-05-12 05:37:33  No: 21449

>DoubleBufferdプロパティがあるとか描画が早いとかちらつかないとかメモリが少なくて済む、

こういう細かい情報は、ネットを探しても国内にはあまり無いです。
昔は医療画像処理系のDelphiアプリがたくさんあり、情報もありましたが、
最近すたれぎみです。

画像処理を極めたいのであれば、
Delphi CT MRI
でググって見る価値はあります。

DoubleBufferdは、基本的にメモリは2倍以上使用します。

ケース1 
1.出力先のイメージを画像として内部に保持し
2.それに対して、ユーザーが画像処理を行い
3.それを出力先に戻す という流れが組まれます。

ケース2
1.ユーザーがバックバッファに画像処理を行い
2.常に、そのバッファを出力先に出力し
3.本来の出力先のイメージは、無視する

>描画が早い

Delphi固有の問題ですが
 TCanvas.Pixels[x,y] 
これが、けっこう曲者で、Delphiユーザーには広く知られていますが
かなり遅く、画像の全てを走査するような
ループの中では利用しないほうが良いでしょう。

ので、TBitmapが利用可能な場合、
 TBitmap.ScanLine を使うことで、かなり効率が良くなります。
という話は聞いたことがあると思います。

>メモリが少なくてすむ
は、ちょっと専門外なのでパス。


あった  2006-05-12 05:39:29  No: 21450

まだありました(^^)

h ttp://www2s.biglobe.ne.jp/~aks-lab/
画像処理講座があります。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加