Aracılığıyla paylaş


Fare hareketi

Fare hareket ettiğinde Windows bir WM_MOUSEMOVE iletisi yayınlar. Varsayılan olarak, WM_MOUSEMOVE imleci içeren pencereye gider. Sonraki bölümde açıklanan fare yakalayarak bu davranışı geçersiz kılabilirsiniz.

WM_MOUSEMOVE iletisi, fare tıklama iletileriyle aynı parametreleri içerir. en düşük 16 bit lParam x koordinatını, sonraki 16 bit ise y koordinatını içerir. lParamkoordinatlarını açmak için GET_X_LPARAM ve GET_Y_LPARAM makrolarını kullanın. wParam parametresi, diğer fare düğmelerinin ve SHIFT ve CTRL tuşlarının durumunu gösteren bit düzeyinde bir VEYA bayrak içerir. Aşağıdaki kod, lParamfare koordinatlarını alır.

int xPos = GET_X_LPARAM(lParam); 
int yPos = GET_Y_LPARAM(lParam);

Bu koordinatların cihazdan bağımsız pikseller (IP' ler) değil piksel cinsinden olduğunu unutmayın. Bu konunun ilerleyen bölümlerinde iki birim arasında dönüştürülen kodu inceleyeceğiz.

İmlecin konumu pencereye göre değişirse bir pencere de WM_MOUSEMOVE iletisi alabilir. Örneğin, imleç bir pencerenin üzerine konumlandırılırsa ve kullanıcı pencereyi gizlerse, fare hareket etmese bile pencere WM_MOUSEMOVE iletileri alır. Bu davranışın bir sonucu, fare koordinatlarının WM_MOUSEMOVE iletiler arasında değişemeyebilir.

Pencerenin dışında fare hareketini yakalama

Varsayılan olarak, fare istemci alanının kenarından geçerse pencere WM_MOUSEMOVE iletileri almayı durdurur. Ancak bazı işlemler için bu noktanın ötesindeki fare konumunu izlemeniz gerekebilir. Örneğin, bir çizim programı kullanıcının aşağıdaki diyagramda gösterildiği gibi seçim dikdörtgenini pencerenin kenarından ileriye sürüklemesini sağlayabilir.

Fare yakalamanın bir çizimini .

Pencerenin kenarından fareyle taşıma iletileri almak için SetCapture işlevini çağırın. Bu işlev çağrıldıktan sonra, kullanıcı pencerenin dışına taşınsa bile en az bir fare düğmesini basılı tuttuğu sürece pencere WM_MOUSEMOVE iletileri almaya devam eder. Yakalama penceresi ön plan penceresi olmalıdır ve aynı anda yalnızca bir pencere yakalama penceresi olabilir. Fare yakalamayı serbest bırakmak için ReleaseCapture işlevini çağırın.

Genellikle SetCapture ve ReleaseCapture aşağıdaki şekilde kullanırsınız.

  1. Kullanıcı sol fare düğmesine bastığında, fareyi yakalamaya başlamak için SetCaptureçağırın.
  2. Fareyle taşıma iletilerine yanıt verin.
  3. Kullanıcı sol fare düğmesini serbest bıraktığında ReleaseCaptureöğesini çağırın.

Örnek: daire çizme

Şimdi kullanıcının fareyle daire çizmesini sağlayarak Circle programını Module 3 genişletelim. Direct2D Circle Sample programıyla başlayın. Basit çizim eklemek için bu örnekteki kodu değiştireceğiz. İlk olarak, MainWindow sınıfına yeni bir üye değişkeni ekleyin.

D2D1_POINT_2F ptMouse;

Bu değişken, kullanıcı fareyi sürüklerken fare aşağı konumunu depolar. MainWindow oluşturucuda üç nokta başlatın ve ptMouse değişkenlerini.

    MainWindow() : pFactory(NULL), pRenderTarget(NULL), pBrush(NULL),
        ellipse(D2D1::Ellipse(D2D1::Point2F(), 0, 0)),
        ptMouse(D2D1::Point2F())
    {
    }

MainWindow::CalculateLayout yönteminin gövdesini kaldırın; bu örnek için gerekli değildir.

void CalculateLayout() { }

Ardından, sol düğme aşağı, sol düğme yukarı ve fareyle hareket eden iletiler için ileti işleyicilerini bildirin.

void OnLButtonDown(int pixelX, int pixelY, DWORD flags);
void OnLButtonUp();
void OnMouseMove(int pixelX, int pixelY, DWORD flags);

Fare koordinatları fiziksel piksel cinsinden verilir, ancak Direct2D cihazdan bağımsız pikseller (IP'ler) bekler. Yüksek DPI ayarlarını doğru şekilde işlemek için piksel koordinatlarını IP'lere çevirmeniz gerekir. DPI hakkında daha fazla bilgi için bkz. DPI ve Device-Independent Piksel. Aşağıdaki kod, pikselleri IP'lere dönüştüren bir yardımcı sınıfı gösterir.

class DPIScale
{
    static float scale;

public:
    static void Initialize(HWND hwnd)
    {
        float dpi = GetDpiForWindow(hwnd);
        scale = dpi/96.0f;
    }

    template <typename T>
    static D2D1_POINT_2F PixelsToDips(T x, T y)
    {
        return D2D1::Point2F(static_cast<float>(x) / scale, static_cast<float>(y) / scale);
    }
};

float DPIScale::scale = 1.0f;

Direct2D fabrika nesnesini oluşturduktan sonra WM_CREATE işleyicinizde DPIScale::Initialize çağrısı yapın.

case WM_CREATE:
    if (FAILED(D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &pFactory)))
    {
        return -1;  // Fail CreateWindowEx.
    }
    DPIScale::Initialize(hwnd);
    return 0;

FARE iletilerinden DIP'lerdeki fare koordinatlarını almak için aşağıdakileri yapın:

  1. Piksel koordinatlarını almak için GET_X_LPARAM ve GET_Y_LPARAM makrolarını kullanın. Bu makrolar WindowsX.h'de tanımlanır, bu nedenle bu üst bilgiyi projenize eklemeyi unutmayın.
  2. Pikselleri IP'lere dönüştürmek için DPIScale::PixelsToDips çağır.

Şimdi pencere yordamınıza ileti işleyicilerini ekleyin.

case WM_LBUTTONDOWN: 
    OnLButtonDown(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), (DWORD)wParam);
    return 0;

case WM_LBUTTONUP: 
    OnLButtonUp();
    return 0;

case WM_MOUSEMOVE: 
    OnMouseMove(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), (DWORD)wParam);
    return 0;

Son olarak, ileti işleyicilerini kendileri uygulayın.

Sol düğme aşağı

Sol düğme aşağı iletisi için aşağıdakileri yapın:

  1. Fareyi yakalamaya başlamak için SetCaptureçağırın.
  2. fare tıklamasının konumunu ptMouse değişkeninde depolayın. Bu konum, üç nokta için sınırlayıcı kutunun sol üst köşesini tanımlar.
  3. Üç nokta yapısını sıfırlayın.
  4. InvalidateRectçağrısı yapın. Bu işlev pencereyi yeniden boyanmaya zorlar.
void MainWindow::OnLButtonDown(int pixelX, int pixelY, DWORD flags)
{
    SetCapture(m_hwnd);
    ellipse.point = ptMouse = DPIScale::PixelsToDips(pixelX, pixelY);
    ellipse.radiusX = ellipse.radiusY = 1.0f; 
    InvalidateRect(m_hwnd, NULL, FALSE);
}

Fareyle hareket etme

Fare taşıma iletisi için, sol fare düğmesinin aşağı olup olmadığını denetleyin. Bu durumda, üç noktayı yeniden hesaplayın ve pencereyi yeniden boyayın. Direct2D'de üç nokta, merkez noktası ve x ve y yarıçapı ile tanımlanır. Fare aşağı noktası (ptMouse) ve geçerli imleç konumu (x, y) tarafından tanımlanan sınırlayıcı kutuya uyan bir üç nokta çizmek istiyoruz, bu nedenle üç noktanın genişliğini, yüksekliğini ve konumunu bulmak için biraz aritmetik gereklidir.

Aşağıdaki kod üç noktayı yeniden hesaplar ve sonra pencereyi yeniden boyamak için InvalidateRect çağırır.

x ve y yarıçaplarına sahip üç nokta gösteren Diyagramı.

void MainWindow::OnMouseMove(int pixelX, int pixelY, DWORD flags)
{
    if (flags & MK_LBUTTON) 
    { 
        const D2D1_POINT_2F dips = DPIScale::PixelsToDips(pixelX, pixelY);

        const float width = (dips.x - ptMouse.x) / 2;
        const float height = (dips.y - ptMouse.y) / 2;
        const float x1 = ptMouse.x + width;
        const float y1 = ptMouse.y + height;

        ellipse = D2D1::Ellipse(D2D1::Point2F(x1, y1), width, height);

        InvalidateRect(m_hwnd, NULL, FALSE);
    }
}

Sol düğme yukarı

Sol düğmeli ileti için, fare yakalamayı serbest bırakmak için ReleaseCapture çağırmanız yeterlidir.

void MainWindow::OnLButtonUp()
{
    ReleaseCapture(); 
}

Önümüzdeki