首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

C# 實現 PrintPreviewControl 滑鼠拖曳移動頁面功能

     編輯:關於C#

前言

在開發 Windows Forms 應用程式時,PrintPreviewControl 控制項常用於顯示列印預覽畫面。雖然該控制項內建水平與垂直捲軸,但使用者習慣像看圖軟體那樣,直接按住滑鼠左鍵拖曳頁面來瀏覽超出可視範圍的內容。可惜 .NET Framework 並未直接提供這項功能,我們必須自行實作。

核心思路:透過 Win API 控制捲軸

由於 PrintPreviewControl 未公開捲軸相關的方法或屬性,我們只能求助於 Windows API。關鍵在於呼叫 SetScrollPos 設定捲軸位置,再透過 PostMessage 發送捲動訊息(WM_HSCROLL / WM_VSCROLL),讓控制項真正重繪內容。若缺少 PostMessage,捲軸雖會移動,但頁面內容卻不會跟著更新——這是許多開發者容易踩的坑。

所需 API 宣告與常數

[DllImport("user32.dll")]
private static extern int SetScrollPos(IntPtr hwnd, int nBar, int nPos, bool bRedraw);

[DllImport("user32.dll")]
private static extern int GetScrollPos(IntPtr hwnd, int nBar);

[DllImport("user32.dll")]
private static extern bool PostMessage(IntPtr hWnd, int Msg, int wParam, int lParam);

[DllImport("user32", CharSet = CharSet.Auto)]
private static extern bool GetScrollRange(IntPtr hWnd, int nBar, out int lpMinPos, out int lpMaxPos);

private const int SB_HORZ = 0x0;
private const int SB_VERT = 0x1;
private const int WM_HSCROLL = 0x114;
private const int WM_VSCROLL = 0x115;
private const int SB_THUMBPOSITION = 4;

實作步驟

1. 定義狀態變數

bool isDragging = false;      // 是否正在拖曳
Point dragStart;              // 滑鼠按下時的座標
Point dragCurrent;            // 滑鼠移動時的目前座標

2. 滑鼠按下:記錄起始點

private void previewer_MouseDown(object sender, MouseEventArgs e)
{
    if (e.Button == MouseButtons.Left)
    {
        isDragging = true;
        dragStart = e.Location;
        previewer.Cursor = Cursors.SizeAll; // 視覺回饋
    }
}

3. 滑鼠移動:計算位移並更新捲軸

private void previewer_MouseMove(object sender, MouseEventArgs e)
{
    if (!isDragging) return;

    dragCurrent = e.Location;
    // 位移量除以 10 降低移動速度,負號使頁面跟隨滑鼠方向移動
    int deltaX = -(dragCurrent.X - dragStart.X) / 10;
    int deltaY = -(dragCurrent.Y - dragStart.Y) / 10;

    // 取得捲軸範圍與目前位置
    GetScrollRange(previewer.Handle, SB_HORZ, out int minH, out int maxH);
    GetScrollRange(previewer.Handle, SB_VERT, out int minV, out int maxV);
    int posH = GetScrollPos(previewer.Handle, SB_HORZ);
    int posV = GetScrollPos(previewer.Handle, SB_VERT);

    // 計算新位置並邊界檢查
    int newH = posH + deltaX;
    if (newH >= minH && newH <= maxH)
    {
        SetScrollPos(previewer.Handle, SB_HORZ, newH, true);
        // wParam: SB_THUMBPOSITION | (newH << 16)
        PostMessage(previewer.Handle, WM_HSCROLL, SB_THUMBPOSITION + 0x10000 * newH, 0);
    }

    int newV = posV + deltaY;
    if (newV >= minV && newV <= maxV)
    {
        SetScrollPos(previewer.Handle, SB_VERT, newV, true);
        PostMessage(previewer.Handle, WM_VSCROLL, SB_THUMBPOSITION + 0x10000 * newV, 0);
    }
}

4. 滑鼠放開:結束拖曳

private void previewer_MouseUp(object sender, MouseEventArgs e)
{
    if (e.Button == MouseButtons.Left)
    {
        isDragging = false;
        previewer.Cursor = Cursors.Default;
    }
}

補充說明

  • SB_THUMBPOSITION + 0x10000 * pos:PostMessage 的 wParam 高字組為捲軸新位置,低字組為捲動類型(SB_THUMBPOSITION 表示拖曳滑塊到指定位置)。
  • 同樣的技巧適用於任何擁有捲軸但未公開捲軸控制介面的 WinForms 控制項(如 Panel、PictureBox 等)。
  • 若需更平滑的體驗,可引入 WM_MOUSEWHEEL 處理滾輪縮放,或加入雙緩衝減少閃爍。

完整範例下載

完整專案原始碼可參考:推箱子專案原始碼(內含此拖曳邏輯的實作)。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved