2010-02-05 85 views
2

我有一个RichEdit控制在我简单的应用程序,我希望模拟一个控制台般的显示。我想能够有一个x行数(例如300)的缓冲区,并且每当添加一行时,如果新行超过阈值x,我还想删除最早的行(顶行)。我也希望它自动滚动到底部以显示添加的最新行。如何像使用Win32 API一样使用RichEdit控件?

我一直在使用SetWindowText取得了一些成功,但是我发现有一种更有效的方法可以将文本附加到最后并从头开始删除文本,而无需每次都替换所有文本。这是真的吗?如果是这样,我该怎么办?

另外,如何在添加新文本时自动滚动到窗口的底部?

这是使用C的Win32 API,我没有使用MFC版本的RichEdit(只使用XP和Vista上的vanilla Win32 API)。

回答

3

要添加文本,请将所选内容设置为文本的末尾(EM_SETSEL),然后将所选内容替换为新文本(EM_​​REPLACESEL)。

要滚动到底部,可以使用SB_BOTTOM向其发送一个WM_VSCROLL。

+1

我使用了-1作为'EM_SETSEL'的开始和结束位置来获得结束,它似乎已经工作。它是否正确?另外,我如何有效地找到第一个换行符来删除RichEdit控件中的第一行? – Sydius 2010-02-06 00:19:39

+0

是的,我通常使用-1作为起点和终点。我相信你应该能够用EM_FINDTEXT找到一个换行符(你可能需要查找“\ r \ n”),尽管我想我必须检查确定。 – 2010-02-06 00:23:52

1

我送你样品类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); 
} 

内置自己的类,并检查该!