Output Window

Abstract:

The TOutputWnd class was written originally as an IRC-style Output window. By this, I mean a window where the first line that is entered appears at the bottom, and the contents are scrolled upwards, ala mIRC. This is actually alot more difficult than writing text starting at the top of the window. But, forgetting IRC for the moment, this style also serves great as a general purpose output window. Whats more, it supports foreground and background colours together with optional wordwrapping. Text Selection has not, at the moment, been implemented.

Creating

The TOutputWnd class requires no special construction, so you can use the usual Create() or CreateEx() functions to create the window.

Displaying Text

Text is easy to display in the window, just call the AddLine( CString& ) method, which takes a reference to a CString. This line is then immediately added. Just like in mIRC, if the user has scrolled back up the window, the view is not updated, so the window will not 'jump' just because a line has been added (just try using the ICQ chat system to know how annoying it is for a window to jump when you're trying to read the rest of the text). The other two ways of getting text in to the Output window, is to use the Load( const char* ) function. This Load() routine is far from optimized (it was intended originally just so I could get some kind of text in to the window to test the various functions. The Output Window is *not* designed to load large text files, although handling large amounts of text isn't the problem). The third and final method of setting text is to call the SetBuffer( CStringArray& ), which sets the entire buffer from a string array. This, combined with the GetBuffer( CStringArray& ) function enables the programmer to save and restore the output window's buffer when necessary.

You may also clear the buffer at any time using the ClearBuffer() function.

Colour Codes

The output window uses embedded codes to denote foreground and background colours. the CONTROL_BYTE is #define'd in the header file (defaulting to '3'). The next 2 bytes following the control byte is the desired foreground colour index in the colour table ( 2 digits ), and optionally a comma and 2 further bytes denoting the background colour. The default colour table has colour constants defined to make explicit colour code setting easier. The following example adds a line with bright white foreground and blue background to the outputwindow:


   CString strLine = CONTROL_BYTE;
   strLine += _T("00,04HEY!");
   pOutputWnd->AddLine( strLine );

The Colour table

The output window uses a colour table of 16 colours to store the various colours that can be used as foreground and background. At any time you can pass an array of COLORREF's using the SetColourTable( COLORREF* ) function. The array should have 16 elements.

Font Support

You can set the font used by the output window to any font you wish, using the SetFont( LOGFONT& ) function. By default, the output window will use the default mono-spaced font. It is worth noting that the rendering code checks to see if a monospaced font is being used and if so, uses a different method of calculating text width to speed the process up.

Word Wrapping

Word wrapping can be switched on and off as necessary. When word-wrapping is off, you will see quite a speed increase in rendering, and also the addition of a horizontal scrollbar.

Public Methods

The following list describes the public methods that you can use to work with the output window:


	void SetWordWrap( bool bWrap );
	bool GetWordWrap() const;
	void SetDefaultTextColour( UINT nIndex );
	UINT GetDefaultTextColour() const;
	void SetBuffer( CStringArray& );
	bool GetBuffer( CStringArray& ) const;
	void AddLine( CString& strLine );
	void SetFont( LOGFONT& lf );
	bool GetFont( LOGFONT& lf ) const;
	void SetBackColour( COLORREF col );
	COLORREF GetBackColour() const;
	void SetColourTable( COLORREF* pColTable );
	void SetHead( int nHead );
	int GetHead() const;
	void SetMaxLines( UINT nMaxLines );
	UINT GetMaxLines() const;
	UINT GetMaxViewableLines();
	int GetLineCount() const;
	CString GetLine( int l ) const ;
	void ClearBuffer();
	void Load( const char* lpFilename );

Download source - 8.7 KB



Comments

  • Last post messed up (Sample project would be nice...)

    Posted by kanga321 on 11/14/2008 02:25pm

    A sample project is most definately needed in order for us newbies to MFC to figure out how to create the window on a modeless or modal dialog, on a child window, etc. It's not helpful to say "you can use Create() or CreateEx() to create the window". There isn't enough information on the net to describe this in more detail. I got as far as this: CRect rect; TOutputWnd* pOut = new TOutputWnd; pOut->Create("test","test",WS_VISIBLE,CRect(10,10,100,100),this,IDD_CONNECT,NULL); pOut->ShowWindow(SW_SHOW); without error, but I'm not sure what the lpszClassname is supposed to be or anything and the window will still not show on the dialog =/. Surely SOMEONE has a working example of this by now??

    Reply
  • Text Selection Available...?

    Posted by Semperhoo on 07/08/2004 01:06pm

    Has anyone figured out a way to enable text selection with this code? It's a nice architecture but text selection is missing. I haven't had the necessary time to figure out a way to do it but I thought someone else might have implemented it by now.

    Reply
  • COOL,but it does not work

    Posted by Legacy on 12/28/2001 12:00am

    Originally posted by: whj

    can you tell me why?

    Reply
  • OnCreate() does not always do it...

    Posted by Legacy on 08/21/2001 12:00am

    Originally posted by: Kevin Pinkerton

    If you want to replace a CStatic window or any other control window that you have created via the class wizard and allowed the DDX to create a handle to then you will not get a call to OnCreate(). However there is an easy fix. Simply add a PreSubclassWindow() and put the important stuff from OnCreate() in there. That worked for me.

    Reply
  • Anyone can pass me a sample

    Posted by Legacy on 07/28/2001 12:00am

    Originally posted by: Roland

    Anyone has a simple sample with all the mentioned error correction added in??

    thanks.

    Reply
  • CopyToClipboard function

    Posted by Legacy on 03/29/2001 12:00am

    Originally posted by: Tim Kosse

    This function copies all text from the Window to the clipboard. The text is copied both in Rich Text Format as well as in plain text. Tested with Notepad and Wordpad.
    
    

    void COutputWnd::CopyToClipboard()
    {
    if (!GetLineCount())
    return;
    OpenClipboard();
    EmptyClipboard();
    UINT format=RegisterClipboardFormat("Rich Text Format");
    HGLOBAL hData;
    CString str;
    str="{\\rtf1\\ansi";
    str+="{\\fonttbl{\\f0\\fnil "+CString(m_lfFont.lfFaceName)+";}}";
    str+="{\\colortbl ;";
    for (int i=0;i<16;i++)
    {
    CString tmp;
    tmp.Format("\\red%d\\green%d\\blue%d;",GetRValue(m_ColTable[i]),GetGValue(m_ColTable[i]),GetBValue(m_ColTable[i]));
    str+=tmp;
    }
    str+="}";

    int pointsize=(-m_lfFont.lfHeight*72/ GetDeviceCaps(GetDC()->GetSafeHdc(), LOGPIXELSY))*2;
    CString tmp;
    tmp.Format("%d",pointsize);
    str+="\\fs"+tmp;
    CString str2;
    for (i=0;i<GetLineCount();i++)
    {
    CString line=GetLine(i);
    CString line2=line;
    line.Replace("\\","\\\\");
    line.Replace("{","\\{");
    line.Replace("}","\\}");
    int res=line.Find(CONTROL_BYTE);
    if (res!=-1)
    {
    int color=atoi(line.Mid(res+1,2));
    CString tmp;
    tmp.Format("%d",color+1);
    line2.Delete(res,6);
    line.Delete(res,6);
    line.Insert(res,"\\cf"+tmp);
    }
    line+="\\par";
    str+=line;
    str2+=line2+"\r\n";
    }
    str+="} ";

    hData = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE,str.GetLength()+1);
    LPVOID pData;
    pData=GlobalLock(hData);
    strcpy((LPSTR)pData,str);
    GlobalUnlock(hData);
    SetClipboardData(format,hData);

    hData = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE,str2.GetLength()+1);
    pData=GlobalLock(hData);
    strcpy((LPSTR)pData,str2);
    GlobalUnlock(hData);
    SetClipboardData(CF_TEXT,hData);
    CloseClipboard();
    }

    Reply
  • Useful enhancement (with code)

    Posted by Legacy on 02/15/2001 12:00am

    Originally posted by: Tim Kosse

    I've noticed that the output always starts on the lowest line of the Window, so if the window can hold 10 lines and only 5 lines were added, only the bottom part of the window is used.
    Also, if there are several lines, so that scrolling is enabled, you can scroll all the way up so that again only one line can be seen in the window, leaving large portions of the window unused.
    To compensat this, I updated the OnPaint, UpdateVScroll and OnVScroll functions.

    OnPaint:
    Put this directly before the do-while loop:
    //Ensure that as much space as possible is used
    if (GetLineCount()<GetMaxViewableLines())
    {
    nMasterY -= (GetMaxViewableLines()-GetLineCount())*m_nFontHeight;
    }

    OnUpdateVScroll:
    void TOutputWnd::UpdateVScroll()
    {
    SetScrollRange( SB_VERT, GetMaxViewableLines()-1, GetLineCount() - 1 );
    };


    OnVScroll:
    ...
    case SB_TOP:
    SetHead(GetMaxViewableLines()-1);
    break;
    ...
    case SB_LINEUP:
    if( m_nHead > (GetMaxViewableLines()-1) )
    ...

    This all makes the OutputWindow behave more like the Statuswindow of the VisualStudio IDE.

    • Another enhancement

      Posted by Semperhoo on 07/08/2004 12:56pm

      Mr. Kosse's codes is indeed very handy when using this class.  
      I came across this architecture while working on a piece of software 
      that was written by someone else.  The previous author used this 
      Output Window class for creating a Logger Window similar to one 
      seen in MSVS IDE but all logging began on the bottom of the logger 
      window (as mentioned).
      
      The code provided does fix this...with one exception.  In my 
      application, the logging window is adjustable in size.  Therefore, if 
      only a few lines of text are written to the output window and the window 
      size is readjusted, the OnPaint() function does not correctly fill in 
      the bottom portion of the logging window.  Instead of filling it in with 
      the nice white window background it fills it in with the toolbar color. 
       Fixing this is easy and requires only a slight extra mod to the 
      OnPaint() command:
      
      Old Code:
      // Pad out any remaining area...
      
      
      		if( nMasterY >= 0 )
      		{
      			CRect solidRc = clientRc;
      			solidRc.bottom = nMasterY;
                              dc.FillSolidRect(          &solidRc, m_BackCol );
                         };
      
      
      New Code:
      // Pad out any remaining area...
      
      
      		if( nMasterY >= 0 )
      		{
      			CRect solidRc = clientRc;
      			solidRc.bottom = nMasterY;
      			CRect fillRc = clientRc;
                              fillRc.top = clientRc.top + nMasterY + (GetLineCount()*m_nFontHeight);
      			dc.FillSolidRect( &solidRc, m_BackCol );
      			dc.FillSolidRect( &fillRc, m_BackCol );
      			
      		};
      
      
      The new fillRc object fills in the portion of the Output Window below the 
      portion where the text is logged.
      
      Note:  The above code will only work with Mr. Kosse's mod in place.
      
      Good luck!

      Reply
    Reply
  • Sample Project?

    Posted by Legacy on 06/20/1999 12:00am

    Originally posted by: Bob

    Just wondering if anyone can send me a sample project of
    this to see how to implement it or at least maybe give some
    hints etc. Thanks.

    Bob - honor@geocities.com

    Reply
  • GDI Leak

    Posted by Legacy on 05/17/1999 12:00am

    Originally posted by: Fix

    The tool is in certain situations wery useful, however there is a GDI leak in it.
    The m_pFont member is always deleted as a C++ object (delete m_pFont) but never deleted as a GDI resource (m_pFont->DeleteObject())

    Reply
  • The type of the member m_nOffset should be signed integer.

    Posted by Legacy on 03/18/1999 12:00am

    Originally posted by: sesame

    There are some code like this In OtuputWnd.cpp 1086 line,
    
    

    m_nXOffset -= m_nAvgCharWidth;
    if( m_nXOffset < 0 ) m_nXOffset = 0;

    if m_nXoffset is UINT,it don't work right.

    regards
    sesame

    Reply
  • Loading, Please Wait ...

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • IBM Worklight is a mobile application development platform that lets you extend your business to mobile devices. It is designed to provide an open, comprehensive platform to build, run and manage HTML5, hybrid and native mobile apps.

  • Live Event Date: November 13, 2014 @ 2:00 p.m. ET / 11:00 a.m. PT APIs can be a great source of competitive advantage. The practice of exposing backend services as APIs has become pervasive, however their use varies widely across companies and industries. Some companies leverage APIs to create internal, operational and development efficiencies, while others use them to drive ancillary revenue channels. Many companies successfully support both public and private programs from the same API by varying levels …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds