【问题标题】:c++ winapi: Move scrollbar after WM_SETTEXT to old positionc ++ winapi:将WM_SETTEXT之后的滚动条移动到旧位置
【发布时间】:2015-08-03 13:21:52
【问题描述】:

我有这种情况。我有两个多行编辑框。第一个不可编辑,第二个是。我捕捉到 EN_UPDATE 消息,当出现时,我将更新的文本从第二个窗口发送到第一个窗口。所以两个窗口都有相同的文本。此外,如果一个被滚动,第二个也被滚动(镜像行为)。

问题是,如果我在从第二个窗口发送新文本后更新第一个窗口中的文本,那么滚动条会在开始时移动。如果我使用 SetScrollPos 而不是设置滚动条,但文本不会移动到正确的位置。我看到第一行文本,我想在更新文本之前查看位置。这怎么可能?

更新

我希望在 SendMessage 到像这样的第一个窗口之后,在用新文本替换旧文本时不要将窗口移动到文本的起始位置。因为我有例如第一个窗口在中间滚动,并且在替换文本后,第一个窗口被移动到新文本的第一行但我想留在旧位置,因为我只更新第二个窗口中的文本中的字母,而不是我将此更改发送到 firstWindow。但我重新发送所有文本。

 SendMessage(firstWindow, WM_SETTEXT, 0, (LPARAM) buffer);

我创建这样的多行文本框:

firstWindow = CreateWindowEx(
            0, TEXT("EDIT"),   // predefined class
            NULL,         // no window title
            WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_BORDER |
            ES_READONLY | ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL,
            TEXTBOX_START_X, TEXTBOX_START_Y, TEXTBOX_WIDTH, TEXTBOX_HEIGHT,
            hWnd,         // parent window
            (HMENU) ID_TEXTBOX,   // edit control ID
            (HINSTANCE) GetWindowLong(hWnd, GWL_HINSTANCE),
            NULL
        );
        savedWndProcTablet = (WNDPROC) SetWindowLongPtr(tabletWindowUtils.textboxHwnd, GWL_WNDPROC, (LONG_PTR) &textBoxProc);

更新 2

我试试这个:

char *buffer = new char[2];
buffer = "a\0";
DWORD l,r;
SendMessage(secondWindow, EM_GETSEL,(WPARAM)&l,(LPARAM)&r);
SendMessage(firstWindow, EM_REPLACESEL, 0, (LPARAM)buffer);
SendMessage(firstWindow, EM_SETSEL,l,r);

所以我在第一个窗口中有一些文本,第二个窗口中的位置在哪里,我在这个位置添加了新字母。但这在正确的位置添加了一个字母,但它没有添加一个字母,但仍然添加了 aaaaaaaaaaaaaaa。为什么会这样?

我只能使用纯 c++ 和 winapi。

谢谢。

【问题讨论】:

标签: c++ user-interface winapi childwindow


【解决方案1】:

如果您想将第二个编辑框的整个文本一致地复制到第一个,并确保滚动位置正确镜像,您可以使用:

// get the full text of second window
int len = ::GetWindowTextLength(secondWindow) + 1;
LPTSTR txt = new TCHAR[len];
::GetWindowText(secondWindow, txt, len);
// copies it to first one
::SetWindowText(firstWindow, txt);
// get scroll position of second window
SCROLLINFO si = { sizeof(SCROLLINFO) };
::GetScrollInfo(secondWindow, SB_VERT, &si);
// set scroll bar of first window accordingly
::SetScrollInfo(firstWindow, SB_VERT | SIF_PAGE | SIF_POS | SIF_RANGE, &si, TRUE );
// get first visible line in second window
int line = ::SendMessage(secondWindow, EM_GETFIRSTVISIBLELINE, 0, 0);
// skip to same line in first window
::SendMessage(firstWindow, EM_LINESCROLL, 0, line);
delete[] txt;

你当然可以使用EM_REPLACESEL只复制一部分文本,但是你没有说如何找到新旧部分,所以我建议全部替换。

【讨论】:

  • 这可能会更新滚动条,但如果它真的滚动了控件的内容,我会感到惊讶。
  • @JonathanPotter :我忘记了一个重要的部分。根据您的评论更新帖子 - 现在经过测试:-)
  • 好的,这适用于 Serge Ballesta。但这会让用户看到文本位于起始行,然后移动到正确的行。所以我现在尝试使用 EM_REPLACESEL。我在 EN_UPDATE 之后执行此操作。如何检测添加了什么?用户可以添加文本,例如使用 ctrl-c + ctr+v 或通过右键单击显示的对话框中的粘贴选项。是否比在 EN_UPDATE 之前保存旧文本并将更改与新文本进行比较有效?
  • @JaroKollár:由于上面的代码只使用了SendMessage 调用,没有使用PostMessage,所以在代码中间不会重新绘制窗口。所以内部窗口滚动到第一行,然后更正一个,但用户看不到(如果你在调试器下执行它,窗口被冻结而不重新显示)。如果重要,我会在 EN_CHANGE 通知处理中执行此代码......如果您想知道哪些更改可以尝试在 EN_UPDATE(之前的通知)复制并与 EN_CHANGE(之后)存在的内容进行比较。但恕我直言,只使用完整副本。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-01-07
  • 2011-12-14
  • 2014-05-01
  • 1970-01-01
  • 2021-06-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多