Sydius
Sydius

Reputation: 14257

How to use a RichEdit control like a console with the Win32 API?

I have a RichEdit control in my simple application that I wish to simulate a console-like display with. I want to be able to have a buffer of x number of lines (say, 300) and whenever a line is added, I would like to also remove the oldest (top) line if the new line exceeded the threshold x. I would also like it to automatically scroll to the bottom to display the newest line when added.

I've been using SetWindowText with some success, however it occurs to me that there is likely a more efficient method of appending text to the end and removing text from the beginning without having to replace all of it every time. Is this true, and, if so, how might I go about it?

Also, how might I make it automatically scroll to the bottom of the window when new text is added?

This is using the Win32 API from C, and I'm not using the MFC version of RichEdit (just using the vanilla Win32 API on XP and Vista).

Upvotes: 2

Views: 2889

Answers (2)

Todor Todorov
Todor Todorov

Reputation: 11

I send you some methods of sample class cConsole:

class cConsole {
private:
    //-------------------
    int lines;
    int max_lines;             // Init it with your choise ( 300 )
    //-------------------
    char* buf;
    int buf_size;
    //-------------------
    int CheckMemory( int size );
    void NewLine( int new_lines );
    void InternalPrint( char* msg, int size );

public:
    HWND hWin;
    void Print( char* msg );    // Add text data through this methods
    void Print( char* msg, int size );
    cConsole( );
    ~cConsole( );
};

int cConsole::CheckMemory( int size ) {
int rv = 1;
if( size + 16 >= buf_size ) {
    int new_buf_size = size + 1024;
    char* new_buf = ( char* )realloc( buf, new_buf_size );
    if( new_buf != NULL ) {
        buf = new_buf;
        buf_size = new_buf_size;
    } else {
        rv = 0;
    }
}
return rv;
}

void cConsole::NewLine( int new_lines ) {
int rem_lines = ( new_lines + lines + 1 ) - max_lines;
if( rem_lines <= 0 ) {
    lines += new_lines;
} else {
    int sel = SendMessage( hWin, EM_LINEINDEX, rem_lines, 0 );

    SendMessage( hWin, EM_SETSEL, 0, (LPARAM)sel );
    SendMessage( hWin, EM_REPLACESEL, FALSE, (LPARAM)"" );
    SendMessage( hWin, WM_VSCROLL, SB_BOTTOM, NULL );

    lines = max_lines - 1;
}
}

void cConsole::Print( char* msg ) { InternalPrint( msg, -1 ); }
void cConsole::Print( char* msg, int size ) { if( size < 0 ) size = 0; InternalPrint( msg, size ); }

void cConsole::InternalPrint( char* msg, int size ) {
int s, t = 0;
int new_lines = 0;
char* tb;

// msg only mode
if( size == -1 ) size = 0x7fffffff;

if( msg != NULL && size && CheckMemory( t ) ) {
    for( s = 0; msg[ s ] && ( s < size ); s++ ) {
        if( msg[ s ] == '\r' ) continue;
        if( !CheckMemory( t ) ) break;
        if( msg[ s ] == '\n' ) {
            ++new_lines;
            buf[ t++ ] = '\r';
        }
        buf[ t++ ] = msg[ s ];
    }
    buf[ t ] = '\0';
}
if( t && msg != NULL ) {
    tb = buf;
} else {
    ++new_lines;
    tb = "\r\n";
}

SendMessage( hWin, EM_SETSEL, (WPARAM)-2, (LPARAM)-1 );
SendMessage( hWin, EM_REPLACESEL, FALSE, (LPARAM)tb );
SendMessage( hWin, WM_VSCROLL, SB_BOTTOM, NULL );

if( new_lines ) NewLine( new_lines );
}

Built your own class and check this!

Upvotes: 1

Jerry Coffin
Jerry Coffin

Reputation: 490108

To add text, you set the selection to the end of the text (EM_SETSEL), then replace the selection with the new text (EM_REPLACESEL).

To scroll to the bottom, you can send it a WM_VSCROLL with SB_BOTTOM.

Upvotes: 3

Related Questions