Я адаптирую консольную программу к GUI.
Консольная программа читает текстовый файл и «компилирует» его.
Мое приложение с графическим интерфейсом читает текстовый файл и отображается в RichTextBox.
Я ищу метод для обработки RichTextBox как C ++ std::istream
, Это позволило бы мне использовать код из консольной программы без его изменения.
Я искал в Интернете и StackOverflow и не нашел каких-либо решений для обработки RichTextBox как std::istream
,
Кто-нибудь знает какие-либо функции библиотеки Winforms, которые позволили бы рассматривать RichTextBox как std::istream
?
Мои идеи:
Я использую Visual Studio 2010 на Win 7, используя «.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 добавляет несколько морщин к этому. Прежде всего, вы имеете дело с «широкими» символами в 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 добавляет немного сложность задачи, но в конечном итоге лишь небольшая — в основном одна строка, чтобы получить дескриптор элемента управления и привести его к правильному типу. Кроме этого, код для буферного класса практически не нуждается в изменении, а его создание и использование изменяются только в той степени, в которой мы работаем с широкими символами вместо узких.
Правильный способ создания потока, подключаемого к библиотеке 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";
}
}