我正在将基于控制台的程序改编为 GUI。
控制台程序读取文本文件并"编译"它。
我的 GUI 应用程序读取文本文件并显示在富文本框中。
我正在寻找一种将富文本框视为C++ std::istream
的方法。 这将允许我使用控制台程序中的代码而无需对其进行修改。
我搜索了网络和StackOverflow,没有找到任何将RichTextBox视为std::istream
的解决方案。
有没有人知道任何允许将RichTextBox视为std::istream
的Winforms库函数?
我的想法:
- 创建一个适配器以将富文本框视为流。
- 更改控制台程序以将"getline"函数传递给编译器部分,并具有两个 getline 函数(一个作为std::getline,另一个从 RichTextBox 获取一行)。
- 将富文本框内容写入文件,并将文件提供给编译器。
我在Win 7上使用Visual Studio 2010,使用".NET"4.0,使用C++(不要建议任何C#技术,因为我翻译不流利)。
在实际C++中,可以从 RTF 控件创建流缓冲区,如下所示:
class RTF_buf : public std::streambuf {
std::vector<char> buffer;
public:
RTF_buf(HWND ctrl) {
DWORD len = SendMessage(ctrl, WM_GETTEXTLENGTH, 0, 0);
buffer.resize(len+1);
SendMessageA(ctrl, WM_GETTEXT, len+1, (LPARAM)&buffer[0]);
setg(&buffer[0], &buffer[0], &buffer[len]);
}
};
请注意,这实际上并不限于 RTF 控件。仅举另一个示例,它也可以与普通的 EDIT 控件一起使用。
C++/CLI 为此增加了一些皱纹。首先,您正在处理 RichText Box 中的"宽"字符。其次,您(通常)不会从 HWND 开始 - 您必须通过其 Handle
属性从System.Windows.Forms.RichTextBox
中检索它。不幸的是,这将HWND
作为IntPtr
而不是HWND
返回,因此您必须添加强制转换才能将其转换为正确的类型。这使得代码有点丑陋,但没什么太可怕的:
#include <windows.h>
#include <streambuf>
#include <iostream>
#include <vector>
#include <algorithm>
#pragma comment(lib, "user32.lib")
using namespace System;
using namespace System::Windows::Forms;
class RTF_buf : public std::wstreambuf {
std::vector<wchar_t> buffer;
public:
RTF_buf(RichTextBox^ control) {
HWND ctrl = *reinterpret_cast<HWND *>(&control->Handle);
int len = SendMessage(ctrl, WM_GETTEXTLENGTH, 0, 0);
buffer.resize(len+1);
SendMessage(ctrl, WM_GETTEXT, len+1, (LPARAM)&buffer[0]);
setg(&buffer[0], &buffer[0], &buffer[len]);
}
};
我们可以创建一个缓冲区并像这样流式传输:
RTF_buf b(this->richTextBox1);
std::wistream in(&b);
最后,我们可以从流中读取数据并像处理任何其他(宽)流一样处理它们。例如:
wchar_t ch;
while (in >> ch)
// do something with ch
因此,C++/CLI 确实增加了任务的一点复杂性,但最终只是一点点 - 主要是获取控件句柄并将其转换为正确类型的一行。除此之外,缓冲区类的代码几乎不需要更改,并且实例化和使用它仅在我们使用宽字符而不是窄字符的范围内更改。
IOStreams 库的流的正确方法是实现流缓冲区,即从 std::streambuf
或 std::wstreambuf
派生(我不是 Windows 程序员,但我的理解是大多数代码以wchar_t
而不是char
的方式传输)并覆盖合适的 virtual
成员函数。假设你可以得到成堆的字符(可能全部在 bukl 中),你真正重载的只是underflow()
如果输入缓冲区耗尽,就会调用它。如果你可以在构造过程中获取所有字符,你也可以设置一个缓冲区。
后,可以使用指向流缓冲区的指针来初始化std::istream
。下面是一个简单的示例,它使用在构造函数中传递的内存 arean 作为其输入:
#include <iostream>
#include <streambuf>
class membuf
: std::streambuf {
public:
membuf(char* buffer, std::size_t size) {
this->setg(buffer, buffer, buffer + size);
}
};
int main() {
char input[] = "hello, world!n";
membuf sbuf(input, sizeof(input - 1));
std::istream in(&sbuf);
char buffer[100];
if (in.getline(buffer, sizeof(buffer)) {
std::cout << "read '" << buffer << "'n";
}
else {
std::cout << "ERROR: failed to read a line but Dietmar said...!?!n";
}
}