将RichTextBox Winform为istream

时间:2013-12-16 21:47:57

标签: c++ winforms richtextbox istream

我正在调整基于控制台的程序到GUI。

控制台程序读取文本文件并“编译”它。

我的GUI应用程序读取文本文件并显示在RichTextBox中。

我正在寻找一种方法将RichTextBox视为C ++ std::istream。这将允许我使用控制台程序中的代码而无需修改它。

我搜索了网络和StackOverflow,并没有找到任何将RichTextBox视为std::istream的解决方案。

是否有人知道任何允许将RichTextBox视为std::istream的Winforms库函数?

我的想法:

  1. 创建适配器以将RichTextBox视为流。
  2. 更改控制台程序以将“getline”函数传递给 编译器部分,并有两个getline函数(一个作为 std :: getline,另一个从RichTextBox获取一行。)
  3. 将RichTextBox内容写入文件并将文件提供给 编译器。
  4. 我在Win 7上使用Visual Studio 2010使用“.NET”4.0,使用C ++ (不建议任何C#技术,因为我不能流利地翻译)< / em>的。

2 个答案:

答案 0 :(得分:1)

创建插入IOStreams库的流的正确方法是实现流缓冲区,即从std::streambufstd::wstreambuf派生(我不是Windows程序员,但我的理解是大多数代码都以wchar_t而不是char的形式传播,并覆盖合适的virtual成员函数。假设你可以获得一串中的字符(可能全部都是bukl),那么你真正重载的是underflow(),如果输入缓冲区已用尽,则调用它。如果你可以在构造过程中获得所有字符,你也可以设置一个缓冲区。

获得流缓冲区后,可以使用指向流缓冲区的指针初始化std::istream。这是一个简单的例子,它使用在构造函数中传递的内存作为其输入:

#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";
    }
}

答案 1 :(得分:1)

在真正的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为此添加了一些皱纹。首先,您正在处理RichTextBox中的“宽”字符。其次,您不会(通常)以HWND开头 - 您必须通过System.Windows.Forms.RichTextBox属性从Handle检索它。不幸的是,这会将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确实为任务添加了复杂性,但最终只有一点 - 主要是获得控件句柄的一行,并将其转换为正确的类型。除此之外,缓冲类的代码几乎不需要改变,并且实例化和使用它只会改变我们使用宽字符而不是缩小的范围。