【问题标题】:Custom Find/Replace dialog box自定义查找/替换对话框
【发布时间】:2011-06-30 18:45:02
【问题描述】:

首先,请记住,我是 Windows 编程新手。我会尽量详细地回答我的问题,希望答案也是如此。

简短介绍:

我正在复制使用 Win32 API 和纯 C 编写一个类似记事本的应用程序。对于那些熟悉 Petzold 的 Windows 编程的人,这是他以前的 POPPAD 程序的修改版本描述通用对话框。我写这篇文章是为了教育目的,所以请不要发布类似“你为什么使用旧技术,使用 .NET”这样的 cmets,因为这些 cmets 不会帮助我解决我的问题 :)。

问题描述:

Petzold 在他的 POPPAD 程序中使用通用对话框来编写这个类似记事本的应用程序。他使用 Edit Control 来提供基本文本编辑器的所有功能。 POPPAD,很像记事本,也有查找和替换对话框,您可以在其中找到并替换它!令人难以置信,我知道。

所以我想在这里测试我通过阅读过去的章节获得的新知识,因为我决定编写自己的查找和替换对话框。当然,它可能是最简单的形式。它能有多难?您有一个文本字段,您可以在其中输入一些文本,并且您有一个花哨的按钮,上面写着“查找!”就可以了。
现在我想再次提醒您,我是 Windows 编程的新手,所以请原谅我有任何可能是新手的问题。另外,我想指出,我将只专注于使 Find 对话框正常工作,因为 Replace 应该不会太难实现。

所以我在 Visual Studio 中使用了资源编辑器,几个小时后我得到了这个:
(stackoverflow 实际上并不允许我发布图片,所以这是下面的链接)
http://i.imgur.com/R98x4.png

我将此对话框命名为“查找”(带引号),因此按照 Petzold 的思想,我不必在我的程序中使用 MAKEINTRESOURCE 宏。我将“确定”按钮的标题更改为“查找下一个”,并将其 ID 从 IDOK 更改为 IDC_FIND。还将IDCANCEL 更改为IDC_CANCEL,单行编辑控件为IDC_FIND_FIND

现在是更严肃的事情。在我的主程序的 Windows 过程中,我有这段代码:

case IDM_SEARCH_FIND:
               hDlgModeless = CreateDialog (hInst, TEXT ("Find"), 
                             hwnd, FindDlgProc) ;
               return 0 ;

IDM_SEARCH_FIND 是菜单项的消息标识符,单击时应打开“查找”对话框。 CreateDialog 函数用于创建无模式对话框并将其句柄存储到全局变量hDlgModeless 中。 FindDlgProc 是对话框过程的名称(我认为)所有查找文本的代码都应该放在哪里。

所以事不宜迟,下面是我的“查找”对话框过程的代码:

BOOL CALLBACK FindDlgProc (HWND hDlg, UINT message, 
                        WPARAM wParam, LPARAM lParam)
{
     static TCHAR     szFindWhat[MAX_STRING_LEN];    //Text to find
     static int       iOffset ;                      //Offset from the beginning of  Edit control to the result
     int              iLength, iPos, iSingleLength ; //Length of a main Edit control and single line Edit control 
     PTSTR            pstrDoc, pstrPos ;

     switch (message)
     {
     case WM_INITDIALOG:
          return TRUE ;

     case WM_COMMAND:
          switch (LOWORD (wParam))
          {

              //If the button "Find Next" has been pressed, process all the logic of finding the text

          case IDC_FIND:

                      // Get the text from a single-line edit control in Find dialog box
                      // and save it in szFindWhat variable

                 iSingleLength = GetWindowTextLength(GetDlgItem(hDlg, IDE_FIND_FIND)) ;
                 GetWindowText(GetDlgItem(hDlg, IDE_FIND_FIND), szFindWhat, iSingleLength)  ;

                      // Get the text from a main Edit control, allocate memory for it
                      // and store it in pstrDoc variable

                 iLength = GetWindowTextLength (hwndEdit) ;

                 if (NULL == (pstrDoc = (PTSTR) malloc ((iLength + 1) * sizeof (TCHAR))))
                      return FALSE ;

                 GetWindowText (hwndEdit, pstrDoc, iLength + 1) ;

                      // Search the document for the find string

                 pstrPos = _tcsstr (pstrDoc + iOffset, szFindWhat) ;
                 free (pstrDoc) ;

                      // Return an error code if the string cannot be found

                 if (pstrPos == NULL)
                      return FALSE ;

                      // Find the position in the document and the new start offset

                 iPos = pstrPos - pstrDoc ;
                 iOffset = iPos + lstrlen (szFindWhat) ;

                      // Select the found text

                 SendMessage (hwndEdit, EM_SETSEL, iPos, iOffset) ;
                 SendMessage (hwndEdit, EM_SCROLLCARET, 0, 0) ;

          case IDC_CANCEL:
               DestroyWindow (hDlg) ;
               hDlgModeless = NULL ;
               break ;
          }
          break ;

     case WM_CLOSE:
         DestroyWindow (hDlg) ;
         hDlgModeless = NULL ;
         break ;

     default:
         return FALSE;
     }
     return FALSE ;
}


我在这里得到的唯一实际错误是 hwndEdit 是未声明的标识符。 hwndEdit 是主编辑控件(不是查找对话框中的单行)。当我在查找对话框过程中时,如何获得hwndEdit 的句柄?

我想指出,我在这里感觉有点过头了,所以请说我是否遗漏/做错了一些明显的事情。我很确定即使我修复了我遇到的唯一错误,该程序仍然无法运行。尽管我应该做什么的概念听起来很简单,但实际上编程似乎相当困难:)

这是上面的代码应该做的,最简单的形式:
- 从“查找”对话框中获取我希望搜索的文本
- 从主编辑控件获取文本
- 从最后一个偏移量进行子字符串搜索(不要每次都从头开始)
- 查找结果的位置并重新调整偏移量
- 选择找到的文字

我知道我在这里并没有真正提出直接的问题,我想直接的问题是:我该如何进行这项工作? :) 但更重要的是要了解这究竟是如何工作的。如果您能给我一个详尽的答案,我将不胜感激。感谢大家的帮助!

【问题讨论】:

    标签: c windows winapi


    【解决方案1】:

    看起来你已经很接近了,你只需要从你的主窗口中获取 hwndEdit。您将主窗口的句柄作为父窗口传递给对话框,因此您应该能够像这样获取对话框的父窗口:

    HWND hwndParent = GetParent(hDlg);
    

    之后,您可以通过在主窗口定义中引用编辑控件 ID 从该父级获取编辑控件。像这样(假设控件 ID 是 IDC_EDIT):

    HWND hwndEdit = GetDlgItem(hwndParent, IDC_EDIT);
    

    【讨论】:

    • 感谢您的回答。你是对的,我确实得到了带有这两个功能的 hwndEdit,现在所有错误都被消除了!但是,仍然存在一些逻辑错误,因为搜索仍然无法正常工作。明天我会尝试更多地调试它(现在是凌晨 3 点),但我猜它与 iOffset 变量有关。
    • 谁能解释这条线的工作原理(我从 Petzold 复制粘贴): pstrPos = _tcsstr (pstrDoc + iOffset, szFindWhat) ;
    • @marko 这一行正在调用一个内置的字符串例程,该例程在第一个输入字符串中搜索第二个字符串,如果找到则返回指向该字符串所在位置的指针,否则返回 NULL找到它。这里棘手的部分是他将该偏移量添加到第一个字符串。此偏移量表示您当前在编辑框字符串中搜索的位置,以便您实现在记事本中习惯的查找下一个行为。如果没有偏移量,它将始终从字符串的开头开始。
    • 还要注意,这段代码中有几个错误会让人头疼。首先,iOffset 应该被初始化为 0。我很确定在 C 中静态会被初始化为 0,但通常你想在 C 中初始化你的变量,因为在大多数情况下,未初始化的变量有垃圾值,你不能指望它们具有特定的默认值。因此,尽管静态在这里可以工作,但我通常还是会初始化它们以增强清晰度并保持始终初始化变量的习惯。
    • 第二,你不应该在你释放它的地方释放 pstrDoc,因为 pstrPos 指向 pstrDoc 中的数据。完成 pstrPos 后,您需要释放 pstrDoc。
    猜你喜欢
    • 2022-01-22
    • 1970-01-01
    • 2011-07-14
    • 1970-01-01
    • 2014-02-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-04
    相关资源
    最近更新 更多