2016-05-16 44 views
3

我試圖根據鼠標的當前位置縮放圖形。現在我onMouseWheel方法如下所示(基於this StackOverflow answer):基於當前鼠標位置縮放圖形

private void onMouseWheel(object sender, MouseEventArgs e) 
    { 
     if (e.Delta > 0) 
     { 
      _scale *= 1.25f; 
      _translateY = e.Y - 1.25f * (e.Y - _translateY); 
      _translateX = e.X - 1.25f * (e.X - _translateX); 
     } 
     else 
     { 
      _scale /= 1.25f; 
      _translateY = e.Y - 0.8f * (e.Y - _translateY); 
      _translateX = e.X - 0.8f * (e.X - _translateX); 
     } 
     this.Invalidate(); 
    } 

_scale_translateX,並且_translateY是成員變量。

我縮放圖形,翻譯它,然後繪製線條像這樣:

protected override void OnPaint(PaintEventArgs e) 
    { 
     g.ScaleTransform(_scale, _scale); 
     g.TranslateTransform(_translateX, _translateY); 
     //draw lines here 
    } 

This video顯示當我嘗試放大,什麼發生在某一點的縮小。我究竟做錯了什麼?

這是代碼看起來像在樣本面板類用於測試目的:

class Display : Panel 
{ 
    public Display() 
    { 
     this.MouseWheel += new MouseEventHandler(this.onMouseWheel); 
    } 

    private void onMouseWheel(object sender, MouseEventArgs e) 
    { 
     if (e.Delta > 0) 
     { 
      _scale *= 1.25f; 
      _translateY = e.Y - 1.25f * (e.Y - _translateY); 
      _translateX = e.X - 1.25f * (e.X - _translateX); 
     } 
     else 
     { 
      _scale /= 1.25f; 
      _translateY = e.Y - 0.8f * (e.Y - _translateY); 
      _translateX = e.X - 0.8f * (e.X - _translateX); 
     } 
     this.Invalidate(); 
    } 

    protected override void OnPaint(PaintEventArgs e) 
    { 
     g.ScaleTransform(_scale, _scale); 
     g.TranslateTransform(_translateX, _translateY); 

     Pen pen = new Pen(Color.Red); 
     g.FillEllipse(pen.Brush, 50, 50, 10, 10); 
    } 
} 
+0

您可以上傳示例應用程序的代碼嗎?我認爲它與你的規模有關,如果你使用_scale + = 0.25f而不是乘法,它是否工作。雖然這只是一個猜測,因爲我現在沒有一個工作的例子。 – dwonisch

+0

我添加了一個示例面板類,您可以將其添加到表單中。添加不起作用。如果我縮小太多,這將使變焦變爲負值。它與翻譯有關。縮放工作正常。 –

回答

0

懶得做出正確的方程(最有可能會做出類似的錯誤,你......我不知道它是否只是我,但正是我不能處理這種簡單的東西,讓我發瘋)。相反,我處理這類任務如下(這是從錯誤中更安全):

  1. 造屏和世界之間的轉換函數座標

    所以,你的鼠標的位置是在屏幕座標和渲染的東西是在世界座標。因爲這只是2D那麼這很容易。使這兩個功能之間進行轉換。你的世界到屏幕變換(如果我不是忽視的東西)是這樣的:

    g.ScaleTransform(_scale, _scale); 
    g.TranslateTransform(_translateX, _translateY); 
    

    這樣:

    screen_x=(world_x*_scale)+_translateX; 
    screen_y=(world_y*_scale)+_translateY; 
    

    所以反向:

    world_x=(screen_x-_translateX)/_scale; 
    world_y=(screen_y-_translateY)/_scale; 
    
  2. 變焦的變化/規模

    這個想法是,在變焦/ s cale更改鼠標位置應保持與以前一樣的世界座標。所以記住改變之前鼠標的世界座標。然後從中計算出變化後的屏幕位置和差異。

這裏簡單的C++例如:

double x0=0.0,y0=0.0,zoom=1.0,mx,my; 
//--------------------------------------------------------------------------- 
void scr2obj(double &ox,double &oy,double sx,double sy) 
    { 
    ox=(sx-x0)/zoom; 
    oy=(sy-y0)/zoom; 
    } 
//--------------------------------------------------------------------------- 
void obj2scr(double &sx,double &sy,double ox,double oy) 
    { 
    sx=x0+(ox*zoom); 
    sy=y0+(oy*zoom); 
    } 
//--------------------------------------------------------------------------- 
void __fastcall TForm1::FormMouseWheelDown(TObject *Sender, TShiftState Shift,TPoint &MousePos, bool &Handled) 
    { 
    double mx0,my0; 
    scr2obj(mx0,my0,mx,my); 
    zoom/=1.25; // zoom out 
    obj2scr(mx0,my0,mx0,my0); 
    x0+=mx-mx0; 
    y0+=my-my0; 
    _redraw=true; 
    } 
//--------------------------------------------------------------------------- 
void __fastcall TForm1::FormMouseWheelUp(TObject *Sender, TShiftState Shift, TPoint &MousePos, bool &Handled) 
    { 
    double mx0,my0; 
    scr2obj(mx0,my0,mx,my); 
    zoom*=1.25; // zoom in 
    obj2scr(mx0,my0,mx0,my0); 
    x0+=mx-mx0; 
    y0+=my-my0; 
    _redraw=true; 
    } 
//--------------------------------------------------------------------------- 
void __fastcall TForm1::FormMouseMove(TObject *Sender, TShiftState Shift, int X,int Y) 
    { 
    mx=X; my=Y; 
    } 
//--------------------------------------------------------------------------- 

mx,my在屏幕座標實際鼠標位置,x0,y0是翻譯和zoom是規模。

在這裏拍攝的GIF動畫這樣的:

example

[EDIT1]它看起來像你的GFX對象使用transponed矩陣

這意味着變換的順序顛倒,等式改變了一點...這裏你的案例在C++

void scr2obj(double &ox,double &oy,double sx,double sy) 
{ 
// ox=(sx-x0)/zoom; 
// oy=(sy-y0)/zoom; 
ox=(sx/zoom)-x0; 
oy=(sy/zoom)-y0; 
} 
//--------------------------------------------------------------------------- 
void obj2scr(double &sx,double &sy,double ox,double oy) 
{ 
// sx=x0+(ox*zoom); 
// sy=y0+(oy*zoom); 
sx=(x0+ox)*zoom; 
sy=(y0+oy)*zoom; 
} 
//--------------------------------------------------------------------------- 
void __fastcall TForm1::FormMouseWheelDown(TObject *Sender, TShiftState Shift,TPoint &MousePos, bool &Handled) 
{ 
double mx0,my0; 
scr2obj(mx0,my0,mx,my); 
zoom/=1.25; // zoom out 
obj2scr(mx0,my0,mx0,my0); 
// x0+=mx-mx0; 
// y0+=my-my0; 
x0+=(mx-mx0)/zoom; 
y0+=(my-my0)/zoom; 
_redraw=true; 
} 
//--------------------------------------------------------------------------- 
void __fastcall TForm1::FormMouseWheelUp(TObject *Sender, TShiftState Shift, TPoint &MousePos, bool &Handled) 
{ 
double mx0,my0; 
scr2obj(mx0,my0,mx,my); 
zoom*=1.25; // zoom in 
obj2scr(mx0,my0,mx0,my0); 
// x0+=mx-mx0; 
// y0+=my-my0; 
x0+=(mx-mx0)/zoom; 
y0+=(my-my0)/zoom; 
_redraw=true; 
} 
//--------------------------------------------------------------------------- 
+0

當我使用你的代碼時,它做同樣的事情。你測試過了嗎?如果是這樣,你能提供整個班級的代碼嗎? –

+0

你在#2下的等式似乎和我的等式一樣。 _scale最終被取消,最終增加1.25。難道圖形座標與鼠標座標不一樣嗎? –

+0

@NathanBierema是的,我在寫作時犯了一個錯誤......(我之前做過很多次)早上很匆忙。請參閱已經添加的功能源代碼(來自VCL,但您可以簡單地將它移植到您的代碼中)。如果即使這不起作用,你的鼠標座標也不正確(不是相對於你的應用程序,而是相對於桌面) – Spektre

相關問題