Winforms RichTextBox как istream

Я адаптирую консольную программу к GUI.

Консольная программа читает текстовый файл и «компилирует» его.

Мое приложение с графическим интерфейсом читает текстовый файл и отображается в RichTextBox.

Я ищу метод для обработки RichTextBox как C ++ std::istream, Это позволило бы мне использовать код из консольной программы без его изменения.

Я искал в Интернете и StackOverflow и не нашел каких-либо решений для обработки RichTextBox как std::istream,

Кто-нибудь знает какие-либо функции библиотеки Winforms, которые позволили бы рассматривать RichTextBox как std::istream?

Мои идеи:

  1. Создайте адаптер для обработки RichTextBox как потока.
  2. Измените консольную программу, чтобы передать функцию «getline»
    часть компилятора, и имеет две функции getline (одна как
    std :: getline, другой, чтобы получить строку из RichTextBox).
  3. Запишите содержимое RichTextBox в файл и передайте файл
    компилятор.

Я использую Visual Studio 2010 на Win 7, используя «.NET» 4.0, используя C ++ (не предлагайте никаких методов C #, так как я не бегу в переводе).

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 добавляет немного сложность задачи, но в конечном итоге лишь небольшая — в основном одна строка, чтобы получить дескриптор элемента управления и привести его к правильному типу. Кроме этого, код для буферного класса практически не нуждается в изменении, а его создание и использование изменяются только в той степени, в которой мы работаем с широкими символами вместо узких.

1

Другие решения

Правильный способ создания потока, подключаемого к библиотеке IOStreams, состоит в том, чтобы реализовать буфер потока, то есть извлечь из std::streambuf или же std::wstreambuf (Я не программист Windows, но я понимаю, что большинство кода путешествует с точки зрения wchar_t скорее, чем char) и переопределить подходящий virtual функции-члены. Предполагая, что вы можете получить символы в связках (возможно, все в букле), все, что вы действительно перегружаете, это 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

По вопросам рекламы [email protected]