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

打造企業級 WinForms 圖片瀏覽控件:縮放、漫游、旋轉、打印全功能實現

     編輯:關於C語言

在企業級 WinForms 開發中,專業的圖片瀏覽控件是剛需。本文分享一個開源級 UcImageView 控件的完整實現,涵蓋鼠標滾輪縮放、拖拽漫游、90°旋轉、適應大小、打印輸出等核心功能,代碼結構清晰,可直接集成或二次開發。

控件架構概覽

控件繼承 UserControl,核心組件:

  • PictureBox (picView):承載圖像
  • Panel (PnlMain):可視區域容器
  • 雙向滾動條 (hScrollBarImageView, vScrollBarImageView):大圖導航
  • 右鍵菜單:縮放、漫游、旋轉、打印命令

控件運行效果

核心功能實現詳解

1. 智能縮放:以滾輪位置為中心

關鍵邏輯在 zoom(Point center, int zoomIndexBy1000):

private void zoom(Point center, int zoomIndexBy1000) {
    Point oldSize = new Point(picView.Width, picView.Height);
    // 以 X 方向為基準縮放,Y 方向按比例計算,避免累積誤差
    picView.Width = picView.Width * zoomIndexBy1000 / 1000;
    picView.Height = picView.Width * imgIndexBy1000 / 1000;

    // 重新定位:保持滾輪位置對應的圖像點不變
    picView.Left -= ((picView.Width - oldSize.X) * (center.X * 1000 / oldSize.X)) / 1000;
    picView.Top  -= ((picView.Height - oldSize.Y) * (center.Y * 1000 / oldSize.Y)) / 1000;

    UpdateScrollBars(); // 同步滾動條可見性、最大值、Value
}

滾輪事件處理 (picView_MouseWheel):

private void picView_MouseWheel(object sender, MouseEventArgs e) {
    if (Control.ModifierKeys == Keys.Control) { // Ctrl+滾輪 = 縮放
        if (e.Delta > 0 && picView.Width < 10000) zoom(e.Location, 1100); // 放大 10%
        else if (e.Delta < 0 && picView.Image.Width / picView.Width < 5) zoom(e.Location, 900); // 縮小 10%
        CenterImage();
    } else if (Control.ModifierKeys == Keys.Shift) { // Shift+滾輪 = 水平滾動
        if (hScrollBarImageView.Visible) AdjustScroll(hScrollBarImageView, e.Delta);
    } else { // 普通滾輪 = 垂直滾動
        if (vScrollBarImageView.Visible) AdjustScroll(vScrollBarImageView, e.Delta);
    }
}

2. 拖拽漫游:無縫銜接滾動條

鼠標按下記錄起始點,移動時計算偏移並同步滾動條:

private void picView_MouseMove(object sender, MouseEventArgs e) {
    if (!mnuMoveChecked || !_isMouseDown) return;

    int dx = _startPoint.X - e.X;
    int dy = _startPoint.Y - e.Y;
    int newX = -picView.Left + dx;
    int newY = -picView.Top  + dy;

    // 邊界檢查後更新滾動條 Value,觸發 ValueChanged 事件移動圖片
    if (hScrollBarImageView.Visible) hScrollBarImageView.Value = Clamp(newX, 0, hScrollBarImageView.Maximum);
    else picView.Left = -newX;

    if (vScrollBarImageView.Visible) vScrollBarImageView.Value = Clamp(newY, 0, vScrollBarImageView.Maximum);
    else picView.Top = -newY;
}

3. 容器尺寸變化時保持視圖穩定

PnlMain_Resize 確保縮放/最大化視窗時,圖片相對中心點位置不變,滾動條同步更新。

4. 旋轉與適應大小

public void LeftRotateImage() {
    if (picView.Image != null) {
        picView.Image.RotateFlip(RotateFlipType.Rotate90FlipX);
        picView.Refresh();
        CenterImage();
    }
}

public void FitImageSize() {
    if (picView.Image == null) return;
    float ratioX = (float)PnlMain.Width / picView.Width;
    float ratioY = (float)PnlMain.Height / picView.Height;
    float ratio = Math.Min(ratioX, ratioY);
    picView.Scale(ratio, ratio);
    CenterImage();
}

5. 異步加載大圖

public void AddImage(string fileName, bool isAsync) {
    if (isAsync) {
        picView.LoadCompleted += (s, e) => picView.UseWaitCursor = false;
        picView.UseWaitCursor = true;
        picView.WaitOnLoad = false;
        picView.LoadAsync(fileName);
    } else {
        picView.Image = Image.FromFile(fileName);
    }
    InitialImage(); // 重置縮放、滾動條、居中
}

6. 打印輸出

private void mnuPrint_Click(object sender, EventArgs e) {
    if (picView.Image == null) return;
    using (var dlg = new PrintDialog { Document = _printDoc }) {
        if (dlg.ShowDialog() == DialogResult.OK) {
            _printDoc.Print();
        }
    }
}

private void printDoc_PrintPage(object sender, PrintPageEventArgs e) {
    FitImageSize(); // 打印按適應大小
    e.Graphics.DrawImage(picView.Image, picView.Location.X, picView.Location.Y, picView.Width, picView.Height);
}

WinForms 主視窗調用示例

public partial class FrmImageViewer : Form {
    public FrmImageViewer() { InitializeComponent(); }

    private void FrmImageViewer_Shown(object sender, EventArgs e) {
        ucImageView.AddImage(Image.FromFile(Application.StartupPath + @"\Windows7.jpg"));
    }

    private void btnOpen_Click(object sender, EventArgs e) {
        if (openFileDialog.ShowDialog() == DialogResult.OK)
            ucImageView.AddImage(Image.FromFile(openFileDialog.FileName));
    }

    private void btnZoomIn_Click(object sender, EventArgs e) => ucImageView.ZoomInImage();
    private void btnZoomOut_Click(object sender, EventArgs e) => ucImageView.ZoomOutImage();
    private void btnFitSize_Click(object sender, EventArgs e) => ucImageView.FitImageSize();
    private void btnRotateLeft_Click(object sender, EventArgs e) => ucImageView.LeftRotateImage();
    private void btnRotateRight_Click(object sender, EventArgs e) => ucImageView.RightRotateImage();
    private void btnPan_Click(object sender, EventArgs e) {
        btnPan.Checked = ucImageView.MoveImageChecked = !btnPan.Checked;
        ucImageView.MoveImage();
    }

    // 同步控件內部菜單狀態
    private void ucImageView_OnMoveImageCheckedChanged(object sender, EventArgs e)
        => btnPan.Checked = ucImageView.MoveImageChecked;
}

擴展建議

  • 添加縮略圖導航條:大圖定位更直觀
  • 支援多頁 TIFF/PDF:集成 System.Drawing.Imaging 幀選擇
  • 增加標註/測量圖層:矩形、箭頭、文字覆蓋層
  • WPF 版本:利用 WriteableBitmap 實現硬件加速渲染

結語

這個 UcImageView 控件雖不及 ACDSee 專業,但作為企業級應用的嵌入式圖片查看器,功能完整、代碼開源、易於定製。核心在於座標變換數學(縮放中心點不變、滾動條同步、容器尺寸變化補償)的精確把控。歡迎 Fork 擴展,共同打磨更強大的組件庫。

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