error C2440: "reinterpret_cast":无法从"NMHDR*"转换为"NMITEMACTIVATE"

本文记录了在VS2008环境下使用C++处理LIST控件NM_DBCLICK消息时遇到的一个bug,详细介绍了错误原因及解决办法。

 

VC 2008 LIST CONTROL的BUG

    随着.NET平台的推出,微软的IDE越来越傻瓜化,编程的门槛越来越低。VS2003还没学会,马上就出了VS2005,一转眼现在己是VS2008当道。而对于MFC程序员来说,似乎受到了冷落,自VC6.0到现在,MFC几乎没有更新,因此很多程序员还在坚守经典的VC6.0

    我这个菜鸟程序员也跟着从VC6.0VS2005,到现在的VS2008。虽说VS2008身材臃肿,比VC6.0慢了不少,但其强大的编辑功能还是让我爱不释手,这次的主角就是VS 2008

    我用得最多的就是在VS2008下用C++编程,这两天为了赶一个项目,忙得昏天喑地。处理LIST控件的NM_DBCLIK消息应该是每个程序员都会的事情,我的处理函数如下:

    void CDlgTg::OnNMDblclkList(NMHDR *pNMHDR, LRESULT *pResult)

   {

 LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<NMITEMACTIVATE>(pNMHDR);

 ...    //这里省略我的代码

 *pResult = 0;

    }

    一编译,竞然报错:

    error C2440: "reinterpret_cast":无法从"NMHDR*"转换为"NMITEMACTIVATE"

    这可不是我的代码,这是大名鼎鼎的微软给我自动生成的。由于忙了很久,头脑有点乱(归根到底还是自己太菜_:) ),百思不得其解,VS2008可是Microsoft的拳头产品,对最新C++标准支持是最好的。

    休息几分钟,再来看,终于明白。pNMHDR是一个指针,reinterpret_castNMHDR *强制转换成NMITEMACTIVATE,应该说这种这种转换在任何时候都行不通。对指针稍微了解的人都知道,其本意是想转换成NMITEMACTIVATE*, 这一下豁然开朗,其实就是少了一个字符。把代码改成:

     void CDlgTg::OnNMDblclkList(NMHDR *pNMHDR, LRESULT *pResult)

   {

 LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<NMITEMACTIVATE*>(pNMHDR);

 ...    //这里省略我的代码

 *pResult = 0;

    }

    顺利通过。

    后来测试了一下,NM_CLICK消息也有这样的问题。由此猜想可能处理其他通用控件消息的时候也会有这样的问题(待证实)

    到此问题顺利解决,只是不知道是我机器的问题,还是Microsoft的问题。如果Microsoft的问题,心中不免暗自得意,原来Microsoft的程序员也有粗心的时候(原来大公司的程序员也不是那么神秘...)VS2008傻爪化的功能提高效率的同时,也埋下了隐患。我们这些还在用C++的古董程序员在出现问题的时候还是不要过于依赖IDE

 

源文档 <http://www.raildoor.com/blog/u/2956/archives/2009/1431.html>

 

#pragma once #include <vector> #include <opencv2/opencv.hpp> #include <tesseract/baseapi.h> #include <leptonica/allheaders.h> #include <thread> #include <atomic> #include <mutex> #include <string> #include <algorithm> #include "afxwin.h" #include <shlwapi.h> // 包含 StrCmpLogicalW 函数 #include <atlimage.h> // 添加CImage头文件 #include <tesseract/baseapi.h> #include <leptonica/allheaders.h> #include <iostream> #include <Windows.h> // 用于获取屏幕分辨率 using namespace cv; using namespace std; #pragma comment(lib, "Shlwapi.lib") // 链接 StrCmpLogicalW 所需的库 //#pragma comment(lib, "atlimage.lib") // 链接CImage库 #define WM_UPDATE_DISPLAY_IMAGE (WM_USER + 2) // B2saomiaotuxiangchuangkou 对话框 class B2saomiaotuxiangchuangkou : public CDialogEx { DECLARE_DYNAMIC(B2saomiaotuxiangchuangkou) public: B2saomiaotuxiangchuangkou(CWnd* pParent = NULL); // 标准构造函数 virtual ~B2saomiaotuxiangchuangkou(); enum { WM_LOAD_FIRST_IMAGE = WM_USER + 1 }; // 自定义控件布局调整函数(类似 SetControlPosition) void SetControlPosition(CWnd* pCtrl, int x, int y, int width, int height); void AdjustLayoutWhenResized(); // 对话框数据 #ifdef AFX_DESIGN_TIME enum { IDD = IDD_B2saomiaotuxiangchuangkou }; #endif protected: virtual void DoDataExchange(CDataExchange* pDX); virtual BOOL OnInitDialog(); afx_msg void OnSize(UINT nType, int cx, int cy); afx_msg void OnBnClickedButtonSelectFolder(); afx_msg void OnBnClickedButtonStart(); afx_msg void OnBnClickedButtonPause(); afx_msg void OnBnClickedButtonStop(); afx_msg void OnBnClickedButtonReset(); afx_msg void OnCbnSelchangeComboSaveOption(); afx_msg void OnTimer(UINT_PTR nIDEvent); afx_msg void OnLvnItemchangedListImages(NMHDR* pNMHDR, LRESULT* pResult); afx_msg LRESULT OnLoadFirstImageMessage(WPARAM wParam, LPARAM lParam); afx_msg LRESULT OnUpdateDisplayImage(WPARAM wParam, LPARAM lParam); afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt); afx_msg BOOL OnEraseBkgnd(CDC* pDC); DECLARE_MESSAGE_MAP() private: void ProcessImages(); void ProcessImage(const CString& filePath); bool LoadImageToControl(const CString& filePath, UINT controlID); HBITMAP LoadImageWithOpenCV(const CString& filePath); HBITMAP LoadImageWithGDIPlus(const CString& filePath); HBITMAP LoadImageWithCImage(const CString& filePath); // 新增CImage加载函数 HBITMAP MatToBitmap(cv::Mat& mat, UINT controlID); // 新增函数 void UpdateProgressBars(); void Cleanup(); void CreateBackup(); void RestoreBackup(); void SaveImage(cv::Mat& img, const CString& filePath); /*void SimpleBinarization(cv::Mat& input, cv::Mat& output);*/ void DisplayFirstImage(); CString GetFileNameFromPath(const CString& filePath); void LoadFilesIntoListControl(); void UpdateDisplayImage(const CString& filePath); private: CEdit m_editFolderPath; CListCtrl m_listImages; CComboBox m_saveOption; CButton m_btnStart; CButton m_btnPause; CButton m_btnStop; CButton m_btnReset; CButton m_btnSelectFolder; CProgressCtrl m_totalProgress; CProgressCtrl m_fileProgress; CStatic m_picOriginal; CStatic m_picProcessed; CEdit m_editSavePath; std::vector<CString> m_imageFiles; CString m_folderPath; CString m_savePath; CString m_backupPath; std::atomic<bool> m_processing{ false }; std::atomic<bool> m_paused{ false }; std::atomic<bool> m_stopped{ false }; std::atomic<int> m_currentIndex{ 0 }; std::thread m_processingThread; std::mutex m_mutex; std::mutex m_imageMutex; std::mutex m_bitmapMutex; bool m_firstImageLoaded{ false }; bool m_firstLoadCompleted{ false }; bool m_imageLoaded{ false }; HBITMAP m_currentBitmap{ NULL }; enum ImageLoadMode { MODE_OPENCV, MODE_GDIPlus, MODE_CIMAGE }; // 新增CIMAGE模式 ImageLoadMode m_loadMode{ MODE_CIMAGE }; // 默认使用CImage加载 CRect m_originalRect; CRect m_processedRect; private: // 新增OCR相关函数 cv::Mat rotateImage(const cv::Mat& src, double angle); cv::Mat resizeToFitScreen(const cv::Mat& img); void PerformOCRAndRotation(const CString& imagePath, cv::Mat& inputImage, cv::Mat& outputImage); // 新增Tesseract实例 tesseract::TessBaseAPI m_tess; bool m_tessInitialized{ false }; };// B2saomiaotuxiangchuangkou.cpp : 实现文件 // #include "stdafx.h" #include "Imageprocessing.h" #include "B2saomiaotuxiangchuangkou.h" #include "afxdialogex.h" #include <string> #include <chrono> #include <Gdiplus.h> #include <shlwapi.h> #pragma comment(lib, "Gdiplus.lib") #pragma comment(lib, "shlwapi.lib") #pragma comment(lib, "Shell32.lib") // GDI+初始化全局变量 Gdiplus::GdiplusStartupInput gdiplusInput; ULONG_PTR gdiplusToken; IMPLEMENT_DYNAMIC(B2saomiaotuxiangchuangkou, CDialogEx) B2saomiaotuxiangchuangkou::B2saomiaotuxiangchuangkou(CWnd* pParent /*=NULL*/) : CDialogEx(IDD_B2saomiaotuxiangchuangkou, pParent) { } B2saomiaotuxiangchuangkou::~B2saomiaotuxiangchuangkou() { Cleanup(); Gdiplus::GdiplusShutdown(gdiplusToken); // 释放GDI+资源 // 释放Tesseract资源 if (m_tessInitialized) { m_tess.End(); } } void B2saomiaotuxiangchuangkou::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); DDX_Control(pDX, IDC_EDIT_FOLDER_PATH, m_editFolderPath); DDX_Control(pDX, IDC_LIST_IMAGES, m_listImages); DDX_Control(pDX, IDC_COMBO_SAVE_OPTION, m_saveOption); DDX_Control(pDX, IDC_BUTTON_START, m_btnStart); DDX_Control(pDX, IDC_BUTTON_PAUSE, m_btnPause); DDX_Control(pDX, IDC_BUTTON_STOP, m_btnStop); DDX_Control(pDX, IDC_BUTTON_RESET, m_btnReset); DDX_Control(pDX, IDC_BUTTON_SELECT_FOLDER, m_btnSelectFolder); DDX_Control(pDX, IDC_PROGRESS_TOTAL, m_totalProgress); DDX_Control(pDX, IDC_PROGRESS_FILE, m_fileProgress); DDX_Control(pDX, IDC_STATIC_ORIGINAL_IMAGE, m_picOriginal); DDX_Control(pDX, IDC_STATIC_PROCESSED_IMAGE, m_picProcessed); DDX_Control(pDX, IDC_EDIT2, m_editSavePath); } BEGIN_MESSAGE_MAP(B2saomiaotuxiangchuangkou, CDialogEx) ON_WM_SIZE() ON_BN_CLICKED(IDC_BUTTON_SELECT_FOLDER, &B2saomiaotuxiangchuangkou::OnBnClickedButtonSelectFolder) ON_BN_CLICKED(IDC_BUTTON_START, &B2saomiaotuxiangchuangkou::OnBnClickedButtonStart) ON_BN_CLICKED(IDC_BUTTON_PAUSE, &B2saomiaotuxiangchuangkou::OnBnClickedButtonPause) ON_BN_CLICKED(IDC_BUTTON_STOP, &B2saomiaotuxiangchuangkou::OnBnClickedButtonStop) ON_BN_CLICKED(IDC_BUTTON_RESET, &B2saomiaotuxiangchuangkou::OnBnClickedButtonReset) ON_CBN_SELCHANGE(IDC_COMBO_SAVE_OPTION, &B2saomiaotuxiangchuangkou::OnCbnSelchangeComboSaveOption) ON_WM_TIMER() ON_NOTIFY(LVN_ITEMCHANGED, IDC_LIST_IMAGES, &B2saomiaotuxiangchuangkou::OnLvnItemchangedListImages) ON_MESSAGE(WM_LOAD_FIRST_IMAGE, &B2saomiaotuxiangchuangkou::OnLoadFirstImageMessage) ON_MESSAGE(WM_UPDATE_DISPLAY_IMAGE, &B2saomiaotuxiangchuangkou::OnUpdateDisplayImage) ON_WM_MOUSEWHEEL() ON_WM_ERASEBKGND() END_MESSAGE_MAP() BOOL B2saomiaotuxiangchuangkou::OnInitDialog() { CDialogEx::OnInitDialog(); ////////////////////////////////////////////////////////////////////////////////////////////// // 初始化Tesseract OCR if (m_tess.Init(nullptr, "chi_sim")) { AfxMessageBox(_T("无法初始化Tesseract OCR引擎!")); m_tessInitialized = false; } else { m_tessInitialized = true; } ////////////////////////////////////////////////////////////////////////////////////////////// m_listImages.SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES); m_listImages.InsertColumn(0, _T("文件名"), LVCFMT_LEFT, 200); m_listImages.InsertColumn(1, _T("大小"), LVCFMT_RIGHT, 100); m_listImages.InsertColumn(2, _T("类型"), LVCFMT_LEFT, 100); m_saveOption.AddString(_T("覆盖原图")); m_saveOption.AddString(_T("新路径")); m_saveOption.SetCurSel(0); m_totalProgress.SetRange(0, 100); m_fileProgress.SetRange(0, 100); m_totalProgress.SetPos(0); m_fileProgress.SetPos(0); m_btnPause.EnableWindow(FALSE); m_btnStop.EnableWindow(FALSE); m_btnReset.EnableWindow(FALSE); m_picOriginal.ModifyStyle(0, SS_BITMAP); m_picProcessed.ModifyStyle(0, SS_BITMAP); m_picOriginal.GetWindowRect(&m_originalRect); ScreenToClient(&m_originalRect); m_picProcessed.GetWindowRect(&m_processedRect); ScreenToClient(&m_processedRect); // 初始化GDI+ Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusInput, NULL); if (!m_folderPath.IsEmpty()) { PostMessage(WM_LOAD_FIRST_IMAGE, 0, 0); } return TRUE; } void B2saomiaotuxiangchuangkou::SetControlPosition(CWnd* pCtrl, int x, int y, int width, int height) { if (pCtrl) { CRect rect(x, y, x + width, y + height); pCtrl->MoveWindow(rect); } } void B2saomiaotuxiangchuangkou::AdjustLayoutWhenResized() { CRect clientRect; GetClientRect(&clientRect); int cx = clientRect.Width(); int cy = clientRect.Height(); // 获取屏幕尺寸(可选,若需要基于屏幕比例布局) int sW = GetSystemMetrics(SM_CXSCREEN); int sH = GetSystemMetrics(SM_CYSCREEN); int pc_W1 = (cx - 530) / 3;//图像显示控件宽 int pc_H1;//图像显示控件高 int pc_W2 = (cy - 530) / 3 * 2;//图像显示控件宽 int pc_H2;//图像显示控件高 // 示例:调整子界面中控件的位置(类似你提供的代码) SetControlPosition(GetDlgItem(IDC_STATIC1), 0, 5, 80, 30); /**/ SetControlPosition(GetDlgItem(IDC_STATIC2), 0, 50, 80, 30); /**/SetControlPosition(GetDlgItem(IDC_EDIT_FOLDER_PATH), 85, 43, 280, 30); /**/SetControlPosition(GetDlgItem(IDC_BUTTON_SELECT_FOLDER), 366, 44, 70, 30); /**/SetControlPosition(GetDlgItem(IDC_BUTTON_START), 440, 43, 70, 30);/**/SetControlPosition(GetDlgItem(IDC_STATIC_ORIGINAL_IMAGE), 530, 5, pc_W1 - 1, 490);/**/SetControlPosition(GetDlgItem(IDC_STATIC_PROCESSED_IMAGE), 530 + pc_W1 + 2, 5, 2 * pc_W1 - 5, cy - 10); SetControlPosition(GetDlgItem(IDC_STATIC3), 0, 90, 80, 30); /**/SetControlPosition(GetDlgItem(IDC_EDIT2), 85, 83, 280, 30); /**/SetControlPosition(GetDlgItem(IDC_COMBO_SAVE_OPTION), 366, 89, 70, 30); /**/SetControlPosition(GetDlgItem(IDC_BUTTON_PAUSE), 440, 84, 70, 30); SetControlPosition(GetDlgItem(IDC_STATIC4), 0, 155, 80, 30); /**/ /**/SetControlPosition(GetDlgItem(IDC_BUTTON_STOP), 440, 124, 70, 30); SetControlPosition(GetDlgItem(IDC_STATIC6), 0, 200, 80, 30); /**/SetControlPosition(GetDlgItem(IDC_PROGRESS_TOTAL), 85, 197, 280, 20); /**/SetControlPosition(GetDlgItem(IDC_BUTTON_RESET), 440, 164, 70, 30); SetControlPosition(GetDlgItem(IDC_STATIC7), 0, 240, 80, 30); /**/SetControlPosition(GetDlgItem(IDC_PROGRESS_FILE), 85, 237, 180, 20); SetControlPosition(GetDlgItem(IDC_STATIC8), 0, 305, 80, 30); /**/ /*SetControlPosition(GetDlgItem(IDC_STATIC8), 0, 305, 80, 30); /**/ /*SetControlPosition(GetDlgItem(IDC_STATIC8), 0, 305, 80, 30);*/ /**/ SetControlPosition(GetDlgItem(IDC_LIST_IMAGES), 0, 500, 530 + pc_W1 - 1, cy - 500 - 5); /**/ } void B2saomiaotuxiangchuangkou::OnSize(UINT nType, int cx, int cy) { CDialogEx::OnSize(nType, cx, cy); if (nType != SIZE_MINIMIZED) { AdjustLayoutWhenResized(); } } void B2saomiaotuxiangchuangkou::LoadFilesIntoListControl() { m_listImages.DeleteAllItems(); m_imageFiles.clear(); m_imageLoaded = false; m_firstLoadCompleted = false; std::vector<CString> files; CString searchPath = m_folderPath + _T("\\*.*"); WIN32_FIND_DATA findFileData; HANDLE hFind = FindFirstFile(searchPath, &findFileData); if (hFind != INVALID_HANDLE_VALUE) { do { if (!(findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { CString fileName = findFileData.cFileName; CString ext = fileName.Right(4).MakeLower(); // 扩展支持的图像格式 if (ext == _T(".jpg") || ext == _T(".jpeg") || ext == _T(".png") || ext == _T(".bmp") || ext == _T(".tif") || ext == _T(".tiff") || ext == _T(".webp") || ext == _T(".jp2")) { files.push_back(fileName); } } } while (FindNextFile(hFind, &findFileData)); FindClose(hFind); } std::sort(files.begin(), files.end(), [](const CString& a, const CString& b) { return StrCmpLogicalW(a, b) < 0; }); for (size_t i = 0; i < files.size(); ++i) { CString fileName = files[i]; CString filePath = m_folderPath + _T("\\") + fileName; m_imageFiles.push_back(filePath); int nIndex = m_listImages.InsertItem(i, fileName); WIN32_FILE_ATTRIBUTE_DATA fad; ULONGLONG fileSize = 0; if (GetFileAttributesEx(filePath, GetFileExInfoStandard, &fad)) { fileSize = ((ULONGLONG)fad.nFileSizeHigh << 32) | fad.nFileSizeLow; } CString sizeStr; if (fileSize < 1024) sizeStr.Format(_T("%d B"), fileSize); else if (fileSize < 1024 * 1024) sizeStr.Format(_T("%.2f KB"), fileSize / 1024.0); else sizeStr.Format(_T("%.2f MB"), fileSize / (1024.0 * 1024.0)); m_listImages.SetItemText(nIndex, 1, sizeStr); CString typeStr = fileName.Right(4).Mid(1).MakeUpper(); m_listImages.SetItemText(nIndex, 2, typeStr); } } void B2saomiaotuxiangchuangkou::OnBnClickedButtonSelectFolder() { CFolderPickerDialog dlg; if (dlg.DoModal() == IDOK) { m_folderPath = dlg.GetFolderPath(); m_editFolderPath.SetWindowText(m_folderPath); LoadFilesIntoListControl(); OnCbnSelchangeComboSaveOption(); m_btnStart.EnableWindow(!m_imageFiles.empty()); if (!m_imageFiles.empty()) { m_listImages.SetItemState(0, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED); m_listImages.EnsureVisible(0, FALSE); m_listImages.UpdateWindow(); PostMessage(WM_LOAD_FIRST_IMAGE, 0, 0); } } } LRESULT B2saomiaotuxiangchuangkou::OnLoadFirstImageMessage(WPARAM wParam, LPARAM lParam) { DisplayFirstImage(); return 0; } void B2saomiaotuxiangchuangkou::DisplayFirstImage() { if (m_imageFiles.empty()) return; CString filePath = m_imageFiles[0]; if (!LoadImageToControl(filePath, IDC_STATIC_ORIGINAL_IMAGE)) { return; } m_firstImageLoaded = true; m_firstLoadCompleted = true; m_imageLoaded = true; CWnd* pProcessed = GetDlgItem(IDC_STATIC_PROCESSED_IMAGE); if (pProcessed) { auto pStatic = reinterpret_cast<CStatic*>(pProcessed); HBITMAP hOldBmp = pStatic->GetBitmap(); if (hOldBmp) { DeleteObject(hOldBmp); pStatic->SetBitmap(NULL); } } } bool B2saomiaotuxiangchuangkou::LoadImageToControl(const CString& filePath, UINT controlID) { std::lock_guard<std::mutex> lock(m_imageMutex); DWORD fileAttr = GetFileAttributes(filePath); if (fileAttr == INVALID_FILE_ATTRIBUTES) { return false; } HBITMAP hBitmap = NULL; if (m_loadMode == MODE_CIMAGE) { hBitmap = LoadImageWithCImage(filePath); if (!hBitmap) { // CImage加载失败时,切换到OpenCV并重试 m_loadMode = MODE_OPENCV; hBitmap = LoadImageWithOpenCV(filePath); if (!hBitmap) { // OpenCV加载失败时,切换到GDI+ m_loadMode = MODE_GDIPlus; hBitmap = LoadImageWithGDIPlus(filePath); } } } else if (m_loadMode == MODE_OPENCV) { hBitmap = LoadImageWithOpenCV(filePath); if (!hBitmap) { m_loadMode = MODE_GDIPlus; hBitmap = LoadImageWithGDIPlus(filePath); if (!hBitmap) { m_loadMode = MODE_CIMAGE; hBitmap = LoadImageWithCImage(filePath); } } } else { hBitmap = LoadImageWithGDIPlus(filePath); if (!hBitmap) { m_loadMode = MODE_OPENCV; hBitmap = LoadImageWithOpenCV(filePath); if (!hBitmap) { m_loadMode = MODE_CIMAGE; hBitmap = LoadImageWithCImage(filePath); } } } if (!hBitmap) { return false; } CWnd* pWnd = GetDlgItem(controlID); if (pWnd) { CStatic* pStatic = dynamic_cast<CStatic*>(pWnd); if (pStatic) { HBITMAP oldBmp = pStatic->GetBitmap(); if (oldBmp) DeleteObject(oldBmp); pStatic->SetBitmap(hBitmap); pStatic->Invalidate(); return true; } } DeleteObject(hBitmap); return false; } // 使用CImage加载图像并保持比例 HBITMAP B2saomiaotuxiangchuangkou::LoadImageWithCImage(const CString& filePath) { CImage image; if (image.Load(filePath) != S_OK) { return NULL; } CRect rect; m_picOriginal.GetClientRect(&rect); int ctrlWidth = rect.Width(); int ctrlHeight = rect.Height(); int srcWidth = image.GetWidth(); int srcHeight = image.GetHeight(); // 计算等比例缩放尺寸,确保不超出控件范围 double ratioX = static_cast<double>(ctrlWidth) / srcWidth; double ratioY = static_cast<double>(ctrlHeight) / srcHeight; double ratio = std::min(ratioX, ratioY); // 取较小比例保持原始比例 int drawWidth = static_cast<int>(srcWidth * ratio); int drawHeight = static_cast<int>(srcHeight * ratio); int x = (ctrlWidth - drawWidth) / 2; int y = (ctrlHeight - drawHeight) / 2; // 创建兼容位图 HDC hdcScreen = ::GetDC(NULL); HBITMAP hBitmap = CreateCompatibleBitmap(hdcScreen, ctrlWidth, ctrlHeight); HDC hdcMem = CreateCompatibleDC(hdcScreen); HBITMAP hOldBmp = (HBITMAP)SelectObject(hdcMem, hBitmap); // 填充背景为白色 HBRUSH hBrush = CreateSolidBrush(RGB(255, 255, 255)); RECT rc = { 0, 0, ctrlWidth, ctrlHeight }; FillRect(hdcMem, &rc, hBrush); DeleteObject(hBrush); // 使用GDI+高质量插值缩放图像 HDC hdcImage = image.GetDC(); // 设置高质量拉伸模式 SetStretchBltMode(hdcMem, HALFTONE); // 执行高质量缩放 StretchBlt( hdcMem, x, y, drawWidth, drawHeight, hdcImage, 0, 0, srcWidth, srcHeight, SRCCOPY ); // 释放CImage的设备上下文 image.ReleaseDC(); // 恢复设备上下文并释放资源 SelectObject(hdcMem, hOldBmp); DeleteDC(hdcMem); ::ReleaseDC(NULL, hdcScreen); return hBitmap; } HBITMAP B2saomiaotuxiangchuangkou::LoadImageWithOpenCV(const CString& filePath) { cv::Mat img; #ifdef _UNICODE int len = WideCharToMultiByte(CP_UTF8, 0, filePath, -1, NULL, 0, NULL, NULL); std::vector<char> utf8Buf(len); WideCharToMultiByte(CP_UTF8, 0, filePath, -1, utf8Buf.data(), len, NULL, NULL); img = cv::imread(utf8Buf.data(), cv::IMREAD_COLOR); #else img = cv::imread(CW2A(filePath), cv::IMREAD_COLOR); #endif if (img.empty()) { return NULL; } cv::cvtColor(img, img, cv::COLOR_BGR2RGB); CRect rect; m_picOriginal.GetClientRect(&rect); int dstWidth = rect.Width(); int dstHeight = rect.Height(); double ratio = std::min(static_cast<double>(dstWidth) / img.cols, static_cast<double>(dstHeight) / img.rows); int drawWidth = static_cast<int>(img.cols * ratio); int drawHeight = static_cast<int>(img.rows * ratio); int x = (dstWidth - drawWidth) / 2; int y = (dstHeight - drawHeight) / 2; HDC hdcScreen = ::GetDC(NULL); HBITMAP hBitmap = CreateCompatibleBitmap(hdcScreen, dstWidth, dstHeight); HDC hdcMem = CreateCompatibleDC(hdcScreen); HBITMAP hOldBmp = (HBITMAP)SelectObject(hdcMem, hBitmap); HBRUSH hBrush = CreateSolidBrush(RGB(255, 255, 255)); RECT rc = { 0, 0, dstWidth, dstHeight }; FillRect(hdcMem, &rc, hBrush); DeleteObject(hBrush); cv::Mat resized; // 根据缩放比例选择插值算法(放大用双三次,缩小用区域插值) int interpolation = (ratio >= 1.0) ? cv::INTER_CUBIC : cv::INTER_AREA; cv::resize(img, resized, cv::Size(drawWidth, drawHeight), 0, 0, interpolation); BITMAPINFOHEADER bmiHeader = { 0 }; bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmiHeader.biWidth = resized.cols; bmiHeader.biHeight = -resized.rows; bmiHeader.biPlanes = 1; bmiHeader.biBitCount = 24; bmiHeader.biCompression = BI_RGB; SetStretchBltMode(hdcMem, HALFTONE); StretchDIBits( hdcMem, x, y, drawWidth, drawHeight, 0, 0, resized.cols, resized.rows, resized.data, (BITMAPINFO*)&bmiHeader, DIB_RGB_COLORS, SRCCOPY ); SelectObject(hdcMem, hOldBmp); DeleteDC(hdcMem); ::ReleaseDC(NULL, hdcScreen); return hBitmap; } HBITMAP B2saomiaotuxiangchuangkou::LoadImageWithGDIPlus(const CString& filePath) { Gdiplus::Image image(filePath); if (image.GetLastStatus() != Gdiplus::Ok) { return NULL; } CRect rect; m_picOriginal.GetClientRect(&rect); int ctrlWidth = rect.Width(); int ctrlHeight = rect.Height(); int srcWidth = image.GetWidth(); int srcHeight = image.GetHeight(); double scale = std::min(static_cast<double>(ctrlWidth) / srcWidth, static_cast<double>(ctrlHeight) / srcHeight); int drawWidth = static_cast<int>(srcWidth * scale); int drawHeight = static_cast<int>(srcHeight * scale); int x = (ctrlWidth - drawWidth) / 2; int y = (ctrlHeight - drawHeight) / 2; Gdiplus::Bitmap bitmap(ctrlWidth, ctrlHeight, PixelFormat32bppARGB); Gdiplus::Graphics graphics(&bitmap); // 设置最高质量渲染参数 graphics.SetSmoothingMode(Gdiplus::SmoothingModeHighQuality); graphics.SetPixelOffsetMode(Gdiplus::PixelOffsetModeHighQuality); graphics.SetInterpolationMode(Gdiplus::InterpolationModeHighQualityBicubic); graphics.Clear(Gdiplus::Color(255, 255, 255)); graphics.DrawImage(&image, x, y, drawWidth, drawHeight); HBITMAP hBitmap = NULL; bitmap.GetHBITMAP(Gdiplus::Color::White, &hBitmap); return hBitmap; } // 新增函数:将OpenCV Mat转换为HBITMAP并适配控件 HBITMAP B2saomiaotuxiangchuangkou::MatToBitmap(cv::Mat& mat, UINT controlID) { if (mat.empty()) return NULL; // 确保是3通道RGB图像 if (mat.channels() == 1) { cv::cvtColor(mat, mat, cv::COLOR_GRAY2BGR); } else if (mat.channels() == 4) { cv::cvtColor(mat, mat, cv::COLOR_BGRA2BGR); } CRect rect; CWnd* pWnd = GetDlgItem(controlID); if (!pWnd) return NULL; pWnd->GetClientRect(&rect); int dstWidth = rect.Width(); int dstHeight = rect.Height(); double ratio = std::min(static_cast<double>(dstWidth) / mat.cols, static_cast<double>(dstHeight) / mat.rows); int drawWidth = static_cast<int>(mat.cols * ratio); int drawHeight = static_cast<int>(mat.rows * ratio); int x = (dstWidth - drawWidth) / 2; int y = (dstHeight - drawHeight) / 2; cv::Mat resized; // 根据缩放比例选择插值算法 int interpolation = (ratio >= 1.0) ? cv::INTER_CUBIC : cv::INTER_AREA; cv::resize(mat, resized, cv::Size(drawWidth, drawHeight), ratio, ratio, interpolation); HDC hdcScreen = ::GetDC(NULL); HBITMAP hBitmap = CreateCompatibleBitmap(hdcScreen, dstWidth, dstHeight); HDC hdcMem = CreateCompatibleDC(hdcScreen); HBITMAP hOldBmp = (HBITMAP)SelectObject(hdcMem, hBitmap); HBRUSH hBrush = CreateSolidBrush(RGB(255, 255, 255)); RECT rc = { 0, 0, dstWidth, dstHeight }; FillRect(hdcMem, &rc, hBrush); DeleteObject(hBrush); BITMAPINFOHEADER bmiHeader = { 0 }; bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmiHeader.biWidth = resized.cols; bmiHeader.biHeight = -resized.rows; bmiHeader.biPlanes = 1; bmiHeader.biBitCount = 24; bmiHeader.biCompression = BI_RGB; SetStretchBltMode(hdcMem, HALFTONE); StretchDIBits( hdcMem, x, y, drawWidth, drawHeight, 0, 0, resized.cols, resized.rows, resized.data, (BITMAPINFO*)&bmiHeader, DIB_RGB_COLORS, SRCCOPY ); SelectObject(hdcMem, hOldBmp); DeleteDC(hdcMem); ::ReleaseDC(NULL, hdcScreen); return hBitmap; } BOOL B2saomiaotuxiangchuangkou::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) { return TRUE; } BOOL B2saomiaotuxiangchuangkou::OnEraseBkgnd(CDC* pDC) { CRect rect; GetClientRect(&rect); CBrush brush(RGB(255, 255, 255)); pDC->FillRect(&rect, &brush); return TRUE; } void B2saomiaotuxiangchuangkou::OnCbnSelchangeComboSaveOption() { int option = m_saveOption.GetCurSel(); if (option == 0) { m_savePath = m_folderPath; m_editSavePath.SetWindowText(m_savePath); } else if (option == 1) { if (m_savePath.IsEmpty() || m_savePath == m_folderPath) { CFolderPickerDialog dlg; if (dlg.DoModal() == IDOK) { m_savePath = dlg.GetFolderPath(); m_editSavePath.SetWindowText(m_savePath); } else { m_saveOption.SetCurSel(0); m_savePath = m_folderPath; m_editSavePath.SetWindowText(m_savePath); } } } } void B2saomiaotuxiangchuangkou::OnBnClickedButtonStart() { if (m_folderPath.IsEmpty()) { AfxMessageBox(_T("请先选择文件夹!")); return; } if (m_imageFiles.empty()) { AfxMessageBox(_T("文件夹中没有图像文件!")); return; } if (m_saveOption.GetCurSel() == 1 && m_savePath.IsEmpty()) { AfxMessageBox(_T("请先选择保存路径!")); return; } if (m_saveOption.GetCurSel() == 0) { CreateBackup(); } m_processing = true; m_paused = false; m_stopped = false; m_currentIndex = 0; m_btnStart.EnableWindow(FALSE); m_btnPause.EnableWindow(TRUE); m_btnStop.EnableWindow(TRUE); m_btnReset.EnableWindow(FALSE); m_totalProgress.SetPos(0); m_fileProgress.SetPos(0); if (m_processingThread.joinable()) { m_processingThread.join(); } m_processingThread = std::thread(&B2saomiaotuxiangchuangkou::ProcessImages, this); SetTimer(1, 100, NULL); } void B2saomiaotuxiangchuangkou::OnBnClickedButtonPause() { m_paused = !m_paused; m_btnPause.SetWindowText(m_paused ? _T("继续") : _T("暂停")); } void B2saomiaotuxiangchuangkou::OnBnClickedButtonStop() { m_stopped = true; m_processing = false; m_btnStart.EnableWindow(TRUE); m_btnPause.EnableWindow(FALSE); m_btnStop.EnableWindow(FALSE); m_btnReset.EnableWindow(TRUE); if (m_processingThread.joinable()) { m_processingThread.join(); } KillTimer(1); } void B2saomiaotuxiangchuangkou::OnBnClickedButtonReset() { OnBnClickedButtonStop(); if (m_saveOption.GetCurSel() == 0 && !m_backupPath.IsEmpty()) { RestoreBackup(); } m_currentIndex = 0; m_totalProgress.SetPos(0); m_fileProgress.SetPos(0); m_backupPath.Empty(); m_btnReset.EnableWindow(FALSE); if (!m_imageFiles.empty()) { m_listImages.SetItemState(0, LVIS_SELECTED, LVIS_SELECTED); PostMessage(WM_LOAD_FIRST_IMAGE, 0, 0); } } void B2saomiaotuxiangchuangkou::OnTimer(UINT_PTR nIDEvent) { if (nIDEvent == 1) { UpdateProgressBars(); } CDialogEx::OnTimer(nIDEvent); } void B2saomiaotuxiangchuangkou::OnLvnItemchangedListImages(NMHDR* pNMHDR, LRESULT* pResult) { LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR); int nItem = -1; if (pNMLV) { if ((pNMLV->uChanged & LVIF_STATE) && (pNMLV->uNewState & LVIS_SELECTED)) { nItem = pNMLV->iItem; } } else { nItem = 0; } if (!m_firstLoadCompleted && nItem == 0) { if (pResult) *pResult = 0; return; } // 当用户手动选择时,更新原图并清除处理后的图像 if (nItem >= 0 && nItem < (int)m_imageFiles.size() && !m_processing) { CString filePath = m_imageFiles[nItem]; LoadImageToControl(filePath, IDC_STATIC_ORIGINAL_IMAGE); // 清除处理后的图像 CWnd* pProcessed = GetDlgItem(IDC_STATIC_PROCESSED_IMAGE); if (pProcessed) { auto pStatic = reinterpret_cast<CStatic*>(pProcessed); HBITMAP hOldBmp = pStatic->SetBitmap(NULL); if (hOldBmp) DeleteObject(hOldBmp); } } if (pResult) { *pResult = 0; } } void B2saomiaotuxiangchuangkou::ProcessImages() { for (m_currentIndex = 0; m_currentIndex < (int)m_imageFiles.size(); ++m_currentIndex) { if (m_stopped) break; while (m_paused && !m_stopped) { std::this_thread::sleep_for(std::chrono::milliseconds(100)); } if (m_stopped) break; ProcessImage(m_imageFiles[m_currentIndex]); { std::lock_guard<std::mutex> lock(m_mutex); int totalProgress = static_cast<int>((static_cast<double>(m_currentIndex + 1) / m_imageFiles.size()) * 100); m_totalProgress.SetPos(totalProgress); m_fileProgress.SetPos(100); } std::this_thread::sleep_for(std::chrono::milliseconds(100)); } m_processing = false; m_stopped = true; PostMessage(WM_COMMAND, MAKEWPARAM(IDC_BUTTON_STOP, BN_CLICKED), (LPARAM)m_btnStop.m_hWnd); AfxMessageBox(_T("处理完成!")); } void B2saomiaotuxiangchuangkou::ProcessImage(const CString& filePath) { CT2CA filePathConverted(filePath); std::string filePathStr(filePathConverted); cv::Mat image = cv::imread(filePathStr); if (image.empty()) return; // 更新显示原图 UpdateDisplayImage(filePath); cv::Mat processed; // ====== 调用OCR方向校正函数 ====== // 创建临时副本用于OCR处理 cv::Mat imageCopy = image.clone(); PerformOCRAndRotation(filePath, imageCopy, processed); // ====== END OCR调用 ====== // 直接显示处理后的图像,不使用临时文件 HBITMAP hProcessedBmp = MatToBitmap(processed, IDC_STATIC_PROCESSED_IMAGE); if (hProcessedBmp) { CWnd* pProcessed = GetDlgItem(IDC_STATIC_PROCESSED_IMAGE); if (pProcessed) { auto pStatic = reinterpret_cast<CStatic*>(pProcessed); HBITMAP hOldBmp = pStatic->SetBitmap(NULL); if (hOldBmp) DeleteObject(hOldBmp); pStatic->SetBitmap(hProcessedBmp); pStatic->Invalidate(); } } // 保存处理后的图像 if (m_saveOption.GetCurSel() == 0) { SaveImage(processed, filePath); } else { CString fileName = GetFileNameFromPath(filePath); CString newPath = m_savePath + _T("\\") + fileName; SaveImage(processed, newPath); } // 更新文件处理进度 for (int progress = 0; progress <= 100; progress += 10) { if (m_stopped) return; while (m_paused && !m_stopped) { std::this_thread::sleep_for(std::chrono::milliseconds(100)); } if (m_stopped) return; { std::lock_guard<std::mutex> lock(m_mutex); m_fileProgress.SetPos(progress); } std::this_thread::sleep_for(std::chrono::milliseconds(50)); } } void B2saomiaotuxiangchuangkou::UpdateDisplayImage(const CString& filePath) { PostMessage(WM_UPDATE_DISPLAY_IMAGE, (WPARAM)(LPCTSTR)filePath, 0); } LRESULT B2saomiaotuxiangchuangkou::OnUpdateDisplayImage(WPARAM wParam, LPARAM lParam) { CString filePath = (LPCTSTR)wParam; if (filePath.IsEmpty()) return 0; // 只在处理过程中更新原图显示 if (m_processing && !m_paused && !m_stopped) { LoadImageToControl(filePath, IDC_STATIC_ORIGINAL_IMAGE); } return 0; } Mat B2saomiaotuxiangchuangkou::rotateImage(const Mat& src, double angle) { if (src.empty()) return Mat(); Point2f center(static_cast<float>(src.cols / 2.0), static_cast<float>(src.rows / 2.0)); Mat rotMat = getRotationMatrix2D(center, angle, 1.0); Rect2f bbox = RotatedRect(center, Size2f(src.size()), angle).boundingRect2f(); rotMat.at<double>(0, 2) += bbox.width / 2.0 - center.x; rotMat.at<double>(1, 2) += bbox.height / 2.0 - center.y; Mat dst; warpAffine(src, dst, rotMat, Size(static_cast<int>(bbox.width), static_cast<int>(bbox.height)), INTER_LINEAR, BORDER_CONSTANT, Scalar(0, 0, 0)); return dst; } // 调整图像大小以适应屏幕 Mat B2saomiaotuxiangchuangkou::resizeToFitScreen(const Mat& img) { if (img.empty()) return Mat(); // 获取屏幕分辨率 int screenWidth = GetSystemMetrics(SM_CXSCREEN); int screenHeight = GetSystemMetrics(SM_CYSCREEN); // 设置最大显示尺寸(留出边缘空间) int maxDisplayWidth = static_cast<int>(screenWidth * 0.8); int maxDisplayHeight = static_cast<int>(screenHeight * 0.8); // 计算缩放比例 double scale = min(static_cast<double>(maxDisplayWidth) / img.cols, static_cast<double>(maxDisplayHeight) / img.rows); // 如果图像已经小于最大尺寸,则不缩放 if (scale >= 1.0) return img.clone(); // 计算新尺寸 int newWidth = static_cast<int>(img.cols * scale); int newHeight = static_cast<int>(img.rows * scale); // 缩放图像 Mat resized; resize(img, resized, Size(newWidth, newHeight), 0, 0, INTER_AREA); return resized; } void B2saomiaotuxiangchuangkou::PerformOCRAndRotation(const CString& imagePath, cv::Mat& inputImage, cv::Mat& outputImage) { // 检查OCR引擎是否初始化 if (!m_tessInitialized) { outputImage = inputImage.clone(); // 返回原始图像 return; } try { // 使用传入的图像 cv::Mat image = inputImage; // 设置图像为灰度图 (Tesseract需要) cv::Mat gray; cv::cvtColor(image, gray, cv::COLOR_BGR2GRAY); // 设置Tesseract图像 m_tess.SetImage(gray.data, gray.cols, gray.rows, 1, gray.step); // 检测方向和脚本 int orient_deg; float orient_conf; const char* script_name; float script_conf; m_tess.DetectOrientationScript(&orient_deg, &orient_conf, &script_name, &script_conf); // 根据检测到的方向角度旋转图像(逆时针旋转) if (orient_deg != 0) { outputImage = rotateImage(image, orient_deg); } else { outputImage = image.clone(); } } catch (...) { // 处理任何异常,返回原始图像 outputImage = inputImage.clone(); } // 重置Tesseract图像 m_tess.Clear(); } void B2saomiaotuxiangchuangkou::SaveImage(cv::Mat& img, const CString& filePath) { if (img.empty()) return; CT2CA filePathConverted(filePath); std::string filePathStr(filePathConverted); std::vector<int> compression_params; CString ext = filePath.Right(4).MakeLower(); if (ext == _T(".jpg") || ext == _T(".jpeg")) { compression_params.push_back(cv::IMWRITE_JPEG_QUALITY); compression_params.push_back(95); } else if (ext == _T(".png")) { compression_params.push_back(cv::IMWRITE_PNG_COMPRESSION); compression_params.push_back(9); } cv::imwrite(filePathStr, img, compression_params); } void B2saomiaotuxiangchuangkou::UpdateProgressBars() { if (m_imageFiles.empty()) return; int totalProgress = static_cast<int>( (static_cast<double>(m_currentIndex) / m_imageFiles.size()) * 100); // 平滑过渡 int currentTotal = m_totalProgress.GetPos(); if (abs(totalProgress - currentTotal) > 5) { m_totalProgress.SetPos(totalProgress); } else if (totalProgress > currentTotal) { m_totalProgress.SetPos(currentTotal + 1); } } void B2saomiaotuxiangchuangkou::CreateBackup() { if (m_folderPath.IsEmpty()) return; CTime time = CTime::GetCurrentTime(); CString timeStr = time.Format(_T("%Y%m%d%H%M%S")); m_backupPath = m_folderPath + _T("\\backup_") + timeStr; if (!CreateDirectory(m_backupPath, NULL)) { return; } for (const auto& file : m_imageFiles) { CString fileName = GetFileNameFromPath(file); CString destPath = m_backupPath + _T("\\") + fileName; CopyFile(file, destPath, FALSE); } } void B2saomiaotuxiangchuangkou::RestoreBackup() { if (m_backupPath.IsEmpty()) return; for (const auto& file : m_imageFiles) { CString fileName = GetFileNameFromPath(file); CString sourcePath = m_backupPath + _T("\\") + fileName; CopyFile(sourcePath, file, FALSE); } RemoveDirectory(m_backupPath); m_backupPath.Empty(); } void B2saomiaotuxiangchuangkou::Cleanup() { m_stopped = true; m_processing = false; if (m_processingThread.joinable()) { m_processingThread.join(); } KillTimer(1); std::lock_guard<std::mutex> lock(m_bitmapMutex); if (m_currentBitmap) { DeleteObject(m_currentBitmap); m_currentBitmap = NULL; } // 释放控件中的位图 HBITMAP hBmp = m_picOriginal.GetBitmap(); if (hBmp) DeleteObject(hBmp); hBmp = m_picProcessed.GetBitmap(); if (hBmp) DeleteObject(hBmp); } CString B2saomiaotuxiangchuangkou::GetFileNameFromPath(const CString& filePath) { int pos = filePath.ReverseFind('\\'); if (pos == -1) pos = filePath.ReverseFind('/'); if (pos != -1) { return filePath.Mid(pos + 1); } return filePath; }中 ,在void B2saomiaotuxiangchuangkou::PerformOCRAndRotation(const CString& imagePath, cv::Mat& inputImage, cv::Mat& outputImage) { // 检查OCR引擎是否初始化 if (!m_tessInitialized) { outputImage = inputImage.clone(); // 返回原始图像 return; } try { // 使用传入的图像 cv::Mat image = inputImage; // 设置图像为灰度图 (Tesseract需要) cv::Mat gray; cv::cvtColor(image, gray, cv::COLOR_BGR2GRAY); // 设置Tesseract图像 m_tess.SetImage(gray.data, gray.cols, gray.rows, 1, gray.step); // 检测方向和脚本 int orient_deg; float orient_conf; const char* script_name; float script_conf; m_tess.DetectOrientationScript(&orient_deg, &orient_conf, &script_name, &script_conf); // 根据检测到的方向角度旋转图像(逆时针旋转) if (orient_deg != 0) { outputImage = rotateImage(image, orient_deg); } else { outputImage = image.clone(); } } catch (...) { // 处理任何异常,返回原始图像 outputImage = inputImage.clone(); } // 重置Tesseract图像 m_tess.Clear(); }函数体中输出的outputImage添加一个判断函数,继续对该输出继续处理,判断函数根据#include <opencv2/opencv.hpp> #include <vector> #include <iostream> #include <numeric> #include <cmath> #include <future> #include <algorithm> using namespace cv; using namespace std; // 计算水平投影的方差 double calculateProjectionVariance(const Mat& binary) { vector<int> projection(binary.rows, 0); // 使用指针遍历加速 for (int y = 0; y < binary.rows; y++) { const uchar* row = binary.ptr<uchar>(y); for (int x = 0; x < binary.cols; x++) { projection[y] += row[x] / 255; // 归一化到0-1 } } // 使用STL算法计算均值和方差 double sum = accumulate(projection.begin(), projection.end(), 0.0); double mean = sum / projection.size(); double variance = 0.0; for_each(projection.begin(), projection.end(), [&](int val) { variance += pow(val - mean, 2); }); variance /= projection.size(); return variance; } // 检测文本倾斜角度 - 优化版本 double detectSkewAngle(const Mat& image) { // 转为灰度图并二值化 Mat gray, binary; cvtColor(image, gray, COLOR_BGR2GRAY); threshold(gray, binary, 0, 255, THRESH_BINARY_INV | THRESH_OTSU); // 初始角度搜索范围和步长 double angleStart = -15.0; double angleEnd = 15.0; double angleStep = 2.0; // 粗粒度搜索 double bestAngle = 0.0; // 两次迭代搜索:先粗后精 for (int iter = 0; iter < 2; iter++) { vector<double> angles; for (double angle = angleStart; angle <= angleEnd; angle += angleStep) { angles.push_back(angle); } double maxVariance = 0.0; double currentBestAngle = 0.0; // 多线程并行计算不同角度的投影方差 vector<future<pair<double, double>>> futures; for (double angle : angles) { futures.push_back(async(launch::async, [binary, angle]() { // 获取图像尺寸 int height = binary.rows; int width = binary.cols; // 计算旋转矩阵 Point2f center(width / 2.0, height / 2.0); Mat rot = getRotationMatrix2D(center, angle, 1.0); // 计算旋转后的图像尺寸 Rect bbox = RotatedRect(center, Size2f(width, height), angle).boundingRect(); // 调整旋转矩阵的平移部分 rot.at<double>(0, 2) += bbox.width / 2.0 - center.x; rot.at<double>(1, 2) += bbox.height / 2.0 - center.y; // 旋转图像 (使用更快的插值方法) Mat rotated; warpAffine(binary, rotated, rot, bbox.size(), INTER_LINEAR, BORDER_REPLICATE); // 计算投影方差 double variance = calculateProjectionVariance(rotated); return make_pair(variance, angle); })); } // 收集结果 for (auto& future : futures) { auto result = future.get(); if (result.first > maxVariance) { maxVariance = result.first; currentBestAngle = result.second; } } // 更新下一次迭代的搜索范围 bestAngle = currentBestAngle; angleStart = bestAngle - angleStep; angleEnd = bestAngle + angleStep; angleStep /= 4.0; // 精搜索步长变为原来的1/4 } return bestAngle; } // 校正倾斜图像 - 优化版本 Mat correctSkew(const Mat& image, double angle) { // 获取图像尺寸 int height = image.rows; int width = image.cols; // 计算旋转矩阵 Point2f center(width / 2.0, height / 2.0); Mat rot = getRotationMatrix2D(center, angle, 1.0); // 计算旋转后的图像尺寸 Rect bbox = RotatedRect(center, Size2f(width, height), angle).boundingRect(); // 调整旋转矩阵的平移部分 rot.at<double>(0, 2) += bbox.width / 2.0 - center.x; rot.at<double>(1, 2) += bbox.height / 2.0 - center.y; // 使用更快的插值方法 Mat corrected; warpAffine(image, corrected, rot, bbox.size(), INTER_LINEAR, BORDER_REPLICATE); return corrected; } int main() { // 读取图像 Mat image = imread("E:\\123\\14.jpg"); if (image.empty()) { cerr << "无法读取图像!" << endl; return -1; } // 检测倾斜角度 double skewAngle = detectSkewAngle(image); cout << "检测到倾斜角度: " << skewAngle << "°" << endl; // 校正倾斜 Mat correctedImage = correctSkew(image, skewAngle); // 显示结果 namedWindow("原始图像", WINDOW_NORMAL); namedWindow("校正后图像", WINDOW_NORMAL); imshow("原始图像", image); imshow("校正后图像", correctedImage); // 保存结果 imwrite("corrected_text.jpg", correctedImage); cout << "校正后的图像已保存为 corrected_text.jpg" << endl; waitKey(0); return 0; }和#include <opencv2/opencv.hpp> #include <iostream> #include <vector> #include <cmath> #include <algorithm> #include <limits> using namespace cv; using namespace std; // 计算两条直线的夹角差(0-90度) double calculateAngleDiff(double angle1, double angle2) { double diff = fabs(angle1 - angle2); if (diff > 90) diff = 180 - diff; return diff; } // 计算直线角度(0-180度) double getLineAngle(const Vec4i& line) { Point pt1(line[0], line[1]); Point pt2(line[2], line[3]); double dx = pt2.x - pt1.x; double dy = pt2.y - pt1.y; double angle = atan2(dy, dx) * 180 / CV_PI; if (angle < 0) angle += 180; return angle; } // 调整图像大小以适应屏幕显示 Mat resizeToFitScreen(const Mat& image, int maxWidth = 1200, int maxHeight = 800) { double scale = 1.0; if (image.cols > maxWidth || image.rows > maxHeight) { double scaleX = static_cast<double>(maxWidth) / image.cols; double scaleY = static_cast<double>(maxHeight) / image.rows; scale = min(scaleX, scaleY); } if (scale < 1.0) { Mat resized; resize(image, resized, Size(), scale, scale); return resized; } return image.clone(); } // 检测四边形轮廓 vector<vector<Point>> detectQuadrilaterals(Mat& edges) { vector<vector<Point>> contours; vector<Vec4i> hierarchy; findContours(edges, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE); vector<vector<Point>> quads; for (size_t i = 0; i < contours.size(); i++) { // 忽略小轮廓 if (contourArea(contours[i]) < 1000) continue; vector<Point> approx; // 多边形逼近 double epsilon = 0.02 * arcLength(contours[i], true); approxPolyDP(contours[i], approx, epsilon, true); // 如果是四边形 if (approx.size() == 4) { // 检查是否是凸四边形 if (isContourConvex(approx)) { quads.push_back(approx); } } } return quads; } // 计算四边形的最小外接矩形角度 double getQuadrilateralAngle(const vector<Point>& quad) { RotatedRect rect = minAreaRect(quad); return rect.angle; } // 检查两个四边形是否嵌套(一个在另一个内部) bool isNestedQuad(const vector<Point>& outer, const vector<Point>& inner) { for (const Point& pt : inner) { if (pointPolygonTest(outer, pt, false) < 0) { return false; } } return true; } int main() { // 硬编码图片路径 - 修改为您需要的实际路径 string imagePath = "C:/path/to/your/image.jpg"; // Windows路径 // string imagePath = "/home/user/images/test.jpg"; // Linux路径 // 1. 读取图片 Mat src = imread(imagePath); if (src.empty()) { cerr << "Error: Could not open or find the image at: " << imagePath << endl; cerr << "Please check the path and try again." << endl; return -1; } // 2. 转换为灰度图并进行边缘检测 Mat gray, edges; cvtColor(src, gray, COLOR_BGR2GRAY); GaussianBlur(gray, gray, Size(5, 5), 0); Canny(gray, edges, 50, 150); // 3. 霍夫变换检测直线 vector<Vec4i> lines; HoughLinesP(edges, lines, 1, CV_PI / 180, 50, 50, 10); // 4. 过滤短直线 double diag = sqrt(src.rows * src.rows + src.cols * src.cols); double minLength = diag / 20; vector<Vec4i> validLines; vector<double> angles; for (const auto& line : lines) { Point pt1(line[0], line[1]); Point pt2(line[2], line[3]); double length = norm(pt1 - pt2); if (length > minLength) { validLines.push_back(line); angles.push_back(getLineAngle(line)); } } // 5. 检测四边形轮廓 vector<vector<Point>> quads = detectQuadrilaterals(edges); bool hasNestedQuads = false; double nestedQuadAngle = 0; // 寻找嵌套的四边形(外框和内框) for (size_t i = 0; i < quads.size(); i++) { for (size_t j = 0; j < quads.size(); j++) { if (i == j) continue; // 检查是否嵌套 if (isNestedQuad(quads[i], quads[j])) { hasNestedQuads = true; nestedQuadAngle = getQuadrilateralAngle(quads[j]); // 使用内框的角度 break; } } if (hasNestedQuads) break; } // 6. 处理检测结果 Mat dst = src.clone(); string resultText; double rotationAngle = 0; bool foundFrame = false; const double angleTolerance = 5.0; // 如果有嵌套四边形(粗边框) if (hasNestedQuads) { foundFrame = true; rotationAngle = nestedQuadAngle; resultText = "Nested frame detected. Rotation angle: " + to_string(rotationAngle) + " degrees"; } // 否则检测水平和垂直线 else if (validLines.size() >= 2) { // 分组存储水平和垂直方向的直线 vector<Vec4i> horizontalLines, verticalLines; for (size_t i = 0; i < validLines.size(); i++) { if (angles[i] < angleTolerance || angles[i] > 180 - angleTolerance || (angles[i] > 90 - angleTolerance && angles[i] < 90 + angleTolerance)) { if (fabs(angles[i] - 90) < angleTolerance) { verticalLines.push_back(validLines[i]); } else { horizontalLines.push_back(validLines[i]); } } } // 检查是否构成线框 if (horizontalLines.size() >= 2 && verticalLines.size() >= 2) { foundFrame = true; // 计算水平线平均角度 double avgAngle = 0; int count = 0; for (double angle : angles) { if (angle < angleTolerance || angle > 180 - angleTolerance) { avgAngle += (angle > 90) ? angle - 180 : angle; count++; } } if (count > 0) { avgAngle /= count; rotationAngle = avgAngle; } resultText = "Frame detected. Rotation angle: " + to_string(rotationAngle) + " degrees"; } else { // 检查是否存在平行/共线直线 bool foundParallel = false; for (size_t i = 0; i < angles.size(); i++) { for (size_t j = i + 1; j < angles.size(); j++) { double angleDiff = calculateAngleDiff(angles[i], angles[j]); if (angleDiff < angleTolerance) { foundParallel = true; break; } } if (foundParallel) break; } if (foundParallel) { resultText = "Parallel lines detected but no frame found"; } else { resultText = "No frame or parallel lines detected"; } } } else { resultText = "No sufficient lines detected"; } cout << resultText << endl; // 7. 如果有线框,进行校正 if (foundFrame) { // 旋转图像校正 Point2f center(src.cols / 2.0f, src.rows / 2.0f); Mat rotMat = getRotationMatrix2D(center, rotationAngle, 1.0); warpAffine(src, dst, rotMat, src.size(), INTER_LINEAR, BORDER_CONSTANT, Scalar(255, 255, 255)); } // 8. 保存结果 size_t dotPos = imagePath.find_last_of("."); string baseName = (dotPos == string::npos) ? imagePath : imagePath.substr(0, dotPos); string ext = (dotPos == string::npos) ? ".jpg" : imagePath.substr(dotPos); string origPath = baseName + "_original" + ext; string correctedPath = baseName + "_corrected" + ext; imwrite(origPath, src); if (foundFrame) { imwrite(correctedPath, dst); cout << "Saved original image: " << origPath << endl; cout << "Saved corrected image: " << correctedPath << endl; } else { cout << "Saved original image: " << origPath << endl; } // 9. 显示结果(调整大小以适应屏幕) Mat displaySrc = resizeToFitScreen(src); Mat displayDst = resizeToFitScreen(dst); // 计算字体大小比例 double fontScaleSrc = min(0.7, 600.0 / displaySrc.cols); double fontScaleDst = min(0.7, 600.0 / displayDst.cols); // 添加文本到显示图像 putText(displaySrc, resultText, Point(20, 40), FONT_HERSHEY_SIMPLEX, fontScaleSrc, Scalar(0, 0, 255), 2); if (foundFrame) { putText(displayDst, "Corrected Image", Point(20, 40), FONT_HERSHEY_SIMPLEX, fontScaleDst, Scalar(0, 0, 255), 2); } // 显示原始图像 namedWindow("Original Image", WINDOW_NORMAL); imshow("Original Image", displaySrc); // 显示校正图像(如果有) if (foundFrame) { namedWindow("Corrected Image", WINDOW_NORMAL); imshow("Corrected Image", displayDst); } waitKey(0); return 0; }这两个函数添加,判断条件符合哪一个函数就执行哪一个函数的功能(前提是将后两个函数的功能合理的嵌合到第一个代码中)
07-05
根据我提供的控件源码,写出一个更好的控件 #ifndef _CONSOLE_H_ #define _CONSOLE_H_ #define _CRT_SECURE_NO_WARNINGS #define NO_WARN_MBCS_MFC_DEPRECATION #include <SDKDDKVer.h> //#include <afxwin.h> #include <afxcmn.h> #include <concurrent_vector.h> #define CONSOLECOLOR_BLACK "\x1E\x1D" //字体 黑色 #define CONSOLECOLOR_RED "\x1E\x1F" //字体 红色 #define CONSOLECOLOR_GREEN "\x1E\x20" //字体 绿色 #define CONSOLECOLOR_YELLOW "\x1E\x21" //字体 黄色 #define CONSOLECOLOR_BLUE "\x1E\x22" //字体 蓝色 #define CONSOLECOLOR_PURPLE "\x1E\x23" //字体 紫色 #define CONSOLECOLOR_CYAN "\x1E\x24" //字体 青色 #define CONSOLECOLOR_DEF "\x1E\x25" //字体 默认色 class ScrollBar; struct LineInfo { DWORD m_dwStrLen;//行内容的长度 DWORD m_dwHead;//行首的sel游标 DWORD m_dwMaxSelWnd;//当前控件x轴尽头的sel DWORD m_dwTail;//行尾的sel int m_xPos;//行首的x开始坐标 int m_yPos;//行首的y开始坐标 DWORD m_dwMaxPixl;//此行内容占最大的像素 int* m_pDx; ~LineInfo() { if (m_pDx)delete[]m_pDx; } }; class Console: public CRichEditCtrl { public: Console(CWnd* _pParent); ~Console(); template<class ...Args> void Printf(const char* pformat, Args... args) { int len = std::snprintf(nullptr, 0, pformat, args...); if (len > 0) { char* szBuf = new char[len+1]; std::snprintf(szBuf, len+1, pformat, args...); split(szBuf); delete[]szBuf; } } private: void split(const char* _szText); void printf(const char* _szText); private: CDC* m_pDC; CRect m_rcWnd; BOOL m_bIsTrack; CFont m_Font;//默认字体,只是方便计算字体占屏幕长度使用的 int m_nFontSize;//默认字体大小(单位Twips) 如220Twip = 220/20 = 11磅 CHARFORMAT2 m_CF;//最终字体的数据 concurrency::concurrent_vector<LineInfo> m_vecLineInfo; ScrollBar* m_pHScroll; SCROLLINFO m_infoHScroll; DWORD m_pixCurMaxChars; ScrollBar* m_pVScroll; SCROLLINFO m_infoVScroll; int m_iLineHeight; int m_iStartPos_x; int m_iPrePos_x; bool m_bIsCapture; CHARRANGE m_StartSel; public: DECLARE_MESSAGE_MAP() afx_msg void OnEnSelchange(NMHDR* pNMHDR, LRESULT* pResult); afx_msg void OnEnMsgfilter(NMHDR* pNMHDR, LRESULT* pResult); afx_msg void OnMouseLeave(); afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); }; extern Console* pConsole; #define console(_format, ...)pConsole->Printf(_format, ##__VA_ARGS__); #endif#include "Console.h" #include <io.h> #include <thread> #include "ScrollBar/ScrollBar.h" Console* pConsole = NULL; Console::Console(CWnd* _pParent) : m_nFontSize(10 * 10), m_bIsTrack(FALSE), m_pHScroll(NULL), m_pVScroll(NULL), m_pixCurMaxChars(0), m_iPrePos_x(0), m_iStartPos_x(0), m_bIsCapture(FALSE) { if (_pParent) { const char* szFontName = "lucida consoles"; //Arial _pParent->GetWindowRect(&m_rcWnd); m_rcWnd = {10, 0, m_rcWnd.Width()-15, m_rcWnd.Height()-15};//682 //| WS_HSCROLL | WS_VSCROLL if (CreateEx(NULL, WS_CHILD | WS_VISIBLE | ES_LEFT | ES_WANTRETURN | ES_MULTILINE | ES_READONLY | ES_AUTOHSCROLL | ES_AUTOVSCROLL, m_rcWnd, _pParent, 0))// { m_pDC = GetDC(); SetBackgroundColor(false, RGB(30, 30, 30));//设置背景颜色 LimitText(32767);//系统默认设置是 32767 = 31.999kb 只能限制用户的输入 //创建新字体数据,此字体只是方便计算屏幕显示的长度用的。最终字体数据以 CHARFORMAT2 为准 //以十分之一磅为单位。例如,如果你想要一个12磅的字体,你应该传递120作为这个参数。 m_Font.CreatePointFont(m_nFontSize, szFontName);// 100/10 =10磅,相当于200Twip CreatePointFont用的单位是Point, 是磅的10倍,刚好是Twips的一半 SetFont(&m_Font);//设置字体 m_pDC->SelectObject(&m_Font);//dc选择当前字体 /* 1缇等于1/1440 英寸或1/567厘米 缇(Twips) (缇:计量单位,等于“磅”的 1/20,英寸的 1/1440。一厘米有 567 缇。 像素(Pixels):监视器或打印机分辨率的最小单位 右键单击桌面,选择属性,选择“设置”选卡,单击高级按钮。 里面出现DPI设置。一般为“正常尺寸(96 DPI)”。 DPI的意思就是 DPI(Dots per Inch)。因此我们可以得到如下换算公式 1 Pixel = 1440 TPI / 96 DPI = 15 Twips 1 Twip = 96 DPI / 1440 TPI = 0.0666667 Pixels 磅:指打印的字符的高度的度量单位, 1磅等于1/72英寸,或大约等于1厘米的 1/28。 英寸:2.54 厘米 一般情况下:1厘米=8505像素 20Twip = 1磅 = 20*0.0666667 = 1.333334 Pixels */ LRESULT FontStyle = 0; FontStyle = SendMessage(EM_GETLANGOPTIONS, 0, 0); if (FontStyle & IMF_DUALFONT) { FontStyle &= ~IMF_DUALFONT; //"<CRichEdit_Ctrl::CRichEdit_Ctrl>成功去掉IMF_DUALFONT"; } SendMessage(EM_SETLANGOPTIONS, 0, (LPARAM)FontStyle); /* PARAFORMAT2 pf; ZeroMemory(&pf, sizeof(PARAFORMAT2)); pf.cbSize = sizeof pf; pf.dwMask |= PFM_ALL; pf.bLineSpacingRule = 100; pf.dyLineSpacing = 400; pf.dySpaceAfter = 400; pf.dySpaceBefore = 400; pf.dxStartIndent = 100; pf.dxRightIndent = 100; SetParaFormat(pf); */ TEXTMETRIC tm; ::GetTextMetrics(m_pDC->GetSafeHdc(), &tm); m_iLineHeight = tm.tmHeight + (tm.tmDescent*2);//取得行高 //准确的字体数据 memset(&m_CF, 0, sizeof(m_CF)); //StrCpyA(m_CF.szFaceName, szFontName);//设置字体 //m_CF.cbSize = sizeof(CHARFORMAT2); m_CF.dwMask = CFM_EFFECTS | CFM_COLOR; m_CF.dwEffects = 0; m_CF.crTextColor = RGB(165, 165, 165);//设置颜色 //m_CF.yHeight = m_nFontSize;//除20得到磅 如 200/20 = 10磅 //默认的字符磅数 SetDefaultCharFormat(m_CF);//设置字体 SetEventMask(GetEventMask() | ENM_CHANGE | ENM_SELCHANGE | ENM_SCROLL | ENM_MOUSEEVENTS); //创建滚动动 m_pHScroll = new ScrollBar(); if (m_pHScroll->Create(SB_HORZ, CRect(m_rcWnd.left, m_rcWnd.Height(), m_rcWnd.right, m_rcWnd.Height()+15), _pParent)) { m_pHScroll->SetTarget(this); memset(&m_infoHScroll, 0, sizeof m_infoHScroll); m_infoHScroll.cbSize = sizeof m_infoHScroll; m_infoHScroll.fMask = SIF_ALL; m_infoHScroll.nPage = m_rcWnd.Width(); } m_pVScroll = new ScrollBar(); if (m_pVScroll->Create(SB_VERT, CRect(m_rcWnd.right, m_rcWnd.top, m_rcWnd.right+15, m_rcWnd.bottom), _pParent)) { m_pVScroll->SetTarget(this); memset(&m_infoVScroll, 0, sizeof m_infoVScroll); m_infoVScroll.cbSize = sizeof m_infoVScroll; m_infoVScroll.fMask = SIF_ALL; m_infoVScroll.nPage = m_rcWnd.Height(); } } } } Console::~Console() { m_Font.DeleteObject(); if (m_pHScroll)delete m_pHScroll; if (m_pVScroll)delete m_pVScroll; for (concurrency::concurrent_vector<LineInfo>::iterator iter = m_vecLineInfo.begin(); iter != m_vecLineInfo.end(); iter++) { if (iter->m_pDx) { delete[] iter->m_pDx; iter->m_pDx = NULL; } } } /* *0x1E RS (Record Separator) 记录分离符 属性代码 颜色 29 黑色 = 0x1D 31 红色 = 0x1F 32 绿色 = 0x20 33 黄色 = 0x21 34 蓝色 = 0x22 35 紫色 = 0x23 36 青色 = 0x24 */ void Console::printf(const char* _szText) { const char* szText = _szText; char byteColor = 0; //如果\n会替换成\r int indexLine = LineFromChar(-1);//取出当前行号 long lStart = 0; long lEnd = 0; GetSel(lStart, lEnd);//取得当前的光标位置 CString szStart; GetTextRange(lStart - 1, lEnd, szStart);//当前光标向后选择一位字符,并取出此字符 if (szStart == '\r' || szStart == "")//判断字符是否行头 { CPoint point = PosFromChar(lEnd); LineInfo info; memset(&info, 0, sizeof info); info.m_dwHead = lEnd; info.m_xPos = point.x; info.m_yPos = point.y; m_vecLineInfo.push_back(info);//保存行头的光标位置 } if (_szText[0] == '\x1E') { switch (_szText[1]) { case '\x1D': { m_CF.crTextColor = RGB(0, 0, 0); break; } case '\x1F': { m_CF.crTextColor = RGB(255, 0, 0); break; } case '\x20': { m_CF.crTextColor = RGB(0, 255, 0); break; } case '\x21': { m_CF.crTextColor = RGB(255, 255, 0); break; } case '\x22': { m_CF.crTextColor = RGB(0, 0, 255); break; } case '\x23': { m_CF.crTextColor = RGB(199, 0, 106); break; } case '\x24': { m_CF.crTextColor = RGB(0, 255, 255); break; } default: { m_CF.crTextColor = RGB(165, 165, 165); break; } } szText = _szText+2; SetSelectionCharFormat(m_CF); } ReplaceSel(szText); m_CF.crTextColor = RGB(165, 165, 165);//重置回原始颜色 SetSelectionCharFormat(m_CF); LineInfo* pInfo = &(m_vecLineInfo[indexLine]); //尝试取出控件尽头x轴末尾是否有字符存在 GetSel(lStart, lEnd);//取得当前的光标位置 GetTextRange(lEnd - 1, lEnd, szStart);//当前光标向后选择一位字符,并取出此字符 bool bIsEnter = false; if (szStart == '\r') { //已经完成换行操作 bIsEnter = true; pInfo->m_dwTail = lEnd - 1; GetTextRange(pInfo->m_dwHead, pInfo->m_dwTail, szStart);//取出本行内容 CPoint point = PosFromChar(pInfo->m_dwTail); pInfo->m_dwMaxPixl = point.x-1;//此行文本的最大像素 int len = szStart.GetLength(); int iFit = 0; CSize size = { 0, 0 }; if (pInfo->m_pDx) { delete [] pInfo->m_pDx; pInfo->m_pDx = NULL; } pInfo->m_pDx = new int[len]; pInfo->m_dwStrLen = len; ::GetTextExtentExPoint(m_pDC->GetSafeHdc(), szStart, len, point.x, &iFit, pInfo->m_pDx, &size);//计算出本行每个字符所占的像素,并把每个字符的像素存在m_pDx数组里面 pInfo->m_yPos = indexLine * m_iLineHeight; } else { pInfo->m_dwTail = lEnd; CPoint point = PosFromChar(pInfo->m_dwTail); pInfo->m_dwMaxPixl = point.x;//此行文本的最大像素 } //重置水平滚动条信息 if (pInfo->m_dwMaxPixl > (DWORD)m_rcWnd.Width() && pInfo->m_dwMaxPixl > m_pixCurMaxChars) { m_pixCurMaxChars = pInfo->m_dwMaxPixl; m_infoHScroll.nMax = m_pixCurMaxChars; m_pHScroll->SetScrollInfo(m_infoHScroll); } if (bIsEnter) { //已经完成换行操作 if (((indexLine + 1) * m_iLineHeight) > m_rcWnd.Height()) { m_infoVScroll.nMax = ((indexLine + 1) * m_iLineHeight); m_pVScroll->SetScrollInfo(m_infoVScroll); m_pVScroll->SetScrollPos(m_infoVScroll.nMax - m_rcWnd.Height());//向下滚动 } LineScroll(1); } } void Console::split(const char* _szText) { const char* szCurText = _szText; const char* szOldText = _szText; char* szPreText = NULL; int len = NULL; const char* szClrText = NULL; if (_szText[0] != '\x1E') { bool bIsFined = false; while ((szClrText = strchr(szCurText, '\x1E'))) { bIsFined = true; len = szClrText - szOldText; szPreText = new char[len + 1]; szPreText[len] = 0; memcpy(szPreText, szOldText, len); Console::printf(szPreText); delete[]szPreText; szCurText = szClrText + 1; szOldText = szClrText; } if (bIsFined) { if(szOldText)Console::printf(szOldText); } else { Console::printf(_szText); } } else { bool bIsFined = false; szCurText = _szText + 1; while ((szClrText = strchr(szCurText, '\x1E'))) { bIsFined = true; len = szClrText - szOldText; szPreText = new char[len + 1]; szPreText[len] = 0; memcpy(szPreText, szOldText, len); Console::printf(szPreText); delete[]szPreText; szCurText = szClrText + 1; szOldText = szClrText; } if (szOldText) { Console::printf(szOldText); } } } BEGIN_MESSAGE_MAP(Console, CRichEditCtrl) ON_NOTIFY_REFLECT(EN_SELCHANGE, &Console::OnEnSelchange) ON_NOTIFY_REFLECT(EN_MSGFILTER, &Console::OnEnMsgfilter) ON_WM_MOUSELEAVE() ON_WM_VSCROLL() END_MESSAGE_MAP() void Console::OnEnSelchange(NMHDR* pNMHDR, LRESULT* pResult) { SELCHANGE* pSelChange = reinterpret_cast<SELCHANGE*>(pNMHDR); // TODO: 控件将不发送此通知,除非您重写 // CRichEditCtrl::OnInitDialog() 函数,以将 EM_SETEVENTMASK 消息发送 // 到该控件,同时将 ENM_SELCHANGE 标志“或”运算到 lParam 掩码中。 // TODO: 在此添加控件通知处理程序代码 int iLineIndex = -1; iLineIndex = LineFromChar(pSelChange->chrg.cpMax); if (iLineIndex != -1 && iLineIndex < (int)m_vecLineInfo.size()) { CHARRANGE LineStartSel; LineInfo* pInfo = &m_vecLineInfo[iLineIndex]; switch (pSelChange->seltyp) { case 0://鼠标点击在某处文本的某个sel中 { //开始存储此行的选择sel起始位置 m_StartSel = pSelChange->chrg; break; } case CBN_EDITCHANGE://鼠标左键按住拖动选择文本 { //通过m_StartSel算出本行的选择起始位置 CPoint point = PosFromChar(m_StartSel.cpMin);//算出sel处于控件内坐标 int x = point.x; point.y = pInfo->m_yPos;//替换上本行的y坐标 LineStartSel.cpMin = CharFromPos(point);//算出本行起始位置 LineStartSel.cpMax = LineStartSel.cpMin; point = PosFromChar(LineStartSel.cpMin); if (point.x < x - 5) { //outputdebug_default("行号:%d 检测到起始位置异常,和原位差太远", iLineIndex); LineStartSel.cpMin = 0; LineStartSel.cpMax = 0; if (point.x > m_rcWnd.Width()) { m_pHScroll->SetScrollPos(point.x - m_rcWnd.Width());//通知滚动条 } else { m_pHScroll->SetScrollPos(0); } } if (pSelChange->chrg.cpMax > LineStartSel.cpMax) { //outputdebug_default("行号:%d 从左向右选择文本: %d", iLineIndex, pSelChange->chrg.cpMax); CString str; GetTextRange(pInfo->m_dwHead, pSelChange->chrg.cpMax, str); int len = str.GetLength(); if (--len > -1 && len < (int)pInfo->m_dwStrLen) { //outputdebug_default("行号:%d, 当前光标所占像素: %d", iLineIndex, pInfo->m_pDx[len]); int pix = pInfo->m_pDx[len]; if (pix > m_rcWnd.Width()) { //outputdebug_default("行号:%d, 当前光标所占像素超出控件长度: %d", iLineIndex, pix); m_pHScroll->SetScrollPos(pix - m_rcWnd.Width());//通知滚动条 } } else { if (--len > -1 && pInfo->m_dwStrLen == 0) { //此行末尾没有/r回车符 CPoint point = PosFromChar(pSelChange->chrg.cpMax); if (point.x > m_rcWnd.Width()) { m_pHScroll->SetScrollPos(point.x - m_rcWnd.Width());//通知滚动条 } else { m_pHScroll->SetScrollPos(0); } } else { int i = 0; } } } else if (pSelChange->chrg.cpMax != pInfo->m_dwHead) { //outputdebug_default("行号:%d 从右向左选择文本: head:%d start:%d, min:%d max:%d", iLineIndex, pInfo->m_dwHead, LineStartSel.cpMax, pSelChange->chrg.cpMin, pSelChange->chrg.cpMax); if (pSelChange->chrg.cpMin == pInfo->m_dwHead) { m_pHScroll->SetScrollPos(0); } } else { //outputdebug_default("x行号:%d 从右向左选择文本: head:%d start:%d, min:%d max:%d", iLineIndex, pInfo->m_dwHead, LineStartSel.cpMax, pSelChange->chrg.cpMin, pSelChange->chrg.cpMax); if (pInfo->m_dwHead == pSelChange->chrg.cpMax)//本行头部和上一行行尾重复,定位回上一行 { if (--iLineIndex > -1) { pInfo = &m_vecLineInfo[iLineIndex]; CString str; GetTextRange(pInfo->m_dwHead, pSelChange->chrg.cpMax, str); int len = str.GetLength(); //outputdebug_default("行号:%d, 当前光标所占像素: %d len:%d", iLineIndex, pInfo->m_pDx[len-2], len); if (--len > -1 && len <= (int)pInfo->m_dwStrLen) { int pix = pInfo->m_pDx[len-1]; if (pix > m_rcWnd.Width()) { //outputdebug_default("行号:%d, 当前光标所占像素超出控件长度: %d", iLineIndex, pix); //m_pHScroll->SetScrollPos(pix - m_rcWnd.Width());//通知滚动条 } } } } } break; } } } //outputdebug_default("min:%d max:%d", pSelChange->chrg.cpMin, pSelChange->chrg.cpMax); *pResult = 0; } void Console::OnEnMsgfilter(NMHDR* pNMHDR, LRESULT* pResult) { MSGFILTER* pMsgFilter = reinterpret_cast<MSGFILTER*>(pNMHDR); // TODO: 控件将不发送此通知,除非您重写 // CRichEditCtrl::OnInitDialog() 函数,以将 EM_SETEVENTMASK 消息发送 // 到该控件,同时将 ENM_KEYEVENTS 或 ENM_MOUSEEVENTS 标志 //“或”运算到 lParam 掩码中。 // TODO: 在此添加控件通知处理程序代码 switch(pMsgFilter->msg) { case WM_MOUSEMOVE: { /* if (pMsgFilter->wParam == MK_LBUTTON) { int xPos = GET_X_LPARAM(pMsgFilter->lParam); int yPos = GET_Y_LPARAM(pMsgFilter->lParam); //outputdebug_default("x: %d, y:%d",xPos, yPos); if (m_bIsCapture) { if (xPos > m_iStartPos_x) { //outputdebug_default("正在从左向右选择文本."); } else { //outputdebug_default("正在从右向左选择文本."); } m_iPrePos_x = xPos; } }*/ if (!m_bIsTrack) { m_bIsTrack = TRUE; TRACKMOUSEEVENT tme; tme.cbSize = sizeof(tme); tme.hwndTrack = m_hWnd; tme.dwFlags = TME_LEAVE | TME_HOVER; tme.dwHoverTime = 1;// 鼠标在按钮上停留超过 1ms ,才认为成功 _TrackMouseEvent(&tme); } break; } case WM_LBUTTONDOWN: { if (pMsgFilter->wParam == MK_LBUTTON) { int xPos = GET_X_LPARAM(pMsgFilter->lParam); int yPos = GET_Y_LPARAM(pMsgFilter->lParam); m_iPrePos_x = xPos; m_iStartPos_x = xPos; m_bIsCapture = TRUE; //outputdebug_default("x: %d, y:%d", xPos, yPos); } break; } case WM_LBUTTONUP: { if (pMsgFilter->wParam == MK_LBUTTON) { m_bIsCapture = FALSE; } break; } } *pResult = 0; } void Console::OnMouseLeave() { // TODO: 在此添加消息处理程序代码和/或调用默认值 m_bIsTrack = FALSE; ::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW)); CRichEditCtrl::OnMouseLeave(); } void Console::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) { // TODO: 在此添加消息处理程序代码和/或调用默认值 CRichEditCtrl::OnVScroll(nSBCode, nPos, pScrollBar); }
07-02
#ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif namespace TreePropSheet { //------------------------------------------------------------------- // class CTreePropSheet //------------------------------------------------------------------- BEGIN_MESSAGE_MAP(CTreePropSheet, CPropertySheet) //{{AFX_MSG_MAP(CTreePropSheet) ON_WM_DESTROY() //}}AFX_MSG_MAP ON_MESSAGE(PSM_ADDPAGE, OnAddPage) ON_MESSAGE(PSM_REMOVEPAGE, OnRemovePage) ON_MESSAGE(PSM_SETCURSEL, OnSetCurSel) ON_MESSAGE(PSM_SETCURSELID, OnSetCurSelId) ON_MESSAGE(PSM_ISDIALOGMESSAGE, OnIsDialogMessage) ON_NOTIFY(TVN_SELCHANGINGA, s_unPageTreeId, OnPageTreeSelChanging) ON_NOTIFY(TVN_SELCHANGINGW, s_unPageTreeId, OnPageTreeSelChanging) ON_NOTIFY(TVN_SELCHANGEDA, s_unPageTreeId, OnPageTreeSelChanged) ON_NOTIFY(TVN_SELCHANGEDW, s_unPageTreeId, OnPageTreeSelChanged) ON_COMMAND(0x1, OnOk) ON_COMMAND(0x2, OnCancel) END_MESSAGE_MAP() IMPLEMENT_DYNAMIC(CTreePropSheet, CPropertySheet) const UINT CTreePropSheet::s_unPageTreeId = 0x7EEE; CTreePropSheet::CTreePropSheet() : CPropertySheet(), m_bPageTreeSelChangedActive(FALSE), m_bTreeViewMode(TRUE), m_bPageCaption(FALSE), m_bTreeImages(FALSE), m_nPageTreeWidth(200), m_pwndPageTree(NULL), m_pFrame(NULL) {} CTreePropSheet::CTreePropSheet(UINT nIDCaption, CWnd* pParentWnd, UINT iSelectPage) : CPropertySheet(nIDCaption, pParentWnd, iSelectPage), m_bPageTreeSelChangedActive(FALSE), m_bTreeViewMode(TRUE), m_bPageCaption(FALSE), m_bTreeImages(FALSE), m_nPageTreeWidth(200), m_pwndPageTree(NULL), m_pFrame(NULL) { } CTreePropSheet::CTreePropSheet(LPCTSTR pszCaption, CWnd* pParentWnd, UINT iSelectPage) : CPropertySheet(pszCaption, pParentWnd, iSelectPage), m_bPageTreeSelChangedActive(FALSE), m_bTreeViewMode(TRUE), m_bPageCaption(FALSE), m_bTreeImages(FALSE), m_nPageTreeWidth(200), m_pwndPageTree(NULL), m_pFrame(NULL) { } CTreePropSheet::~CTreePropSheet() { } ///////////////////////////////////////////////////////////////////// // Operationen BOOL CTreePropSheet::SetTreeViewMode(BOOL bTreeViewMode /* = TRUE */, BOOL bPageCaption /* = FALSE */, BOOL bTreeImages /* = FALSE */) { if (IsWindow(m_hWnd)) { // needs to becalled, before the window has been created ASSERT(FALSE); return FALSE; } m_bTreeViewMode = bTreeViewMode; if (m_bTreeViewMode) { m_bPageCaption = bPageCaption; m_bTreeImages = bTreeImages; } return TRUE; } BOOL CTreePropSheet::SetTreeWidth(int nWidth) { if (IsWindow(m_hWnd)) { // needs to be called, before the window is created. ASSERT(FALSE); return FALSE; } m_nPageTreeWidth = nWidth; return TRUE; } void CTreePropSheet::SetEmptyPageText(LPCTSTR lpszEmptyPageText) { m_strEmptyPageMessage = lpszEmptyPageText; } DWORD CTreePropSheet::SetEmptyPageTextFormat(DWORD dwFormat) { DWORD dwPrevFormat = m_pFrame->GetMsgFormat(); m_pFrame->SetMsgFormat(dwFormat); return dwPrevFormat; } BOOL CTreePropSheet::SetTreeDefaultImages(CImageList *pImages) { if (pImages->GetImageCount() != 2) { ASSERT(FALSE); return FALSE; } if (m_DefaultImages.GetSafeHandle()) m_DefaultImages.DeleteImageList(); m_DefaultImages.Create(pImages); // update, if necessary if (IsWindow(m_hWnd)) RefillPageTree(); return TRUE; } BOOL CTreePropSheet::SetTreeDefaultImages(UINT unBitmapID, int cx, COLORREF crMask) { if (m_DefaultImages.GetSafeHandle()) m_DefaultImages.DeleteImageList(); if (!m_DefaultImages.Create(unBitmapID, cx, 0, crMask)) return FALSE; if (m_DefaultImages.GetImageCount() != 2) { m_DefaultImages.DeleteImageList(); return FALSE; } return TRUE; } CTreeCtrl* CTreePropSheet::GetPageTreeControl() { return m_pwndPageTree; } ///////////////////////////////////////////////////////////////////// // public helpers BOOL CTreePropSheet::SetPageIcon(CPropertyPage *pPage, HICON hIcon) { pPage->m_psp.dwFlags|= PSP_USEHICON; pPage->m_psp.hIcon = hIcon; return TRUE; } BOOL CTreePropSheet::SetPageIcon(CPropertyPage *pPage, UINT unIconId) { HICON hIcon = AfxGetApp()->LoadIcon(unIconId); if (!hIcon) return FALSE; return SetPageIcon(pPage, hIcon); } BOOL CTreePropSheet::SetPageIcon(CPropertyPage *pPage, CImageList &Images, int nImage) { HICON hIcon = Images.ExtractIcon(nImage); if (!hIcon) return FALSE; return SetPageIcon(pPage, hIcon); } BOOL CTreePropSheet::DestroyPageIcon(CPropertyPage *pPage) { if (!pPage || !(pPage->m_psp.dwFlags&PSP_USEHICON) || !pPage->m_psp.hIcon) return FALSE; DestroyIcon(pPage->m_psp.hIcon); pPage->m_psp.dwFlags&= ~PSP_USEHICON; pPage->m_psp.hIcon = NULL; return TRUE; } ///////////////////////////////////////////////////////////////////// // Overridable implementation helpers CString CTreePropSheet::GenerateEmptyPageMessage(LPCTSTR lpszEmptyPageMessage, LPCTSTR lpszCaption) { CString strMsg; strMsg.Format(lpszEmptyPageMessage, lpszCaption); return strMsg; } CTreeCtrl* CTreePropSheet::CreatePageTreeObject() { return new CTreeCtrl; } CPropPageFrame* CTreePropSheet::CreatePageFrame() { return new CPropPageFrameDefault; } ///////////////////////////////////////////////////////////////////// // Implementation helpers void CTreePropSheet::MoveChildWindows(int nDx, int nDy) { CWnd *pWnd = GetWindow(GW_CHILD); while (pWnd) { CRect rect; pWnd->GetWindowRect(rect); rect.OffsetRect(nDx, nDy); rect.bottom -= 50; ScreenToClient(rect); pWnd->MoveWindow(rect); pWnd->InvalidateRect(rect); pWnd = pWnd->GetNextWindow(); } } void CTreePropSheet::RefillPageTree() { if (!IsWindow(m_hWnd)) return; m_pwndPageTree->DeleteAllItems(); CTabCtrl *pTabCtrl = GetTabControl(); if (!IsWindow(pTabCtrl->GetSafeHwnd())) { ASSERT(FALSE); return; } const int nPageCount = pTabCtrl->GetItemCount(); // rebuild image list if (m_bTreeImages) { for (int i = m_Images.GetImageCount()-1; i >= 0; --i) m_Images.Remove(i); // add page images CImageList *pPageImages = pTabCtrl->GetImageList(); if (pPageImages) { for (int nImage = 0; nImage < pPageImages->GetImageCount(); ++nImage) { HICON hIcon = pPageImages->ExtractIcon(nImage); m_Images.Add(hIcon); DestroyIcon(hIcon); } } // add default images if (m_DefaultImages.GetSafeHandle()) { HICON hIcon; // add default images hIcon = m_DefaultImages.ExtractIcon(0); if (hIcon) { m_Images.Add(hIcon); DestroyIcon(hIcon); } hIcon = m_DefaultImages.ExtractIcon(1); { m_Images.Add(hIcon); DestroyIcon(hIcon); } } } // insert tree items for (int nPage = 0; nPage < nPageCount; ++nPage) { // Get title and image of the page CString strPagePath; TCITEM ti; ZeroMemory(&ti, sizeof(ti)); ti.mask = TCIF_TEXT|TCIF_IMAGE; ti.cchTextMax = MAX_PATH; ti.pszText = strPagePath.GetBuffer(ti.cchTextMax); ASSERT(ti.pszText); if (!ti.pszText) return; pTabCtrl->GetItem(nPage, &ti); strPagePath.ReleaseBuffer(); // Create an item in the tree for the page HTREEITEM hItem = CreatePageTreeItem(ti.pszText); ASSERT(hItem); if (hItem) { m_pwndPageTree->SetItemData(hItem, nPage); // set image if (m_bTreeImages) { int nImage = ti.iImage; if (nImage < 0 || nImage >= m_Images.GetImageCount()) nImage = m_DefaultImages.GetSafeHandle()? m_Images.GetImageCount()-1 : -1; m_pwndPageTree->SetItemImage(hItem, nImage, nImage); } } } } HTREEITEM CTreePropSheet::CreatePageTreeItem(LPCTSTR lpszPath, HTREEITEM hParent /* = TVI_ROOT */) { CString strPath(lpszPath); CString strTopMostItem(SplitPageTreePath(strPath)); // Check if an item with the given text does already exist HTREEITEM hItem = NULL; HTREEITEM hChild = m_pwndPageTree->GetChildItem(hParent); while (hChild) { if (m_pwndPageTree->GetItemText(hChild) == strTopMostItem) { hItem = hChild; break; } hChild = m_pwndPageTree->GetNextItem(hChild, TVGN_NEXT); } // If item with that text does not already exist, create a new one if (!hItem) { hItem = m_pwndPageTree->InsertItem(strTopMostItem, hParent); m_pwndPageTree->SetItemData(hItem, -1); if (!strPath.IsEmpty() && m_bTreeImages && m_DefaultImages.GetSafeHandle()) // set folder image m_pwndPageTree->SetItemImage(hItem, m_Images.GetImageCount()-2, m_Images.GetImageCount()-2); } if (!hItem) { ASSERT(FALSE); return NULL; } if (strPath.IsEmpty()) return hItem; else return CreatePageTreeItem(strPath, hItem); } CString CTreePropSheet::SplitPageTreePath(CString &strRest) { int nSeperatorPos = 0; while (TRUE) { nSeperatorPos = strRest.Find(_T("::"), nSeperatorPos); if (nSeperatorPos == -1) { CString strItem(strRest); strRest.Empty(); return strItem; } else if (nSeperatorPos>0) { // if there is an odd number of backslashes infront of the // seperator, than do not interpret it as separator int nBackslashCount = 0; for (int nPos = nSeperatorPos-1; nPos >= 0 && strRest[nPos]==_T('\\'); --nPos, ++nBackslashCount); if (nBackslashCount%2 == 0) break; else ++nSeperatorPos; } } CString strItem(strRest.Left(nSeperatorPos)); strItem.Replace(_T("\\::"), _T("::")); strItem.Replace(_T("\\\\"), _T("\\")); strRest = strRest.Mid(nSeperatorPos+2); return strItem; } BOOL CTreePropSheet::KillActiveCurrentPage() { HWND hCurrentPage = PropSheet_GetCurrentPageHwnd(m_hWnd); if (!IsWindow(hCurrentPage)) { ASSERT(FALSE); return TRUE; } // Check if the current page is really active (if page is invisible // an virtual empty page is the active one. if (!::IsWindowVisible(hCurrentPage)) return TRUE; // Try to deactivate current page PSHNOTIFY pshn; pshn.hdr.code = PSN_KILLACTIVE; pshn.hdr.hwndFrom = m_hWnd; pshn.hdr.idFrom = GetDlgCtrlID(); pshn.lParam = 0; if (::SendMessage(hCurrentPage, WM_NOTIFY, pshn.hdr.idFrom, (LPARAM)&pshn)) // current page does not allow page change return FALSE; // Hide the page ::ShowWindow(hCurrentPage, SW_HIDE); return TRUE; } HTREEITEM CTreePropSheet::GetPageTreeItem(int nPage, HTREEITEM hRoot /* = TVI_ROOT */) { // Special handling for root case if (hRoot == TVI_ROOT) hRoot = m_pwndPageTree->GetNextItem(NULL, TVGN_ROOT); // Check parameters if (nPage < 0 || nPage >= GetPageCount()) { ASSERT(FALSE); return NULL; } if (hRoot == NULL) { ASSERT(FALSE); return NULL; } // we are performing a simple linear search here, because we are // expecting only little data HTREEITEM hItem = hRoot; while (hItem) { if ((signed)m_pwndPageTree->GetItemData(hItem) == nPage) return hItem; if (m_pwndPageTree->ItemHasChildren(hItem)) { HTREEITEM hResult = GetPageTreeItem(nPage, m_pwndPageTree->GetNextItem(hItem, TVGN_CHILD)); if (hResult) return hResult; } hItem = m_pwndPageTree->GetNextItem(hItem, TVGN_NEXT); } // we've found nothing, if we arrive here return hItem; } BOOL CTreePropSheet::SelectPageTreeItem(int nPage) { HTREEITEM hItem = GetPageTreeItem(nPage); if (!hItem) return FALSE; return m_pwndPageTree->SelectItem(hItem); } BOOL CTreePropSheet::SelectCurrentPageTreeItem() { CTabCtrl *pTab = GetTabControl(); if (!IsWindow(pTab->GetSafeHwnd())) return FALSE; return SelectPageTreeItem(pTab->GetCurSel()); } void CTreePropSheet::UpdateCaption() { HWND hPage = PropSheet_GetCurrentPageHwnd(GetSafeHwnd()); BOOL bRealPage = IsWindow(hPage) && ::IsWindowVisible(hPage); HTREEITEM hItem = m_pwndPageTree->GetSelectedItem(); if (!hItem) return; CString strCaption = m_pwndPageTree->GetItemText(hItem); // if empty page, then update empty page message if (!bRealPage) m_pFrame->SetMsgText(GenerateEmptyPageMessage(m_strEmptyPageMessage, strCaption)); // if no captions are displayed, cancel here if (!m_pFrame->GetShowCaption()) return; // get tab control, to the the images from CTabCtrl *pTabCtrl = GetTabControl(); if (!IsWindow(pTabCtrl->GetSafeHwnd())) { ASSERT(FALSE); return; } if (m_bTreeImages) { // get image from tree int nImage; m_pwndPageTree->GetItemImage(hItem, nImage, nImage); HICON hIcon = m_Images.ExtractIcon(nImage); m_pFrame->SetCaption(strCaption, hIcon); if (hIcon) DestroyIcon(hIcon); } else if (bRealPage) { // get image from hidden (original) tab provided by the original // implementation CImageList *pImages = pTabCtrl->GetImageList(); if (pImages) { TCITEM ti; ZeroMemory(&ti, sizeof(ti)); ti.mask = TCIF_IMAGE; HICON hIcon = NULL; if (pTabCtrl->GetItem((int)m_pwndPageTree->GetItemData(hItem), &ti)) hIcon = pImages->ExtractIcon(ti.iImage); m_pFrame->SetCaption(strCaption, hIcon); if (hIcon) DestroyIcon(hIcon); } else m_pFrame->SetCaption(strCaption); } else m_pFrame->SetCaption(strCaption); } void CTreePropSheet::ActivatePreviousPage() { if (!IsWindow(m_hWnd)) return; if (!IsWindow(m_pwndPageTree->GetSafeHwnd())) { // normal tab property sheet. Simply use page index int nPageIndex = GetActiveIndex(); if (nPageIndex<0 || nPageIndex>=GetPageCount()) return; int nPrevIndex = (nPageIndex==0)? GetPageCount()-1 : nPageIndex-1; SetActivePage(nPrevIndex); } else { // property sheet with page tree. // we need a more sophisticated handling here, than simply using // the page index, because we won't skip empty pages. // so we have to walk the page tree HTREEITEM hItem = m_pwndPageTree->GetSelectedItem(); ASSERT(hItem); if (!hItem) return; HTREEITEM hPrevItem = NULL; if (hPrevItem=m_pwndPageTree->GetPrevSiblingItem(hItem)) { while (m_pwndPageTree->ItemHasChildren(hPrevItem)) { hPrevItem = m_pwndPageTree->GetChildItem(hPrevItem); while (m_pwndPageTree->GetNextSiblingItem(hPrevItem)) hPrevItem = m_pwndPageTree->GetNextSiblingItem(hPrevItem); } } else hPrevItem=m_pwndPageTree->GetParentItem(hItem); if (!hPrevItem) { // no prev item, so cycle to the last item hPrevItem = m_pwndPageTree->GetRootItem(); while (TRUE) { while (m_pwndPageTree->GetNextSiblingItem(hPrevItem)) hPrevItem = m_pwndPageTree->GetNextSiblingItem(hPrevItem); if (m_pwndPageTree->ItemHasChildren(hPrevItem)) hPrevItem = m_pwndPageTree->GetChildItem(hPrevItem); else break; } } if (hPrevItem) m_pwndPageTree->SelectItem(hPrevItem); } } void CTreePropSheet::ActivateNextPage() { if (!IsWindow(m_hWnd)) return; if (!IsWindow(m_pwndPageTree->GetSafeHwnd())) { // normal tab property sheet. Simply use page index int nPageIndex = GetActiveIndex(); if (nPageIndex<0 || nPageIndex>=GetPageCount()) return; int nNextIndex = (nPageIndex==GetPageCount()-1)? 0 : nPageIndex+1; SetActivePage(nNextIndex); } else { // property sheet with page tree. // we need a more sophisticated handling here, than simply using // the page index, because we won't skip empty pages. // so we have to walk the page tree HTREEITEM hItem = m_pwndPageTree->GetSelectedItem(); ASSERT(hItem); if (!hItem) return; HTREEITEM hNextItem = NULL; if (hNextItem=m_pwndPageTree->GetChildItem(hItem)) ; else if (hNextItem=m_pwndPageTree->GetNextSiblingItem(hItem)) ; else if (m_pwndPageTree->GetParentItem(hItem)) { while (!hNextItem) { hItem = m_pwndPageTree->GetParentItem(hItem); if (!hItem) break; hNextItem = m_pwndPageTree->GetNextSiblingItem(hItem); } } if (!hNextItem) // no next item -- so cycle to the first item hNextItem = m_pwndPageTree->GetRootItem(); if (hNextItem) m_pwndPageTree->SelectItem(hNextItem); } } ///////////////////////////////////////////////////////////////////// // Overridings BOOL CTreePropSheet::OnInitDialog() { if (m_bTreeViewMode) { // be sure, there are no stacked tabs, because otherwise the // page caption will be to large in tree view mode EnableStackedTabs(FALSE); // Initialize image list. if (m_DefaultImages.GetSafeHandle()) { IMAGEINFO ii; m_DefaultImages.GetImageInfo(0, &ii); if (ii.hbmImage) DeleteObject(ii.hbmImage); if (ii.hbmMask) DeleteObject(ii.hbmMask); m_Images.Create(ii.rcImage.right-ii.rcImage.left, ii.rcImage.bottom-ii.rcImage.top, ILC_COLOR32|ILC_MASK, 0, 1); } else m_Images.Create(16, 16, ILC_COLOR32|ILC_MASK, 0, 1); } // perform default implementation BOOL bResult = CPropertySheet::OnInitDialog(); if (!m_bTreeViewMode) // stop here, if we would like to use tabs return bResult; // Get tab control... CTabCtrl *pTab = GetTabControl(); if (!IsWindow(pTab->GetSafeHwnd())) { ASSERT(FALSE); return bResult; } // ... and hide it pTab->ShowWindow(SW_HIDE); pTab->EnableWindow(FALSE); // Place another (empty) tab ctrl, to get a frame instead CRect rectFrame; pTab->GetWindowRect(rectFrame); ScreenToClient(rectFrame); rectFrame.bottom -= 50; m_pFrame = CreatePageFrame(); if (!m_pFrame) { ASSERT(FALSE); AfxThrowMemoryException(); } m_pFrame->Create(WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS, rectFrame, this, 0xFFFF); m_pFrame->ShowCaption(m_bPageCaption); // Lets make place for the tree ctrl const int nTreeWidth = m_nPageTreeWidth; const int nTreeSpace = 5; CRect rectSheet; GetWindowRect(rectSheet); rectSheet.right+= nTreeWidth; SetWindowPos(NULL, -1, -1, rectSheet.Width(), rectSheet.Height()-50, SWP_NOZORDER|SWP_NOMOVE|SWP_NOACTIVATE); CenterWindow(); MoveChildWindows(nTreeWidth, 0); // Lets calculate the rectangle for the tree ctrl CRect rectTree(rectFrame); rectTree.right = rectTree.left + nTreeWidth - nTreeSpace; // calculate caption height CTabCtrl wndTabCtrl; wndTabCtrl.Create(WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS, rectFrame, this, 0x1234); wndTabCtrl.InsertItem(0, _T("")); CRect rectFrameCaption; wndTabCtrl.GetItemRect(0, rectFrameCaption); wndTabCtrl.DestroyWindow(); m_pFrame->SetCaptionHeight(rectFrameCaption.Height()); // if no caption should be displayed, make the window smaller in // height if (!m_bPageCaption) { // make frame smaller m_pFrame->GetWnd()->GetWindowRect(rectFrame); ScreenToClient(rectFrame); rectFrame.top+= rectFrameCaption.Height(); m_pFrame->GetWnd()->MoveWindow(rectFrame); // move all child windows up MoveChildWindows(0, -rectFrameCaption.Height()); // modify rectangle for the tree ctrl rectTree.bottom-= rectFrameCaption.Height(); // make us smaller CRect rect; GetWindowRect(rect); rect.top+= rectFrameCaption.Height()/2; rect.bottom-= rectFrameCaption.Height()-rectFrameCaption.Height()/2; if (GetParent()) GetParent()->ScreenToClient(rect); MoveWindow(rect); } // finally create tht tree control const DWORD dwTreeStyle = TVS_SHOWSELALWAYS|TVS_TRACKSELECT|TVS_HASLINES|TVS_LINESATROOT|TVS_HASBUTTONS; m_pwndPageTree = CreatePageTreeObject(); if (!m_pwndPageTree) { ASSERT(FALSE); AfxThrowMemoryException(); } // MFC7-support here (Thanks to Rainer Wollgarten) #if _MFC_VER >= 0x0700 { m_pwndPageTree->CreateEx( WS_EX_CLIENTEDGE|WS_EX_NOPARENTNOTIFY, WS_TABSTOP|WS_CHILD|WS_VISIBLE|dwTreeStyle, rectTree, this, s_unPageTreeId); } #else { m_pwndPageTree->CreateEx( WS_EX_CLIENTEDGE|WS_EX_NOPARENTNOTIFY, _T("SysTreeView32"), _T("PageTree"), WS_TABSTOP|WS_CHILD|WS_VISIBLE|dwTreeStyle, rectTree, this, s_unPageTreeId); } #endif if (m_bTreeImages) { m_pwndPageTree->SetImageList(&m_Images, TVSIL_NORMAL); m_pwndPageTree->SetImageList(&m_Images, TVSIL_STATE); } // Fill the tree ctrl RefillPageTree(); // Select item for the current page if (pTab->GetCurSel() > -1) SelectPageTreeItem(pTab->GetCurSel()); HTREEITEM hItem = m_pwndPageTree->GetChildItem(NULL); while ( hItem ) { m_pwndPageTree->Expand(hItem, TVE_EXPAND); hItem = m_pwndPageTree->GetNextSiblingItem( hItem ); } CRect rectok, rectcancel, rectDlg; GetDlgItem(IDOK)->GetWindowRect(&rectok); GetDlgItem(IDCANCEL)->GetWindowRect(&rectcancel); GetWindowRect(&rectDlg); rectok.top = rectDlg.bottom - 35; rectok.bottom = rectok.top + 25; rectcancel.top = rectDlg.bottom - 35; rectcancel.bottom = rectcancel.top + 25; ScreenToClient(&rectok); ScreenToClient(&rectcancel); GetDlgItem(IDOK)->MoveWindow(&rectok); GetDlgItem(IDCANCEL)->MoveWindow(&rectcancel); return bResult; } void CTreePropSheet::OnDestroy() { CPropertySheet::OnDestroy(); if (m_Images.GetSafeHandle()) m_Images.DeleteImageList(); delete m_pwndPageTree; m_pwndPageTree = NULL; delete m_pFrame; m_pFrame = NULL; } LRESULT CTreePropSheet::OnAddPage(WPARAM wParam, LPARAM lParam) { LRESULT lResult = DefWindowProc(PSM_ADDPAGE, wParam, lParam); if (!m_bTreeViewMode) return lResult; RefillPageTree(); SelectCurrentPageTreeItem(); return lResult; } LRESULT CTreePropSheet::OnRemovePage(WPARAM wParam, LPARAM lParam) { LRESULT lResult = DefWindowProc(PSM_REMOVEPAGE, wParam, lParam); if (!m_bTreeViewMode) return lResult; RefillPageTree(); SelectCurrentPageTreeItem(); return lResult; } LRESULT CTreePropSheet::OnSetCurSel(WPARAM wParam, LPARAM lParam) { LRESULT lResult = DefWindowProc(PSM_SETCURSEL, wParam, lParam); if (!m_bTreeViewMode) return lResult; SelectCurrentPageTreeItem(); UpdateCaption(); return lResult; } LRESULT CTreePropSheet::OnSetCurSelId(WPARAM wParam, LPARAM lParam) { LRESULT lResult = DefWindowProc(PSM_SETCURSEL, wParam, lParam); if (!m_bTreeViewMode) return lResult; SelectCurrentPageTreeItem(); UpdateCaption(); return lResult; } void CTreePropSheet::OnPageTreeSelChanging(NMHDR *pNotifyStruct, LRESULT *plResult) { *plResult = 0; if (m_bPageTreeSelChangedActive) return; else m_bPageTreeSelChangedActive = TRUE; NMTREEVIEW *pTvn = reinterpret_cast<NMTREEVIEW*>(pNotifyStruct); int nPage = m_pwndPageTree->GetItemData(pTvn->itemNew.hItem); BOOL bResult; if (nPage<0 || (unsigned)nPage>=m_pwndPageTree->GetCount()) bResult = KillActiveCurrentPage(); else bResult = SetActivePage(nPage); if (!bResult) // prevent selection to change *plResult = TRUE; // Set focus to tree ctrl (I guess that's what the user expects) m_pwndPageTree->SetFocus(); m_bPageTreeSelChangedActive = FALSE; return; } void CTreePropSheet::OnPageTreeSelChanged(NMHDR *pNotifyStruct, LRESULT *plResult) { *plResult = 0; UpdateCaption(); return; } LRESULT CTreePropSheet::OnIsDialogMessage(WPARAM wParam, LPARAM lParam) { MSG *pMsg = reinterpret_cast<MSG*>(lParam); if (pMsg->message==WM_KEYDOWN && pMsg->wParam==VK_TAB && GetKeyState(VK_CONTROL)&0x8000) { if (GetKeyState(VK_SHIFT)&0x8000) ActivatePreviousPage(); else ActivateNextPage(); return TRUE; } return CPropertySheet::DefWindowProc(PSM_ISDIALOGMESSAGE, wParam, lParam); } void CTreePropSheet::OnOk() { //首先给各子窗口发送 IDOK 消息 for (long l = 0; l < m_pages.GetSize(); l++) { CPropertyPage *pPage = (CPropertyPage*)m_pages[l]; if( pPage != NULL && !::IsBadWritePtr(pPage, sizeof(CPropertyPage)) && pPage->GetSafeHwnd() ) { pPage->UpdateData(TRUE); pPage->OnOK(); } } ::DestroyWindow( m_hWnd ); } void CTreePropSheet::OnCancel() { //首先给各子窗口发送 CANCEL 消息 for (long l = 0; l < m_pages.GetSize(); l++) { CPropertyPage *pPage = (CPropertyPage*)m_pages[l]; if( pPage != NULL && !::IsBadWritePtr(pPage, sizeof(CPropertyPage)) && pPage->GetSafeHwnd() ) { pPage->OnCancel(); } } ::DestroyWindow( m_hWnd ); //EndDialog( IDCANCEL ); } void InitCassParam(CPara1Dlg &m_page1, CPara2Dlg &m_page2, CPara3Dlg &m_page3) { int nElecline=1,nWall=0,nWallSimbol=0,nXiepo=0,nComputeArea=3; double dHatchSpace=20.0,dDtm=10.0; TCHAR szMapInfo[255]=_T("\\CASS9.0\\system\\MapInfo.db"); TCHAR TkChdw[100]=_T("单位名称"),TkCtrq[100]=_T("2002年3月数字化制图."); TCHAR TkZbx[100]=_T("任意直角坐标系: 坐标起点以 地方 为原点起算."); TCHAR TkGcjz[100]=_T("1985国家高程基准,等高距为1米."),TkTushi[100]=_T("2006年版图式."); TCHAR TkSurvey[100]=_T(""),TkDraw[100]=_T(""),TkCheck[100]=_T(""),TkSecret[255]=_T(""); BOOL bCenterLine = FALSE, bHasCenterLine = FALSE, bMakeRegion = FALSE; HKEY rKey; int nTemp; int nHighBits = 2, g_nInmapType = 0, g_nOutmapType = 0, g_nBmsbClose = 1, g_nContinuous = 0, g_nXiepoline = 0, g_bRegenKzdzj, g_bRegenGcdzj,g_bRegenJzwzj; double g_dZdhHeight = 1, g_dJzwHeight = 1, g_dLsxStep = 1; int nInstru = 24000; //全站仪型号 int nParity = 1; //校验 int nByteSize = 1;//数据位 int nTimeOut = 1;//延时 int nPort = 1;//通讯口 int nStopBits = 1;//停止位 int nBaudRate = 1;//波特率 int nZhandian = 1;//展点类型 if (RegOpenKeyEx(HKEY_CURRENT_USER, CASS_REGSTER, 0, KEY_READ, &rKey)==ERROR_SUCCESS) { //地物绘制 CassQueryReg(rKey,_T("highbits"),g_nHighBits); //高程注记小数点位数 CassQueryReg(rKey,_T("elecline"),nElecline); //电力线电杆间是否连线 CassQueryReg(rKey,_T("wall"),nWall); //围墙端是否封口 CassQueryReg(rKey,_T("wallsimbol"),nWallSimbol); //围墙两线间符号 0--图块 1--短线 CassQueryReg(rKey,_T("xiepo"),nXiepo); //自然斜坡短线的长度 0--短 1--长 CassQueryReg(rKey,_T("hatchspace"),dHatchSpace); //填充间距 CassQueryReg(rKey,_T("kanhigh"),g_dKanHigh); //陡坎默认坎高 CassQueryReg(rKey,_T("dtm"),dDtm); //DTM三角形最小角 CassQueryReg(rKey,_T("inmaptype"),g_nInmapType); //生成交换文件选项 0--骨架线 1--图形元素 CassQueryReg(rKey,_T("outmaptype"),g_nOutmapType); //读入交换文件选项 0--骨架线 1--图形元素 CassQueryReg(rKey,_T("bmsbclose"),g_nBmsbClose); CassQueryReg(rKey,_T("continuous"),g_nContinuous); CassQueryReg(rKey,_T("xiepodi"),g_nXiepoline); CassQueryReg(rKey,_T("zdtype"),g_nZdType); CassQueryReg(rKey,_T("mapdbf"),szMapInfo); //图幅数据库名 CassQueryReg(rKey,_T("userpath"),g_szUsePath); //用户工作目录名 CassQueryReg(rKey,_T("gcdheight"),g_dGcdHeight); //高程点字高 CassQueryReg(rKey,_T("gcdwordstyle"),g_szWordStyle); //高程点注记字体 CassQueryReg(rKey,_T("zdhheight"),g_dZdhHeight); //展点号字高 CassQueryReg(rKey,_T("jzwheight"),g_dJzwHeight); //建筑物字高 CassQueryReg(rKey,_T("lsxstep"),g_dLsxStep); //流水线步长 CassQueryReg(rKey,_T("textfactor"),g_dTextFactor); //文字宽高比 CassQueryReg(rKey,_T("transect"),g_nTufaDeci); //土方计算小数位数 CassQueryReg(rKey,_T("computearea"),nComputeArea); //面积计算小数位数 CassQueryReg(rKey, _T("road_centerlinemake"), bCenterLine); //道路、桥梁、河流是否按中心线生成 CassQueryReg(rKey, _T("road_hascenterline"), bHasCenterLine); //道路、桥梁、河流生成中心线 CassQueryReg(rKey, _T("road_makeregion"), bMakeRegion); //道路、桥梁、河流生成面 CassQueryReg(rKey, _T("tufangdoukan"), g_bIfDouKan); CassQueryReg(rKey, _T("fgwhighbits"), g_nFgwHighDeci); //方格网土方格网高程注记位数 CassQueryReg(rKey,_T("hdmhighbits"),g_nHdmHighDeci); //横断面线高程注记位数 CassQueryReg(rKey,_T("hdmdistbits"),g_nHdmDistDeci); //横断面线距离注记位数 nTemp=1; CassQueryReg(rKey,_T("regenkzdzj"),nTemp); if ( 0 == nTemp ) g_bRegenKzdzj = FALSE; else g_bRegenKzdzj = TRUE; nTemp=1; CassQueryReg(rKey,_T("regengcdzj"),nTemp); if ( 0 == nTemp ) g_bRegenGcdzj = FALSE; else g_bRegenGcdzj = TRUE; nTemp=1; CassQueryReg(rKey,_T("regenjzwzj"),nTemp); if ( 0 == nTemp ) g_bRegenJzwzj = FALSE; else g_bRegenJzwzj = TRUE; CassQueryReg(rKey,_T("sc_enable"), m_page3.m_nEnableShortCuts); //是否启用快捷键 //电子平板 CassQueryReg(rKey,_T("totalstation"), nInstru); //全站仪型号 CassQueryReg(rKey,_T("parity"), nParity); //校验 CassQueryReg(rKey,_T("ByteSize"), nByteSize); //数据位 CassQueryReg(rKey,_T("timeout"), nTimeOut); //延时 CassQueryReg(rKey,_T("port"), nPort); //通讯口 CassQueryReg(rKey,_T("stopbits"), nStopBits); //停止位 CassQueryReg(rKey,_T("baudrate"),nTemp); nBaudRate = nTemp;//波特率 nZhandian=0; CassQueryReg(rKey,_T("dzpbzd"), nZhandian); //展点类型 ////图框参数 //CassQueryReg(rKey,_T("tk_chdw"),TkChdw); //CassQueryReg(rKey,_T("tk_ctrq"),TkCtrq); //CassQueryReg(rKey,_T("tk_zbx"),TkZbx); //CassQueryReg(rKey,_T("tk_gcjz"),TkGcjz); //CassQueryReg(rKey,_T("tk_tushi"),TkTushi); //CassQueryReg(rKey,_T("tk_survey"),TkSurvey); //CassQueryReg(rKey,_T("tk_draw"),TkDraw); //CassQueryReg(rKey,_T("tk_check"),TkCheck); //CassQueryReg(rKey,_T("tk_secret"),TkSecret); RegCloseKey(rKey); } //读出对话框 CAcModuleResourceOverride myResources; HWND hWndACAD = adsw_acadMainWnd(); m_page1.m_nGao = g_nHighBits-1; if (1 == nElecline) m_page1.m_nDian=0; else m_page1.m_nDian=1; m_page1.m_nWall = nWall; m_page1.m_nWallSimbol = nWallSimbol; m_page1.m_nXie = nXiepo; m_page1.m_dTian = dHatchSpace; m_page1.m_dKan = g_dKanHigh; m_page1.m_dGcd = g_dGcdHeight; m_page1.m_strWrdSty.Format(_T("%s"),g_szWordStyle); m_page1.m_dZdh = g_dZdhHeight; m_page1.m_dJzwHeight = g_dJzwHeight; m_page1.m_dLsxStep = g_dLsxStep; m_page1.m_nContinuous = g_nContinuous; m_page1.m_nXiepoline = g_nXiepoline; m_page1.m_bCenterLine = bCenterLine; m_page1.m_bHasCenterLine = bHasCenterLine; m_page1.m_bMakeRegion = bMakeRegion; m_page1.m_nZdType = g_nZdType; m_page1.m_dTextWidth = g_dTextFactor; m_page3.m_dDtm = dDtm; m_page3.m_nInmap = g_nInmapType; m_page3.m_nOutmap = g_nOutmapType; m_page3.m_nClose = g_nBmsbClose; m_page3.m_strUserdPath.Format(_T("%s"),g_szUsePath); m_page3.m_strMapinfo.Format(_T("%s"),szMapInfo); m_page3.m_nTransect = g_nTufaDeci; m_page3.m_nComputeArea = nComputeArea; m_page3.m_bKzdzj = g_bRegenKzdzj; m_page3.m_bGczj = g_bRegenGcdzj; m_page3.m_bJzwzj = g_bRegenJzwzj; m_page3.m_bIfDoukan = g_bIfDouKan; m_page3.m_nFGWGao = g_nFgwHighDeci; m_page3.m_nHgmDist = g_nHdmDistDeci; m_page3.m_nHgmGc = g_nHdmHighDeci; //电子平板 m_page2.m_nStation = nInstru; //全站仪型号 m_page2.m_nOvertime = nTimeOut; //延时 m_page2.m_nPort = nPort; //通讯口 m_page2.m_nCheck = nParity; //校验 m_page2.m_strBTL.Format(_T("%d"), nBaudRate); // if ( 2400 == nBaudRate ) m_page2.m_nBaud = 1; //波特率 // else if ( 4800 == nBaudRate )m_page2.m_nBaud = 2; // else if ( 9600 == nBaudRate ) m_page2.m_nBaud = 3; // else if (115200 == nBaudRate) m_page2.m_nBaud = 4; // else m_page2.m_nBaud = 0; if ( 7 == nByteSize ) m_page2.m_nData = 1; //数据位 else m_page2.m_nData = 0; if ( 2 == nStopBits ) m_page2.m_nStop = 1; //停止位 else m_page2.m_nStop = 0; m_page2.m_nZhandian = nZhandian; } void SetCassParam(CPara1Dlg &m_page1, CPara2Dlg &m_page2, CPara3Dlg &m_page3) { int nElecline=1,nWall=0,nWallSimbol=0,nXiepo=0,nTransect=1,nComputeArea=3; double dHatchSpace=20.0,dDtm=10.0; TCHAR szMapInfo[255]=_T("\\CASS9.0\\system\\MapInfo.db"); TCHAR TkChdw[100]=_T("单位名称"),TkCtrq[100]=_T("2002年3月数字化制图."); TCHAR TkZbx[100]=_T("任意直角坐标系: 坐标起点以 地方 为原点起算."); TCHAR TkGcjz[100]=_T("1985国家高程基准,等高距为1米."),TkTushi[100]=_T("2006年版图式."); TCHAR TkSurvey[100]=_T(""),TkDraw[100]=_T(""),TkCheck[100]=_T(""),TkSecret[255]=_T(""); BOOL bCenterLine = m_page1.m_bCenterLine, bHasCenterLine = m_page1.m_bHasCenterLine, bMakeRegion = m_page1.m_bMakeRegion; HKEY rKey; int nTemp; if ( false == seekdog() ) return; int nHighBits = 2, g_nInmapType = 0, g_nOutmapType = 0, g_nBmsbClose = 1, g_nContinuous = 0, g_nXiepoline = 0, g_bRegenKzdzj, g_bRegenGcdzj,g_bRegenJzwzj; double g_dZdhHeight = 1, g_dJzwHeight = 1, g_dLsxStep = 1; int nInstru = 24000; //全站仪型号 int nParity = 1; //校验 int nByteSize = 1;//数据位 int nTimeOut = 1;//延时 int nPort = 1;//通讯口 int nStopBits = 1;//停止位 int nBaudRate = 1;//波特率 int nZhandian = 1;//展点类型 //写入对话框 g_nHighBits = m_page1.m_nGao+1; if (0 == m_page1.m_nDian) nElecline=1; else nElecline=0; nWall = m_page1.m_nWall; nWallSimbol = m_page1.m_nWallSimbol; nXiepo = m_page1.m_nXie; dHatchSpace = m_page1.m_dTian; g_dKanHigh = m_page1.m_dKan; dDtm = m_page3.m_dDtm; g_dGcdHeight = m_page1.m_dGcd; _tcscpy(g_szWordStyle, m_page1.m_strWrdSty); g_dZdhHeight = m_page1.m_dZdh; g_dJzwHeight = m_page1.m_dJzwHeight; g_dLsxStep = m_page1.m_dLsxStep; g_nContinuous = m_page1.m_nContinuous; g_nXiepoline = m_page1.m_nXiepoline; g_nZdType = m_page1.m_nZdType; g_nInmapType = m_page3.m_nInmap; g_nOutmapType = m_page3.m_nOutmap; g_nBmsbClose = m_page3.m_nClose; _tcscpy(g_szUsePath, m_page3.m_strUserdPath); if ( '\\' != g_szUsePath[_tcslen(g_szUsePath)-1] ) _tcscat(g_szUsePath,_T("\\")); //2003.08.02 _tcscpy(szMapInfo, m_page3.m_strMapinfo); g_dTextFactor = m_page1.m_dTextWidth; g_nTufaDeci = m_page3.m_nTransect; nComputeArea = m_page3.m_nComputeArea; g_bRegenKzdzj = m_page3.m_bKzdzj; g_bRegenGcdzj = m_page3.m_bGczj; g_bRegenJzwzj = m_page3.m_bJzwzj; //电子平板 nInstru = m_page2.m_nStation; //全站仪型号 nTimeOut = m_page2.m_nOvertime; //延时 nPort = m_page2.m_nPort; //通讯口 nParity = m_page2.m_nCheck; //校验 nBaudRate = _ttoi(m_page2.m_strBTL); // if ( 1 == m_page2.m_nBaud ) nBaudRate = 2400; //波特率 // else if ( 2 == m_page2.m_nBaud ) nBaudRate = 4800; // else if ( 3 == m_page2.m_nBaud ) nBaudRate = 9600; // else if (4 == m_page2.m_nBaud) nBaudRate = 115200; // else nBaudRate = 1200; if ( 1 == m_page2.m_nData ) nByteSize = 7; //数据位 else nByteSize = 8; if ( 1 == m_page2.m_nStop ) nStopBits = 2; //停止位 else nStopBits = 0; nZhandian = m_page2.m_nZhandian; //展点 //写入注册表 DWORD result; if ( RegCreateKeyEx(HKEY_CURRENT_USER, CASS_REGSTER, 0, _T(""), REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &rKey, &result) != ERROR_SUCCESS) return; CassSetReg(rKey,_T("highbits"),g_nHighBits); //高程注记小数点位数 CassSetReg(rKey,_T("elecline"),nElecline); //电力线电杆间是否连线 CassSetReg(rKey,_T("wall"),nWall); //围墙端是否封口 CassSetReg(rKey,_T("wallsimbol"),nWallSimbol); //围墙端是否封口 CassSetReg(rKey,_T("xiepo"),nXiepo); //自然斜坡短线的长度 0--短 1--长 CassSetReg(rKey,_T("hatchspace"),dHatchSpace); //填充间距 CassSetReg(rKey,_T("kanhigh"),g_dKanHigh); //陡坎默认坎高 CassSetReg(rKey,_T("dtm"),dDtm); //DTM三角形最小角 CassSetReg(rKey,_T("inmaptype"),g_nInmapType); //生成交换文件选项 0--骨架线 1--图形元素 CassSetReg(rKey,_T("outmaptype"),g_nOutmapType); //读入交换文件选项 0--骨架线 1--图形元素 CassSetReg(rKey,_T("bmsbclose"),g_nBmsbClose); CassSetReg(rKey,_T("continuous"),g_nContinuous); CassSetReg(rKey,_T("xiepodi"),g_nXiepoline); CassSetReg(rKey,_T("zdtype"),g_nZdType); //展点注记选项 CassSetReg(rKey,_T("mapdbf"),szMapInfo); //图幅数据库名 CassSetReg(rKey,_T("userpath"),g_szUsePath); //用户工作目录名 CassSetReg(rKey,_T("gcdheight"),g_dGcdHeight); //高程点字高 CassSetReg(rKey,_T("gcdwordstyle"),g_szWordStyle); //高程点字高 CassSetReg(rKey,_T("zdhheight"),g_dZdhHeight); //展点号字高 CassSetReg(rKey,_T("jzwheight"),g_dJzwHeight); //建筑物字高 CassSetReg(rKey,_T("lsxstep"),g_dLsxStep); //流水线步长 CassSetReg(rKey,_T("textfactor"),g_dTextFactor); //文字宽高比 CassSetReg(rKey,_T("computearea"),nComputeArea); //面积计算小数位数 g_nFgwHighDeci = m_page3.m_nFGWGao; g_nHdmDistDeci = m_page3.m_nHgmDist; g_nHdmHighDeci = m_page3.m_nHgmGc; g_bIfDouKan = m_page3.m_bIfDoukan; CassSetReg(rKey, _T("tufangdoukan"), g_bIfDouKan); CassSetReg(rKey,_T("transect"),g_nTufaDeci); //土方量位数 CassSetReg(rKey,_T("fgwhighbits"),g_nFgwHighDeci); //方格网土方格网高程注记位数 CassSetReg(rKey,_T("hdmhighbits"),g_nHdmHighDeci); //横断面线高程注记位数 CassSetReg(rKey,_T("hdmdistbits"),g_nHdmDistDeci); //横断面线距离注记位数 if ( FALSE == g_bRegenGcdzj ) nTemp = 0; else nTemp = 1; CassSetReg(rKey,_T("regengcdzj"),nTemp); //重构高程点 if ( FALSE == g_bRegenKzdzj ) nTemp = 0; else nTemp = 1; CassSetReg(rKey,_T("regenkzdzj"),nTemp); //重构控制点 if ( FALSE == g_bRegenJzwzj ) nTemp = 0; else nTemp = 1; CassSetReg(rKey,_T("regenjzwzj"),nTemp); //重构建筑物注记 CassSetReg(rKey,_T("sc_enable"), m_page3.m_nEnableShortCuts); //是否启用快捷键 if (FALSE == bCenterLine) nTemp = 0; else nTemp = 1; CassSetReg(rKey, _T("road_centerlinemake"), nTemp); if (FALSE == bHasCenterLine) nTemp = 0; else nTemp = 1; CassSetReg(rKey, _T("road_hascenterline"), nTemp); if (FALSE == bMakeRegion) nTemp = 0; else nTemp = 1; CassSetReg(rKey, _T("road_makeregion"), nTemp); //电子平板 CassSetReg(rKey,_T("totalstation"), nInstru); //全站仪型号 nTemp = nBaudRate; CassSetReg(rKey,_T("baudrate"),nTemp); //波特率 CassSetReg(rKey,_T("parity"), nParity); //校验 CassSetReg(rKey,_T("ByteSize"), nByteSize); //数据位 CassSetReg(rKey,_T("timeout"), nTimeOut); //延时 CassSetReg(rKey,_T("port"), nPort); //通讯口 CassSetReg(rKey,_T("stopbits"), nStopBits); //停止位 CassSetReg(rKey,_T("dzpbzd"), nZhandian); //展点 //图框参数 /*CassSetReg(rKey,_T("tk_chdw"),TkChdw); CassSetReg(rKey,_T("tk_ctrq"),TkCtrq); CassSetReg(rKey,_T("tk_zbx"),TkZbx); CassSetReg(rKey,_T("tk_gcjz"),TkGcjz); CassSetReg(rKey,_T("tk_tushi"),TkTushi); CassSetReg(rKey,_T("tk_survey"),TkSurvey); CassSetReg(rKey,_T("tk_draw"),TkDraw); CassSetReg(rKey,_T("tk_check"),TkCheck); CassSetReg(rKey,_T("tk_secret"),TkSecret);*/ RegCloseKey(rKey); } void CTreePropSheet::ShowDongGuanSetUp() { CAcModuleResourceOverride myResources; //if( g_ThemeLib.IsAvailable() == FALSE) // { //g_ThemeLib.LoadLib(); // } #ifdef DONGGUAN #endif CDJParcelSetDlg wndPageZdt ; CMapFrameDlg mapframe ; CExplortToKMLdlg ProInfo; //投影参数 CGeoCrdDlg geocrd; CTextStyleSet textSet; CPara1Dlg param1; CPara2Dlg param2; CPara3Dlg param3; // disable help button wndPageZdt.m_psp.dwFlags&= ~PSP_HASHELP; mapframe.m_psp.dwFlags&= ~PSP_HASHELP; ProInfo.m_psp.dwFlags &= ~PSP_HASHELP; geocrd.m_psp.dwFlags &= ~PSP_HASHELP; textSet.m_psp.dwFlags &= ~PSP_HASHELP; param1.m_psp.dwFlags &= ~PSP_HASHELP; param2.m_psp.dwFlags &= ~PSP_HASHELP; param3.m_psp.dwFlags &= ~PSP_HASHELP; // set images CImageList DefaultImages, Images; DefaultImages.Create(IDB_DEFAULT, 16, 0, RGB(0x00, 0x80, 0x80)); Images.Create(IDB_IMAGES, 16, 0, RGB(0x00, 0x80, 0x80)); // TreePropSheet::CTreePropSheet::SetPageIcon( &wndPageZdt, Images, 0); TreePropSheet::CTreePropSheet::SetPageIcon( &mapframe, Images, 1); TreePropSheet::CTreePropSheet::SetPageIcon( &ProInfo, Images, 1); TreePropSheet::CTreePropSheet::SetPageIcon( &geocrd, Images, 1); TreePropSheet::CTreePropSheet::SetPageIcon( &textSet, Images, 1); TreePropSheet::CTreePropSheet sht(_T("CASS10综合设置")); InitCassParam(param1, param2, param3); sht.m_psh.dwFlags&= ~PSH_HASHELP; sht.AddPage( &wndPageZdt); sht.AddPage(&param1); sht.AddPage(&param2); sht.AddPage(&param3); sht.AddPage( &mapframe); sht.AddPage( &ProInfo); sht.AddPage( &geocrd); sht.AddPage(&textSet); sht.SetEmptyPageText(_T("请选择\"%s\"下任意一项,系统将为您设置所需信息.")); sht.SetTreeViewMode(TRUE, TRUE, TRUE); sht.SetTreeDefaultImages(&DefaultImages); sht.SetActivePage( &wndPageZdt); sht.SetTreeWidth(170); sht.DoModal(); DefaultImages.DeleteImageList(); Images.DeleteImageList(); SetCassParam(param1, param2, param3); //通知其他ARX struct resbuf *cmd,*res; cmd=ads_buildlist(RTSTR,_T("cassapara"),RTNONE); ads_invoke(cmd,&res); ads_relrb(cmd); ads_relrb(res); cmd=ads_buildlist(RTSTR,_T("landformpara"),RTNONE); ads_invoke(cmd,&res); ads_relrb(cmd); ads_relrb(res); cmd=ads_buildlist(RTSTR,_T("cass9para"),RTNONE); ads_invoke(cmd,&res); ads_relrb(cmd); ads_relrb(res); cmd=ads_buildlist(RTSTR,_T("djzdtpara"),RTNONE); ads_invoke(cmd,&res); ads_relrb(cmd); ads_relrb(res); ReadRegValue(); } //显示设置对话框 void CTreePropSheet::ShowSetUp() { #ifdef DONGGUAN ShowDongGuanSetUp(); return; #endif CAcModuleResourceOverride myResources; //if( g_ThemeLib.IsAvailable() == FALSE) // { //g_ThemeLib.LoadLib(); // } CDjParamDlg wndPageZdt ; CJzpParamDlg wndPageJzp ; // CDjReportParamDlg wndPageReport; #ifdef _XIANGTAN_KCSJY CTKSX95Dlg mapframe; #else CMapFrameDlg mapframe ; #endif CExplortToKMLdlg ProInfo; //投影参数 CGeoCrdDlg geocrd; CTextStyleSet textSet; CPara1Dlg param1; CPara2Dlg param2; CPara3Dlg param3; CParaXBLDlg xblpage; // disable help button wndPageZdt.m_psp.dwFlags&= ~PSP_HASHELP; wndPageJzp.m_psp.dwFlags&= ~PSP_HASHELP; //wndPageReport.m_psp.dwFlags&= ~PSP_HASHELP; mapframe.m_psp.dwFlags&= ~PSP_HASHELP; ProInfo.m_psp.dwFlags &= ~PSP_HASHELP; geocrd.m_psp.dwFlags &= ~PSP_HASHELP; textSet.m_psp.dwFlags &= ~PSP_HASHELP; param1.m_psp.dwFlags &= ~PSP_HASHELP; param2.m_psp.dwFlags &= ~PSP_HASHELP; param3.m_psp.dwFlags &= ~PSP_HASHELP; xblpage.m_psp.dwFlags &= ~PSP_HASHELP; // set images CImageList DefaultImages, Images; DefaultImages.Create(IDB_DEFAULT, 16, 0, RGB(0x00, 0x80, 0x80)); Images.Create(IDB_IMAGES, 16, 0, RGB(0x00, 0x80, 0x80)); // TreePropSheet::CTreePropSheet::SetPageIcon( &wndPageZdt, Images, 0); TreePropSheet::CTreePropSheet::SetPageIcon( &wndPageJzp, Images, 1); //TreePropSheet::CTreePropSheet::SetPageIcon( &wndPageReport, Images, 1); TreePropSheet::CTreePropSheet::SetPageIcon( &mapframe, Images, 1); TreePropSheet::CTreePropSheet::SetPageIcon( &ProInfo, Images, 1); TreePropSheet::CTreePropSheet::SetPageIcon( &geocrd, Images, 1); TreePropSheet::CTreePropSheet::SetPageIcon( &textSet, Images, 1); TreePropSheet::CTreePropSheet sht(_T("CASS10综合设置")); InitCassParam(param1, param2, param3); sht.m_psh.dwFlags&= ~PSH_HASHELP; sht.AddPage(&param1); sht.AddPage(&param2); sht.AddPage(&param3); sht.AddPage( &wndPageZdt); sht.AddPage( &wndPageJzp); //sht.AddPage( &wndPageReport); sht.AddPage( &mapframe); sht.AddPage( &ProInfo); sht.AddPage( &geocrd); sht.AddPage(&textSet); sht.AddPage(&xblpage); sht.SetEmptyPageText(_T("请选择\"%s\"下任意一项,系统将为您设置所需信息.")); sht.SetTreeViewMode(TRUE, TRUE, TRUE); sht.SetTreeDefaultImages(&DefaultImages); sht.SetActivePage( &param1); sht.SetTreeWidth(170); sht.DoModal(); DefaultImages.DeleteImageList(); Images.DeleteImageList(); SetCassParam(param1, param2, param3); //通知其他ARX struct resbuf *cmd,*res; cmd=ads_buildlist(RTSTR,_T("cassapara"),RTNONE); ads_invoke(cmd,&res); ads_relrb(cmd); ads_relrb(res); cmd=ads_buildlist(RTSTR,_T("landformpara"),RTNONE); ads_invoke(cmd,&res); ads_relrb(cmd); ads_relrb(res); cmd=ads_buildlist(RTSTR,_T("cass9para"),RTNONE); ads_invoke(cmd,&res); ads_relrb(cmd); ads_relrb(res); cmd=ads_buildlist(RTSTR,_T("djzdtpara"),RTNONE); ads_invoke(cmd,&res); ads_relrb(cmd); ads_relrb(res); ReadRegValue(); //if( g_ThemeLib.IsAvailable() == TRUE) { //g_ThemeLib.FreeLib(); } } } //namespace TreePropSheet
06-18
评论 4
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值