5

漫画本のレイアウトの .bmp 画像があります。現在、私のコードは次のように機能します。マウス ボタンを右クリックして押したままにすると、コミック ページの 1 つのフレームの周りにマーキー タイプのボックスを描画できます。ボタンを放すと、そのフレームにズームインします。しかし、その瞬間。そして、アニメーション効果を持たせたいと思っています。

したがって、PicRect の値を "END VALUE" に設定する代わりに

PicRect.Left
PicRect.right
PicRect.top
PicRect.bottom

以下のコードに見られるように、ゆっくりとそこにたどり着く方法が必要です。「終了値」に到達するまで、これらの値を少しずつ設定する while ループのようなものですが、この数学がどのように行われるかについては 100% 確信が持てません。は働いている。また、while ループの試行も何もしませんが、ズームインしすぎます。これが手順です。

procedure TZImage.MouseUp(Button: TMouseButton; Shift: TShiftState;
                      X, Y: Integer);
    var coef:Double;
    t:integer;
begin
   if FMouse=mNone then Exit;
   if x>ShowRect.Right then x:=ShowRect.Right;
   if y>ShowRect.Bottom then y:=ShowRect.Bottom;
   if FMouse=mZoom then begin  //calculate new PicRect
     t:=startx;
     startx:=Min(startx,x);
     x:=Max(t,x);
     t:=starty;
     starty:=Min(starty,y);
     y:=Max(t,y);
     FMouse:=mNone;
     MouseCapture:=False;
//enable the following if you want to zoom-out by dragging in the opposite direction}
    {     if Startx>x then begin
            DblClick;
            Exit;
         end;}
         if Abs(x-startx)<5 then Exit;
         if (x - startx < y - starty) then
         begin
           while (x - startx < y - starty) do
           begin
              x := x + 100;
              startx := startx - 100;
           end;
         end
         else if (x - startx > y - starty) then
         begin
            while (x - startx > y - starty) do
            begin
                y := y + 100;
                starty := starty - 100;
            end;
         end;


    //This is were it sets the zoom info. This is were
    //I have to change to slowly get the PICRECT.Left/right/top/bottom
         if (PicRect.Right=PicRect.Left)
         then
            coef := 100000
         else
            coef:=ShowRect.Right/(PicRect.Right-PicRect.Left);
         PicRect.Left:=Round(PicRect.Left+startx/coef);
         PicRect.Right:=PicRect.Left+Round((x-startx)/coef);
         if (PicRect.Bottom=PicRect.Top)
         then
            coef := 100000
         else
            coef:=ShowRect.Bottom/(PicRect.Bottom-PicRect.Top);
         PicRect.Top:=Round(PicRect.Top+starty/coef);
         PicRect.Bottom:=PicRect.Top+Round((y-starty)/coef);
       end;
       if FMouse=mDrag then begin
         FMouse:=mNone;
         Canvas.Pen.Mode:=pmCopy;
         Screen.Cursor:=crDefault;
       end;
       Invalidate;
    end;

これは上記のコードで実行できると思います。しかし、それが役立つ場合に備えてこれを追加したかったのです。

type
    TZImage = class(TGraphicControl)
  private
    FBitmap        : TBitmap;
    PicRect        : TRect;
    ShowRect       : TRect;
    FShowBorder    : boolean;
    FBorderWidth   : integer;
    FForceRepaint  : boolean;
    FMouse         : (mNone, mDrag, mZoom);
    FProportional  : boolean;
    FDblClkEnable  : boolean;
    startx, starty,
    oldx, oldy     : integer;

これを機能させるのに助けてくれてありがとう。

4

4 に答える 4

6

いくつか提案があります。それらがあなたの問題を解決するのに十分かどうかはわかりませんが、あなたがそこにたどり着くのに役立つことを願っています.

まず、あなたのwhileループはかなりの量の面白いいじりをしています:

if (x - startx < y - starty) then
     begin
       while (x - startx < y - starty) do
       begin
          x := x + 100;
          startx := startx - 100;
       end;
     end
else if (x - startx > y - starty) then
     /* similar code */

x - start == y - startyケースは完全に見落とされていることに注意してください。これが重要かどうかはわかりません。

第二に、これはおそらくループなしで書き直すことができます。ここでは、これが正しいかどうかを確認するために少しテストが必要になると思いますが、これは正しいパスのように感じます:

foo := (x - startx) - (y - starty)
if (foo > 200 || foo < -200)
    bar = foo / 200  # I assume integer truncation
    x += bar * 100
    startx += bar * 100

(x-startx) - (y-starty)お互いに 200 以内に近づこうとしている理由がよくわかりません。まだ良いものがあるかもしれません。

コードのこのセクションは少しわかりにくいです:

if (PicRect.Right=PicRect.Left)
     then
        coef := 100000
     else
        coef:=ShowRect.Right/(PicRect.Right-PicRect.Left);
     PicRect.Left:=Round(PicRect.Left+startx/coef);
     PicRect.Right:=PicRect.Left+Round((x-startx)/coef);
     if (PicRect.Bottom=PicRect.Top)
     then
        coef := 100000
     else
        coef:=ShowRect.Bottom/(PicRect.Bottom-PicRect.Top);
     PicRect.Top:=Round(PicRect.Top+starty/coef);
     PicRect.Bottom:=PicRect.Top+Round((y-starty)/coef);
   end;

coef以前から上書きされるはずですか?または、代わりにcoefxandを計算してcoefyから (大きい? 小さい? 100000 に近い?) 値を選択して.Left、 、.Right.Top、およびの両方の.Bottom計算に使用する必要がありますか? このコードは、現状のままでは、ユーザーと作成者の両方を苛立たせる方法でコンテンツをぎこちなく引き延ばす可能性が高いと考えざるを得ません。

ここで、ズームをアニメーション化する本当の理由に対処するには、おそらく何かを大幅に変更する必要があります。あなたのwhileループはおそらくズームを行うことを意図していたように感じますが、それらは計算の後に来るのでcoef何か他のものを意図していると思いました. coefただし、 「ズームなし」から「最終ズーム」までの範囲でさまざまな値を計算するためにループを正確に配置する場所を特定したら、表示を再描画するための呼び出しを追加する必要があります。環境では、50 ミリ秒ごとにタイマーによって起動されるコールバック コードを追加するか、更新されたcoef値で再描画する必要があるかもしれません。

于 2012-06-09T22:31:38.400 に答える
6

次の 2 つの問題があるため、while ループを使用してズーム レベルを更新しないでください。

  1. ズーム操作の速度はコードの速度、現在の CPU 使用率、CPU モデルなどに依存するため、アニメーションの長さが異なります。
  2. Sleep遅延を使用した場合でも (たとえば を使用)、コードがメイン スレッドで実行され、プログラムが応答しなくなるため、GUI がブロックされます。

sarnoldとEllingが既に言ったように: タイミング デバイス (たとえば a ) を使用して、すべての間隔で全体のズーム操作の一部を実行します。現在、これらのピースを計算する方法は 2 つあります。TTimer

  1. ブリッジする合計距離を一定数の小さな距離に分割し、タイマーの間隔を合計期間をその数で割った値に設定し、すべての間隔で処理されたすべての距離の合計を処理します。この方法の欠点は 2 つあります。
    • タイマーの設定間隔は概算であり、さまざまな理由により正確ではありません。そのうちの 1 つは Windows メッセージング システムに依存しています。
    • そのため、アニメーションが荒いまたは滑らかでない可能性があります。
  2. 間隔ごとにブリッジする距離の一部を再計算します。そうすれば、次の間隔が 2 倍以上かかるかどうかに関係なく、アニメーションは常にスムーズに表示されます。

関連する質問に対するこの回答の 2 番目の解決策を使用しました。そこから、次の関連するスニペットが取得されます。

procedure TZImage.Animate(Sender: TObject); 
var 
  Done: Single; 
begin 
  Done := (GetTickCount - FAnimStartTick) / FAnimDuration; 
  if Done >= 1.0 then 
  begin 
    FAnimTimer.Enabled := False; 
    FAnimRect := FCropRect; 
  end 
  else 
    with FPrevCropRect do 
      FAnimRect := Rect( 
        Left + Round(Done * (FCropRect.Left - Left)), 
        Top + Round(Done * (FCropRect.Top - Top)), 
        Right + Round(Done * (FCropRect.Right - Right)), 
        Bottom + Round(Done * (FCropRect.Bottom - Bottom))); 
  Invalidate; 
end; 

procedure TZImage.Zoom(const ACropRect: TRect); 
begin 
  FPrevCropRect := FCropRect; 
  FAnimRect := FPrevCropRect; 
  FCropRect := ACropRect; 
  FAnimStartTick := GetTickCount; 
  FAnimTimer.Enabled := True; 
end; 

説明:

  • FCropRectは新しいズーム四角形で、FPrevCropRectは前のものです。
  • FAnimRectアニメーションの進行状況に応じて、両方の間の長方形です。
  • FAnimStartTickZoomの呼び出しでズーム操作が開始された時刻です。
  • タイマー間隔 (15 ミリ秒、リフレッシュ レート ~67Hz に設定) ごとにAnimate呼び出され、
  • Doneはアニメーションの進行状況のパーセンテージです。
  • Invalidateにグラフィックを描画する再描画をトリガーしFAnimRectます。
于 2012-06-16T17:58:50.593 に答える
4

私はあなたの以前の質問への回答を書きました (これは、おそらくスタックオーバーフローのモデレーターによって完全に削除されました)。

私の以前の回答での提案は、glflow コード例を見ることでした。

http://code.google.com/p/glflow/

この例では GLScene ライブラリを使用し、画像の読み込み、画像のズーム、およびアニメーションの両方を示しています。

GLScene ライブラリを使用していない場合でも、コード例を見てアニメーション部分のインスピレーションを得ることができると思います。

その本質は、再描画を行うためにタイマーを使用する必要があるということです。

最初に、開始ズーム レベルと終了ズーム レベルの間の距離を個別のステップに分割します。次に、タイマーを使用してこれらのステップを循環し、各ステップで再描画を行います。

于 2012-06-10T10:01:55.827 に答える
0

私は実際にこのプロジェクトでグレンと協力しています。問題のコードの一部を書いたので、それが何をするのかを明確にしたいと思います。すぐにまとめたので、コメントを残しました。ここにあるコードのほとんどは、私たちが見つけたオープン ライセンスを介して使用されています。コードにはもともとループがありませんでした:

if (x - startx < y - starty) then
       begin
         while (x - startx < y - starty) do
         begin
            x := x + 100;
            startx := startx - 100;
         end;
       end
       else if (x - startx > y - starty) then
       begin
          while (x - startx > y - starty) do
          begin
              y := y + 100;
              starty := starty - 100;
          end;
       end;

これは私が追加したもので、元のコードが私たちが思っていたように機能しなかったために追加されたものです。基本的にドラッグアンドドロップで領域を選択します。選択された領域は拡大されますが、選択された領域全体を表示する代わりに、x-startx または y-starty の小さい方が表示領域に収まります。したがって、それを明確にするために、高さ 50 ピクセル、幅 100 ピクセルの領域を選択した場合、ズームして 50 ピクセルを上から下に合わせて表示領域を埋めますが、100 ピクセルは切り取られます。側面が表示領域から外れます。したがって、ここに追加されたコードは、2 つの小さい方を大きい方にすることで問題を解決することです。これを行うことで、実際にはビューが元の 2 つのうちの大きい方で、現在は 2 つのうち小さい方に適合します。これは信じられないほどずさんな修正ですが、機能します。あなたの方法もこの問題を解決し、より良い方法で解決する可能性があります。すべての大きな問題は、選択された領域が非常に大きい場合、200pix では実際には違いを修正するのに十分ではない可能性があることです。私たちの目的では、85% 以上は機能する可能性がありますが、すべてではないため、このコードにはまだ作業が必要です。

あなたが質問する他のコードは、実際には以前に私たちを狂わせていたものです。ドキュメント全体を通してコメントが完全に不足しており、それが何を意味するのかを正確にまとめようとしています。coef は、実際に私を怒らせているものです。そもそも何をするつもりなのか、完全にはわかりません。私は別のcoefxとcoefyを試しましたが、実際には壊れています。ズームボックスは、想定されていたものとは大きく異なります。私が知る限り、現在の方法では奇妙なストレッチが追加されていません。理由はよくわかりません。

フルスケールで見たい場合は、ここに使用しているコードへのリンクがあります。http://www.torry.net/authorsmore.php?id=986そのページの Zimage。

目前の実際の質問に関しては、そもそも coef が何をするのか正確にはわかりません。そのため、変更を加えると、物事が壊れてしまい、試行錯誤の方法で作業できなくなります。それが何をするのかを正確に理解するためにそれを見てよろしければ、正しい値に変更して、その過程で私のずさんなコードを取り除くことができます. これにより、ズーム アニメーションに進むことができます。

アニメーションに関する別の質問を追加するには。そうすることで、画像のあるズームポイントから別のズームポイントに移動するときにアニメーションを追加することもできますか. 私たちのアプリケーションでは、コミック パネルから別のコミック パネルへ、下または横に配置され、ほとんどの場合、サイズも異なります。左、右、上、下の中間値をロードすることは、そのタイプのアニメーションを表示するための最良の方法でしょうか? もしそうなら、それはフル画像から最初のズームパネルへの移動でもうまくいくと思います。

于 2012-06-10T05:07:35.967 に答える