cxnet 发表于 2024-10-22 18:24:07

图片放大缩小滚动条

C++ MFC 将Mat图置于Picture control中,怎样将图片放大缩小预览,当图像变大时Picture control控件自动显示水平和垂直滚动条用于上下左右移动图片

FishC 发表于 2024-10-22 18:31:06

在C++ MFC中将Mat图像放置于Picture Control中,并实现图像的缩放和滚动条功能,可以按以下步骤进行:

1. **Picture Control的初始化与Mat图像显示**:
   - 在对话框资源编辑器中添加一个Picture Control。
   - 使用OpenCV将Mat图像转化为HBITMAP,然后在`OnPaint`函数中使用`CDC::BitBlt`或`CDC::StretchBlt`将HBITMAP绘制到Picture Control上。

2. **缩放功能的实现**:
   - 添加鼠标滚轮消息的处理,在`OnMouseWheel`中实现缩放逻辑。
   - 可以通过调整Mat格式图像的尺寸(使用OpenCV的`resize`函数)来实现缩放。
   
3. **滚动条的处理**:
   - 使用CScrollView代替默认的CWnd。这样可以自动管理滚动条。
   - 重载`SetScrollSizes(MM_TEXT, CSize)`来设置滚动区域的大小。
   - 在缩放时,根据新的图像尺寸调整滚动条大小。

4. **示例代码框架**:

   BOOL CYourDlg::OnInitDialog()
   {
       CDialogEx::OnInitDialog();

       // 初始化滚动条、加载图片等
       UpdateImageView();

       return TRUE;
   }

   void CYourDlg::UpdateImageView()
   {
       CClientDC dc(this);
       CRect rect;
       GetClientRect(&rect);

       // 计算图像显示区域,注意缩放比例调整
       // 使用OpenCV的resize函数调整Mat图像尺寸

       // Set滚动条
       SetScrollSizes(MM_TEXT, CSize(image.cols, image.rows));
   }

   void CYourDlg::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
   {
       // 根据zDelta来调整缩放比例
       double scaleFactor = (zDelta > 0) ? 1.1 : 0.9;
       // 对Mat图像进行resize
       cv::resize(originalImage, scaledImage, Size(), scaleFactor, scaleFactor);

       // 更新视图和滚动条
       UpdateImageView();

       CDialogEx::OnMouseWheel(nFlags, zDelta, pt);
   }

通过以上步骤,完善你的对话框类,使其能够支持图像的缩放和滚动。请注意具体实现时需要检查各个OpenCV和MFC函数的适用情况。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。

cxnet 发表于 2024-10-22 18:47:59

FishC 发表于 2024-10-22 18:31
在C++ MFC中将Mat图像放置于Picture Control中,并实现图像的缩放和滚动条功能,可以按以下步骤进行:

1 ...

请给出详细的代码

FishC 发表于 2024-10-22 18:56:45

cxnet 发表于 2024-10-22 18:47
请给出详细的代码

实现该功能需要详细进行以下步骤:

### 1. 添加控件和类

确保在MFC对话框中添加一个Picture Control,并创建一个新的对话框类(例如,`CImageViewerDlg`)。

### 2. 转换Mat为HBITMAP

使用OpenCV将Mat图像转换为HBITMAP:

HBITMAP MatToHBITMAP(const cv::Mat& mat)
{
    cv::Mat temp;
    cv::cvtColor(mat, temp, cv::COLOR_BGR2BGRA);

    HBITMAP hBitmap = CreateBitmap(temp.cols, temp.rows, 1, 32, temp.data);
    return hBitmap;
}

### 3. 初始化滚动视图

在对话框类中初始化滚动条和处理绘图:

BOOL CImageViewerDlg::OnInitDialog()
{
    CDialogEx::OnInitDialog();

    // 将图片加载到Mat对象
    m_matImage = cv::imread("your_image_path.jpg");

    // 初始化滚动条
    CScrollBar* pHScrollBar = GetScrollBarCtrl(SB_HORZ);
    CScrollBar* pVScrollBar = GetScrollBarCtrl(SB_VERT);

    if (pHScrollBar && pVScrollBar)
    {
      SCROLLINFO si;
      si.fMask = SIF_RANGE | SIF_PAGE;
      si.nMin = 0;
      si.nMax = m_matImage.cols - 1;
      si.nPage = 100; // 视图大小
      pHScrollBar->SetScrollInfo(&si);

      si.nMax = m_matImage.rows - 1;
      pVScrollBar->SetScrollInfo(&si);
    }

    return TRUE;
}

### 4. 绘制图像

重载`OnPaint`来绘制Mat图像:

void CImageViewerDlg::OnPaint()
{
    CPaintDC dc(this);

    if (!m_matImage.empty())
    {
      HBITMAP hBitmap = MatToHBITMAP(m_matImage);
      CBitmap bitmap;
      bitmap.Attach(hBitmap);

      CDC memDC;
      memDC.CreateCompatibleDC(&dc);
      CBitmap* pOldBitmap = memDC.SelectObject(&bitmap);

      BITMAP bm;
      bitmap.GetBitmap(&bm);
      dc.BitBlt(0, 0, bm.bmWidth, bm.bmHeight, &memDC, 0, 0, SRCCOPY);

      memDC.SelectObject(pOldBitmap);
      DeleteObject(hBitmap);
    }
}

### 5. 处理缩放

响应鼠标滚轮事件来缩放:

BOOL CImageViewerDlg::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
{
    double scaleFactor = (zDelta > 0) ? 1.1 : 0.9;
    cv::resize(m_matImage, m_matImage, cv::Size(), scaleFactor, scaleFactor);

    // 更新滚动条信息
    CScrollBar* pHScrollBar = GetScrollBarCtrl(SB_HORZ);
    CScrollBar* pVScrollBar = GetScrollBarCtrl(SB_VERT);

    if (pHScrollBar && pVScrollBar)
    {
      SCROLLINFO si;
      si.fMask = SIF_RANGE | SIF_PAGE;
      si.nMin = 0;
      si.nMax = m_matImage.cols - 1;
      si.nPage = 100;
      pHScrollBar->SetScrollInfo(&si);

      si.nMax = m_matImage.rows - 1;
      pVScrollBar->SetScrollInfo(&si);
    }

    Invalidate();
    return CDialogEx::OnMouseWheel(nFlags, zDelta, pt);
}

### 6. 滚动图片

处理滚动:

void CImageViewerDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
    // 滚动处理代码
    CDialogEx::OnHScroll(nSBCode, nPos, pScrollBar);
}

void CImageViewerDlg::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
    // 滚动处理代码
    CDialogEx::OnVScroll(nSBCode, nPos, pScrollBar);
}

### 总结

以上代码为你的对话框添加了图片缩放和滚动条功能,但要测试和调试,以确保配置正确并适应你的应用场景。请根据你的具体需求做出相应调整。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。

cxnet 发表于 2024-10-24 09:56:29

FishC 发表于 2024-10-22 18:56
实现该功能需要详细进行以下步骤:

### 1. 添加控件和类


这些代码中Picture Control的变量名称是或者ID名称是设置的什么?没有看明白

FishC 发表于 2024-10-24 10:02:52

cxnet 发表于 2024-10-24 09:56
这些代码中Picture Control的变量名称是或者ID名称是 ...

在这些代码中,Picture Control的具体变量名称或ID没有指定,因为对Picture Control的操作通常是通过CDC在`OnPaint`中直接进行位图绘制。

如果你想通过变量进行访问,你可以为Picture Control添加一个控件变量。例如:

1. 在资源视图中,找到你的Picture Control。
2. 右键点击选择“添加变量”。
3. 为控件添加一个成员变量,例如:`m_PictureControl`。
4. 将控件的ID命名为合理的名称,例如:`IDC_PICTURE_CONTROL`。

之后,在代码中,你可以使用`m_PictureControl`进行访问和操作:

void CImageViewerDlg::OnPaint()
{
    CPaintDC dc(this);

    if (!m_matImage.empty())
    {
      HBITMAP hBitmap = MatToHBITMAP(m_matImage);
      CBitmap bitmap;
      bitmap.Attach(hBitmap);

      CDC memDC;
      memDC.CreateCompatibleDC(&dc);
      CBitmap* pOldBitmap = memDC.SelectObject(&bitmap);

      BITMAP bm;
      bitmap.GetBitmap(&bm);

      // 在m_PictureControl中绘制
      CRect rect;
      m_PictureControl.GetClientRect(&rect);
      dc.StretchBlt(0, 0, rect.Width(), rect.Height(), &memDC, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);

      memDC.SelectObject(pOldBitmap);
      DeleteObject(hBitmap);
    }
}

这样可以确保图像绘制在指定的Picture Control中。请根据具体设计调整代码。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。

cxnet 发表于 2024-10-24 10:28:10

FishC 发表于 2024-10-22 18:56
实现该功能需要详细进行以下步骤:

### 1. 添加控件和类


请给出处理滚动的详细代码

FishC 发表于 2024-10-24 10:28:32

cxnet 发表于 2024-10-24 10:28
请给出处理滚动的详细代码

下面是处理滚动条的详细代码示例:

### 滚动处理逻辑

1. **在类中添加成员变量**:

CPoint m_ScrollPos;// 记录滚动位置

2. **初始化滚动条**:

在`OnInitDialog`中设置滚动条:

BOOL CImageViewerDlg::OnInitDialog()
{
    CDialogEx::OnInitDialog();

    // 假设图片已经被加载到 m_matImage
    UpdateScrollInfo();

    return TRUE;
}

3. **更新滚动信息**:

void CImageViewerDlg::UpdateScrollInfo()
{
    if (!m_matImage.empty())
    {
      CScrollBar* pHScrollBar = GetScrollBarCtrl(SB_HORZ);
      CScrollBar* pVScrollBar = GetScrollBarCtrl(SB_VERT);

      if (pHScrollBar && pVScrollBar)
      {
            SCROLLINFO si;
            si.fMask = SIF_RANGE | SIF_PAGE;
            si.nMin = 0;
            si.nPage = 100;
            si.nMax = m_matImage.cols - 1;
            pHScrollBar->SetScrollInfo(&si);

            si.nMax = m_matImage.rows - 1;
            pVScrollBar->SetScrollInfo(&si);
      }
    }
}

4. **处理水平滚动**:

void CImageViewerDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
    int scrollPos;
    SCROLLINFO si = { sizeof(si), SIF_ALL };
    pScrollBar->GetScrollInfo(&si);

    switch (nSBCode)
    {
    case SB_LEFT:
      scrollPos = si.nMin;
      break;
    case SB_RIGHT:
      scrollPos = si.nMax;
      break;
    case SB_LINELEFT:
      scrollPos = max(si.nMin, si.nPos - 10);
      break;
    case SB_LINERIGHT:
      scrollPos = min(si.nMax, si.nPos + 10);
      break;
    case SB_PAGELEFT:
      scrollPos = max(si.nMin, si.nPos - (int)si.nPage);
      break;
    case SB_PAGERIGHT:
      scrollPos = min(si.nMax, si.nPos + (int)si.nPage);
      break;
    case SB_THUMBTRACK:
      scrollPos = nPos;
      break;
    default:
      return;
    }

    pScrollBar->SetScrollPos(scrollPos);
    m_ScrollPos.x = scrollPos;
    Invalidate();
}

5. **处理垂直滚动**:

void CImageViewerDlg::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
    int scrollPos;
    SCROLLINFO si = { sizeof(si), SIF_ALL };
    pScrollBar->GetScrollInfo(&si);

    switch (nSBCode)
    {
    case SB_TOP:
      scrollPos = si.nMin;
      break;
    case SB_BOTTOM:
      scrollPos = si.nMax;
      break;
    case SB_LINEUP:
      scrollPos = max(si.nMin, si.nPos - 10);
      break;
    case SB_LINEDOWN:
      scrollPos = min(si.nMax, si.nPos + 10);
      break;
    case SB_PAGEUP:
      scrollPos = max(si.nMin, si.nPos - (int)si.nPage);
      break;
    case SB_PAGEDOWN:
      scrollPos = min(si.nMax, si.nPos + (int)si.nPage);
      break;
    case SB_THUMBTRACK:
      scrollPos = nPos;
      break;
    default:
      return;
    }

    pScrollBar->SetScrollPos(scrollPos);
    m_ScrollPos.y = scrollPos;
    Invalidate();
}

### 总结

这些代码实现了滚动条的基本处理功能,记得在`OnPaint`中使用`m_ScrollPos`来调整图片绘制位置。例如:

dc.StretchBlt(0, 0, rect.Width(), rect.Height(), &memDC, m_ScrollPos.x, m_ScrollPos.y, bm.bmWidth, bm.bmHeight, SRCCOPY);

调整这些代码以适应你的具体需求和应用场景。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。

cxnet 发表于 2024-10-24 11:45:51

FishC 发表于 2024-10-24 10:28
下面是处理滚动条的详细代码示例:

### 滚动处理逻辑


提示错误
“GetScrollBarCtrl”: 找不到标识符

FishC 发表于 2024-10-24 11:48:17

cxnet 发表于 2024-10-24 11:45
提示错误
“GetScrollBarCtrl”: 找不到标识符

对于MFC对话框,`GetScrollBarCtrl`适用于视图类而非对话框。你需要手动管理滚动条。以下是如何修改代码来处理滚动条的示例:

### 修改初始化滚动条

在`OnInitDialog`中,手动设置滚动条的范围和位置:

BOOL CImageViewerDlg::OnInitDialog()
{
    CDialogEx::OnInitDialog();

    // 假设图片已经被加载到 m_matImage
    UpdateScrollInfo();

    return TRUE;
}

### 更新滚动信息

手动控制滚动条的更新:

void CImageViewerDlg::UpdateScrollInfo()
{
    if (!m_matImage.empty())
    {
      SCROLLINFO si;
      si.cbSize = sizeof(SCROLLINFO);
      si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
      si.nMin = 0;
      si.nPage = 100;

      // 水平滚动信息
      si.nMax = m_matImage.cols - 1;
      si.nPos = m_ScrollPos.x;
      SetScrollInfo(SB_HORZ, &si, TRUE);

      // 垂直滚动信息
      si.nMax = m_matImage.rows - 1;
      si.nPos = m_ScrollPos.y;
      SetScrollInfo(SB_VERT, &si, TRUE);
    }
}

### 处理水平滚动

手动调整水平滚动:

void CImageViewerDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
    int scrollPos = GetScrollPos(SB_HORZ);

    switch (nSBCode)
    {
    case SB_LEFT:
      scrollPos = 0;
      break;
    case SB_RIGHT:
      scrollPos = m_matImage.cols - 1;
      break;
    case SB_LINELEFT:
      scrollPos = max(0, scrollPos - 10);
      break;
    case SB_LINERIGHT:
      scrollPos = min(m_matImage.cols - 1, scrollPos + 10);
      break;
    case SB_PAGELEFT:
      scrollPos = max(0, scrollPos - 100);
      break;
    case SB_PAGERIGHT:
      scrollPos = min(m_matImage.cols - 1, scrollPos + 100);
      break;
    case SB_THUMBTRACK:
      scrollPos = nPos;
      break;
    default:
      return;
    }

    SetScrollPos(SB_HORZ, scrollPos);
    m_ScrollPos.x = scrollPos;
    Invalidate();
}

### 处理垂直滚动

手动调整垂直滚动:

void CImageViewerDlg::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
    int scrollPos = GetScrollPos(SB_VERT);

    switch (nSBCode)
    {
    case SB_TOP:
      scrollPos = 0;
      break;
    case SB_BOTTOM:
      scrollPos = m_matImage.rows - 1;
      break;
    case SB_LINEUP:
      scrollPos = max(0, scrollPos - 10);
      break;
    case SB_LINEDOWN:
      scrollPos = min(m_matImage.rows - 1, scrollPos + 10);
      break;
    case SB_PAGEUP:
      scrollPos = max(0, scrollPos - 100);
      break;
    case SB_PAGEDOWN:
      scrollPos = min(m_matImage.rows - 1, scrollPos + 100);
      break;
    case SB_THUMBTRACK:
      scrollPos = nPos;
      break;
    default:
      return;
    }

    SetScrollPos(SB_VERT, scrollPos);
    m_ScrollPos.y = scrollPos;
    Invalidate();
}

### 总结

确保调用`UpdateScrollInfo`来调整滚动条的信息,并在`OnPaint`中使用`m_ScrollPos`调整绘制位置。这些代码应适合用于MFC对话框中的手动滚动处理。根据你的具体需求,进一步调整代码。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
页: [1]
查看完整版本: 图片放大缩小滚动条