Professional UI Solutions
Site Map   /  Register
 
 

Forum

Please Log In to post a new message or reply to an existing one. If you are not registered, please register.

NOTE: Some forums may be read-only if you are not currently subscribed to our technical support services.

Forums » Prof-UIS Tech Support » Various persistent problems in the grid control Collapse All
Subject Author Date
Rachik Elmaraghy Apr 29, 2009 - 9:07 AM

The problems listed here apply to version 2.84 and 2.85 at different degrees.

1 - Scroll Bars

The scroll bars behave pretty badly when using the __ESIS_STH_ITEM flag, when the column widths are not constant. This can be easily reproduced in the SimpleGrid sample by resizing a couple of columns to make them wide compared to others. The scroll bar even overlaps the scroll bar buttons in some situations.


2 - Cell edition

When a cell is in edit state and I press the right arrow key, the cell to the right is automatically highlighted which is the desired behavior. However, the newly highlighted cell is automatically put in edition state with the content of the cell not selected. This is very confusing and also different than any spreadsheet programs like excel. When the arrow keys are pressed, the system automatically calls EditCell() (see Ln.25059 in ExtGridWnd.cpp) for the newly highlighted cell. I think there should be an option to prevent this awkward behavior.


3 - Multi-line text

There seem to be a confusion between multi line texts and word break. I would like to be able to do multi line texts where I would provide the \n myself without automatic word breaking. I can acheive this by overriding OnQueryDrawTextFlag but the problem is that although the text is displayed fine, MeasureCell does not call OnQueryDrawTextFlag so the BestFit function calculates the text size with different flags than the ones used for drawing. Would it be possible to either call OnQueryDrawTextFlag from MeasureCell or provide distinct options for multi line texts and word break? I undertand that multi line and word break often come together when drawing text but it is not the case when drawing lists or column headers.


4 - Printing

Although printing is better in version 2.85 than in version 2.84, it is still not working very well so I needed to rework it from scratch. When doing so I realized that in printing mode, the DT_END_ELLIPSIS flag is forced off and the DT_NOCLIP flag is forced on. I would really like to know why? I want to print the table as is (without adjusting column widths) without cell contents overlapping each others.

Note that I could solve issues 2, 3 and 4 by modifying the Prof-uis source code. Issue 1 is a lot more complicated and the impact of modifications are not obvious to me. I would prefer not to modify the sources as this prevents upgrading to newer versions when they are released.


Thanks,
David

David Langis Apr 30, 2009 - 1:13 PM

Some other problems I faced this morning,

5 - Resizing
In the simple grid sample, if I resize a column to zero width, I can still bring it back by resizing it back to a non zero width. However, if I resize all columns to zero width, then the resizing cursors are lost and I am unable to resize any column back to a non zero width.

6 - BestFit
I discovered this problem when I fell on a small issue with BestFitColumn. If I have no rows in the table, BestFitColumn does nothing if the bVisibleRowsOnly flag is set.


Thanks for the previous answers, I appreciated the short delays very much.

Regards,
David

Technical Support May 2, 2009 - 1:02 PM

The resizing issue is fixed in Prof-UIS 2.85. Thank you. Please drop us an e-mail to the support mail box so we will provide you with FTP update download.

The bDoBestFitByVisibleRowRangeOnly parameter of the CExtGridWnd::BestFitColumn() method is ignored if the bDoBestFitByInnerCells parameter is false. If your grid have no rows, then the only best fit computation available is to measure outer header rows. This means the bDoBestFitByOuterCells parameter should be true. In other case there is nothing to measure. We recommend you to use the CExtGridWnd::BestFitColumn() method with default values in the bDoBestFitByOuterCells and bDoBestFitByInnerCells parameters (both are true) and use the true flag in the bDoBestFitByVisibleRowRangeOnly parameter only if the number of rows is very large.

David Langis May 4, 2009 - 7:04 AM

I am currently using version 2.85, I will check it more closely and come back on it

David Langis May 4, 2009 - 12:36 PM

It works well with the latest 2.85 version, thanks.

Technical Support Apr 30, 2009 - 11:08 AM

This message is related to the issue 4 only. It’s not an issue. The printed/previewed content and screen surface of the grid window are generated differently. Each printed/previewed grid cell uses the width and height which are greater or equal to the measured grid cell sizes. The printed/previewed grid cells never become partially displayed. The text ellipsis effect is never needed in the printed/previewed grid cells. This is the design of the print preview subsystem, not an issue. You can measure and draw your grid cells differently in the screen painting mode and in the print preview mode. All the painting and measuring virtual methods of the CExtGridCell class have the dwHelperPaintFlags parameter containing set of the __EGCPF_*** flags. Some of these flags are related to this conversation:

// printer/print-preview output rendering (with or without metafile)
#define __EGCPF_PRINTER                             0x00000400L
#define __EGCPF_PRINT_PREVIEW                       0x00000800L
#define __EGCPF_PRINTING_TARGET_MASK                (__EGCPF_PRINTER|__EGCPF_PRINT_PREVIEW)
// rendering DC is metafile based
#define __EGCPF_METAFILE                            0x00001000L
#define __EGCPF_SIMPLIFIED_RENDERING_TARGET         (__EGCPF_PRINTING_TARGET_MASK|__EGCPF_METAFILE)

So, if the painting/measuring methods of the CExtGridCell class are invoked with any of the __EGCPF_PRINTING_TARGET_MASK flags, then the cell is printed or previewed. Otherwise it’s painted somewhere inside the grid’s client area, in the CExtContentExpandWnd popup window displaying partially visible grid cell or in the memory device context used during handling of the WM_PRINT or WM_PRINTCLIENT standard messages.

Technical Support Apr 30, 2009 - 10:51 AM

About issue 3: it’s fixed in Prof-UIS 2.85. Here is the updated CExtGridCell::OnMeasureTextSize() virtual method:

CSize CExtGridCell::OnMeasureTextSize(
	const CExtGridWnd & wndGrid,
	CDC & dc,
	LONG nVisibleColNo,
	LONG nVisibleRowNo,
	LONG nColNo,
	LONG nRowNo,
	INT nColType,
	INT nRowType,
	const RECT & rcCellExtra,
	const RECT & rcCell,
	const RECT & rcCellText,
	DWORD dwAreaFlags
	) const
{
	ASSERT_VALID( this );
	ASSERT_VALID( (&wndGrid) );
	ASSERT( dc.GetSafeHdc() != NULL );
	rcCellExtra; rcCell; rcCellText;
HFONT hOldFont = NULL;
bool bFontMustBeDestroyed = false;
HFONT hCellFont = OnQueryCellFont( wndGrid, nVisibleColNo, nVisibleRowNo, nColNo, nRowNo, nColType, nRowType, dwAreaFlags, bFontMustBeDestroyed );
	if( hCellFont != NULL )
		hOldFont = (HFONT)::SelectObject( dc, hCellFont );
	else
		hOldFont = (HFONT)::SelectObject( dc, wndGrid.OnSiwGetDefaultFont().GetSafeHandle() );
CRect rcCellTextMeasured( 0, 0, 0, 0 );
UINT nDrawTextFlags = DT_LEFT|DT_TOP|DT_CALCRECT;
DWORD dwCellStyleEx = GetStyleEx();
	if( (dwCellStyleEx&__EGCS_EX_WRAP_TEXT) != 0L )
	{
		nDrawTextFlags |= DT_WORDBREAK;
		INT nWidth = wndGrid.OnSiwQueryItemExtentH( nColNo );
		INT nHeight = wndGrid.OnSiwQueryItemExtentV( nRowNo );
		rcCellTextMeasured = CRect(0,0,nWidth,nHeight);
	}
	else
		nDrawTextFlags |= DT_SINGLELINE;
	OnAdjustMeasureTextFlags( nDrawTextFlags, nVisibleColNo, nVisibleRowNo, nColNo, nRowNo, nColType, nRowType, dwAreaFlags );
	ASSERT( ( nDrawTextFlags & DT_CALCRECT ) != 0 );
bool bTextIsMeasured = false;
DWORD dwCellStyle = GetStyle();
	if(		( dwAreaFlags & __EGBWA_OUTER_CELLS ) != 0
		&&	(dwCellStyle&__EGCS_HDR_ROW_COLUMN_NUMBER) != 0L
		&&	( nColType != 0 || nRowType != 0 )
		)
	{ // if draw row/column number text
		CExtSafeString strText;
		OnFormatHeaderNumberString( strText, wndGrid, nVisibleColNo, nVisibleRowNo, nColNo, nRowNo, nColType, nRowType, dwAreaFlags );
		if( ! strText.IsEmpty() )
		{
			dc.DrawText( LPCTSTR( strText ), strText.GetLength(), (RECT *)&rcCellTextMeasured, nDrawTextFlags );
			bTextIsMeasured = true;
		} // if( ! strText.IsEmpty() )
	} // if draw row/column number text
	else
	{ // if draw cell default text
		LPCTSTR strTextBuffer = LPCTSTR( GetTextBuffer() );
		int nTextBufferLen = ( strTextBuffer != NULL ) ? int(_tcslen(strTextBuffer)) : int(0);
		if( nTextBufferLen > 0 )
		{
			dc.DrawText( strTextBuffer, nTextBufferLen, (RECT *)&rcCellTextMeasured, nDrawTextFlags );
			bTextIsMeasured = true;
		} // if( nTextBufferLen > 0 )
		else
		{
			CExtSafeString strCopy;
			TextGet( strCopy );
			if( ! strCopy.IsEmpty() )
			{
				dc.DrawText( LPCTSTR( strCopy ), strCopy.GetLength(), (RECT *)&rcCellTextMeasured, nDrawTextFlags );
				bTextIsMeasured = true;
			} // if( ! strCopy.IsEmpty() )
		} // else from if( nTextBufferLen > 0 )
	} // if draw cell default text
	if( !bTextIsMeasured )
		rcCellTextMeasured = CRect( 0, 0, 0, 0 );
CRect rcCellTextMeasured2( 0, 0, 0, 0 );
static CExtSafeString g_sTestText( _T("AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789;[]{}\\/=+-_*&ˆ%$#@!~") );
	dc.DrawText(
		LPCTSTR( g_sTestText ),
		g_sTestText.GetLength(),
		(RECT *)&rcCellTextMeasured2,
		nDrawTextFlags
		);
INT nAlignHeight = rcCellTextMeasured2.Height();
	if( hOldFont != NULL )
		::SelectObject( dc, hOldFont );
	if(		bFontMustBeDestroyed 
		&&	hCellFont != NULL 
		)
		::DeleteObject( hCellFont );
CSize _sizeText = rcCellTextMeasured.Size();
 	_sizeText.cy = max( _sizeText.cy, nAlignHeight );
	return _sizeText;
}

It does not use the CExtGridCell::OnQueryDrawTextFlags() virtual method. But we defined the new similar method for providing the DT_*** flags for text measuring:

 	virtual void OnAdjustMeasureTextFlags(
		UINT & nDrawTextFlags,
		LONG nVisibleColNo,
		LONG nVisibleRowNo,
		LONG nColNo,
		LONG nRowNo,
		INT nColType,
		INT nRowType,
		DWORD dwAreaFlags
		) const;

 void CExtGridCell::OnAdjustMeasureTextFlags(
	UINT & nDrawTextFlags,
	LONG nVisibleColNo,
	LONG nVisibleRowNo,
	LONG nColNo,
	LONG nRowNo,
	INT nColType,
	INT nRowType,
	DWORD dwAreaFlags
	) const
{
	ASSERT_VALID( this );
	nDrawTextFlags; nVisibleColNo; nVisibleRowNo; nColNo; nRowNo; nColType; nRowType; dwAreaFlags;
}


David Langis Apr 30, 2009 - 12:24 PM

It works partially, the call to OnAdjustMeasureTextFlags is missing in MeasureCell. Adding it to MeasureCell makes things work well.

Thanks
David

Technical Support May 2, 2009 - 6:36 AM

Thank you for this comment. We added invocation of the CExtGridCell::OnAdjustMeasureTextFlags() virtual method into the CExtGridCell::MeasureCell() virtual method:

CSize CExtGridCell::MeasureCell(
	CExtGridWnd * pWndGrid, // can be NULL
	CDC & dcMeasure,
	LONG nVisibleColNo,
	LONG nVisibleRowNo,
	LONG nColNo,
	LONG nRowNo,
	INT nColType,
	INT nRowType
	) const
{
	ASSERT_VALID( this );
	ASSERT( dcMeasure.GetSafeHdc() != NULL );
	if( pWndGrid->GetSafeHwnd() == NULL )
		pWndGrid = NULL;

DWORD dwCellStyle = GetStyle();
DWORD dwCellStyleEx = GetStyleEx();

	// MEASURE ICON SIZE
CSize _sizeIcon = IconGetSize();
	if( _sizeIcon.cx > 0 )
		_sizeIcon.cx += 2;

	// MEASURE EXISTING TEXT SIZE
UINT nDrawTextFlags = DT_LEFT|DT_TOP|DT_CALCRECT;
CRect rcCellTextMeasured( 0, 0, 0, 0 );
	if( pWndGrid != NULL && (dwCellStyleEx&__EGCS_EX_WRAP_TEXT) != 0L )
	{
		nDrawTextFlags |= DT_WORDBREAK;
		INT nWidth = pWndGrid->OnSiwQueryItemExtentH( nColNo );
		INT nHeight = 0; //pWndGrid->OnSiwQueryItemExtentV( nRowNo );
		rcCellTextMeasured = CRect(0,0,nWidth,nHeight);
	}
	else
		nDrawTextFlags |= DT_SINGLELINE;
LPCTSTR strTextBuffer = LPCTSTR( GetTextBuffer() );
int nTextBufferLen = 
		( strTextBuffer != NULL )
			? int(_tcslen(strTextBuffer))
			: int(0);
HGDIOBJ hOldFont = NULL;
HFONT hCellFont = NULL;
bool bFontMustBeDestroyed = false;
	if( pWndGrid != NULL )
	{
		hCellFont = OnQueryCellFont( *pWndGrid, nVisibleColNo, nVisibleRowNo, nColNo, nRowNo, nColType, nRowType, 0, bFontMustBeDestroyed, 0 );
		if( hCellFont == NULL )
		{
			bFontMustBeDestroyed = false;
			hCellFont = (HFONT)pWndGrid->OnSiwGetDefaultFont().GetSafeHandle();
		}
		if( hCellFont != NULL )
			hOldFont = ::SelectObject( dcMeasure, (HGDIOBJ)hCellFont );
	}
	OnAdjustMeasureTextFlags( nDrawTextFlags, nVisibleColNo, nVisibleRowNo, nColNo, nRowNo, nColType, nRowType, 0 );
bool bTextIsMeasured = false;
	if( nTextBufferLen > 0 )
	{
		dcMeasure.DrawText(
			strTextBuffer,
			nTextBufferLen,
			(RECT *)&rcCellTextMeasured,
			nDrawTextFlags
			);
		bTextIsMeasured = true;
	} // if( nTextBufferLen > 0 )
	else
	{
		CExtSafeString strCopy;
		TextGet( strCopy );
		if( ! strCopy.IsEmpty() )
		{
			dcMeasure.DrawText(
				LPCTSTR( strCopy ),
				strCopy.GetLength(),
				(RECT *)&rcCellTextMeasured,
				nDrawTextFlags
				);
			bTextIsMeasured = true;
		} // if( ! strCopy.IsEmpty() )
	} // else from if( nTextBufferLen > 0 )
	if( !bTextIsMeasured )
		rcCellTextMeasured = CRect( 0, 0, 0, 0 );
CRect rcCellTextMeasured2( 0, 0, 0, 0 );
static CExtSafeString g_sTestText( _T("AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789;[]{}\\/=+-_*&ˆ%$#@!~") );
	dcMeasure.DrawText(
		LPCTSTR( g_sTestText ),
		g_sTestText.GetLength(),
		(RECT *)&rcCellTextMeasured2,
		nDrawTextFlags
		);
	if( pWndGrid != NULL && hCellFont != NULL )
		::SelectObject( dcMeasure, hOldFont );
	if( bFontMustBeDestroyed && hCellFont != NULL )
		::DeleteObject( hCellFont );

INT nAlignHeight = rcCellTextMeasured2.Height();
CSize _sizeText = rcCellTextMeasured.Size();
 	_sizeText.cy = max( _sizeText.cy, nAlignHeight );

	if( _sizeText.cx > 0 )
		_sizeText.cx += 4;
	if( _sizeText.cy > 0 )
		_sizeText.cy += 4;

	if( pWndGrid != NULL )
	{
		CRect rcTextAreaMargins = OnQueryTextAreaMargins( *pWndGrid, dcMeasure, nVisibleColNo, nVisibleRowNo, nColNo, nRowNo, nColType, nRowType, 0, 0 );
		_sizeText.cx += rcTextAreaMargins.left + rcTextAreaMargins.right;
		_sizeText.cy += rcTextAreaMargins.top + rcTextAreaMargins.bottom;
	}
	else
	{
		if( _sizeIcon.cx > 0 )
			_sizeText.cx += 4;
	}
	// MEASURE BUTTONS SIZE
CSize _sizeAllButtons( 0, 0 );
	if(		(dwCellStyle&(__EGCS_BUTTON_ELLIPSIS|__EGCS_BUTTON_DROPDOWN|__EGCS_BUTTON_UPDOWN)) != 0
		&&	(	pWndGrid == NULL
			||	(pWndGrid->BseGetStyle()&__EGWS_BSE_BUTTONS_PERSISTENT) != 0
			)
		)
	{
		CSize _sizeOneButton(
				::GetSystemMetrics( SM_CXVSCROLL ),
				::GetSystemMetrics( SM_CYHSCROLL )
				);
		if( (dwCellStyle&__EGCS_BUTTON_ELLIPSIS) != 0 )
		{
			_sizeAllButtons.cx += _sizeOneButton.cx;
			_sizeAllButtons.cy = max( _sizeAllButtons.cy, _sizeOneButton.cx );
		}
		if( (dwCellStyle&__EGCS_BUTTON_DROPDOWN) != 0 )
		{
			_sizeAllButtons.cx += _sizeOneButton.cx;
			_sizeAllButtons.cy = max( _sizeAllButtons.cy, _sizeOneButton.cx );
		}
		if( (dwCellStyle&__EGCS_BUTTON_UPDOWN) != 0 )
		{
			_sizeAllButtons.cx += _sizeOneButton.cx;
			_sizeAllButtons.cy = max( _sizeAllButtons.cy, _sizeOneButton.cx );
		}
	}

	// MEASURE CHECK/RADIO SIZE
CSize _sizeCheck( 0, 0 );
	if( (dwCellStyle&__EGCS_CHK_MASK) != 0 )
	{
		if( pWndGrid != NULL )
			_sizeCheck =
				OnCalcCheckSize(
					false, false, ( (dwCellStyle&__EGCS_READ_ONLY) == 0 ) ? true : false, *pWndGrid, dcMeasure,
					nVisibleColNo, nVisibleRowNo, nColNo, nRowNo, nColType, nRowType, 0, 0
					);
		else
		{
			_sizeCheck.cx = 13;
			_sizeCheck.cy = 13;
		}
	}
	
	// MEASURE SORT ARROW SIZE
CSize _sizeSortArrow( 0, 0 );
	if( (dwCellStyle&__EGCS_SORT_ARROW) != 0 )
	{
		_sizeSortArrow.cx = __EXT_SORT_ARROW_GLYPH_EXTENT_HORZ;
		_sizeSortArrow.cy = __EXT_SORT_ARROW_GLYPH_EXTENT_VERT;
	}

	// MEASURE FOCUS ARROW SIZE
CSize _sizeFocusArrow( 0, 0 );
	if( (dwCellStyle&(__EGCS_HDR_FOCUS_ARROW_RESERVE_SPACE|__EGCS_HDR_FOCUS_ARROW_DISPLAY)) != 0 )
	{
		_sizeFocusArrow.cx = __EXT_FOCUS_ARROW_GLYPH_EXTENT_HORZ;
		_sizeFocusArrow.cy = __EXT_FOCUS_ARROW_GLYPH_EXTENT_VERT;
	}

	// MEASURE ENTIRE SIZE
CSize _sizeMeasured = _sizeIcon;

	_sizeMeasured.cx += _sizeText.cx;
	_sizeMeasured.cx += _sizeAllButtons.cx;
	_sizeMeasured.cx += _sizeCheck.cx;
	_sizeMeasured.cx += _sizeSortArrow.cx;
	_sizeMeasured.cx += _sizeFocusArrow.cx;

	_sizeMeasured.cy = max( _sizeMeasured.cy, _sizeText.cy );
	_sizeMeasured.cy = max( _sizeMeasured.cy, _sizeAllButtons.cy );
	_sizeMeasured.cy = max( _sizeMeasured.cy, _sizeCheck.cy );
	_sizeMeasured.cy = max( _sizeMeasured.cy, _sizeSortArrow.cy );
	_sizeMeasured.cy = max( _sizeMeasured.cy, _sizeFocusArrow.cy );

	return _sizeMeasured;
}

Technical Support Apr 30, 2009 - 10:42 AM

This message is related to the second issue only.
It looks like it’s not possible to implement what you ask. First of all, the left and right arrow case are used for changing selection in the in place activated cell editor. This is the main role of the left and right arrow keys. If the walking editor feature is enabled in the grid window, then pressing the right arrow should focus and edit next grid cell at right only when the editor’s caret is in the rightmost position at the end of text. The same is for left arrow key when the caret is at the beginning of the edited text. So, the walking cell editor walks through text characters, not through grid cells. If we select entire text in the next or previous grid cell, then which action should be performed on left/right arrow key pressing in it? We think the Tab and Shift+Tab key combinations should be used for walking through grid cells in one row/column and optionally selecting entire text in the next/previous grid cells, but not the left/right arrow keys. The new CExtFormulaGridWnd formula grid control in Prof-UIS 2.85 uses such Tab keys and it’s provided as optional feature of the CExtGridWnd control:
http://www.prof-uis.com/download/forums/tmp/FormulaGrid-su.zip

David Langis Apr 30, 2009 - 1:06 PM

Not possible is an answer I was not expecting at all, I did it by commenting a couple of lines in the code. I understand that you want to keep the actual feature for reasons that you are the only one to know, as a Microsoft Excel user, this method is quite confusing. Having an option to control this behavior is a very small issue that would allow the table to behave like any spreadsheet program.

This is not a major issue to me anyway, I commetned the lines in the ExtGridWnd.cpp and it works well. I am more concerned about updates, I will need to comment these lines everytime I install a new verson of Prof-UIS.

Thanks,
David

Technical Support May 2, 2009 - 6:43 AM

We explained in details what is not possible and why. Besides, we run Excel 2007 and checked how the left/right arrow keys are working in it. Our Excel focuses the next/previous grid cells without activating cell editors. We have Excel with initial settings. Do we need to change the Excel settings somehow to make it activating cell editors on arrow keys?
In any case, please let us know which modifications you did in Prof-UIS source code and how can we see them in work using the SimpleGrids sample application?

David Langis May 4, 2009 - 7:01 AM

This is exactly what i want, currently in Prof-UIS, when i press the left/right arrow keys, it focuses the next/prev cell and activates the cell editors, i want it not to activate the cell editors.

Technical Support May 4, 2009 - 11:33 AM

The CExtGridWnd control has the walking cell editor feature which is supported both for horizontal and vertical directions. It’s turned off by default. The __EGWS_BSE_WALK_HORZ and/or __EGWS_BSE_WALK_VERT styles should be applied with the CExtGridWnd::BseModifyStyle() method invocation to turn this feature on. This feature assumes by design that the neighborhood cells of the focused and edited cell are activated by arrow keys. So, seems you need the same feature but without the in place editing of the neighborhood cells. We implemented this feature detail in Prof-UIS 2.85. We added two new __EGWS_BSE_WALK_HORZ_NO_EDIT and __EGWS_BSE_WALK_VERT_NO_EDIT grid styles. They should be used with the existing __EGWS_BSE_WALK_HORZ and/or __EGWS_BSE_WALK_VERT styles. The new styles will allow to change the focused grid cell on arrow keys from the in place activated cell editor but without editing the neighborhood cell. To use the improved walking cell editor feature you should re-download the today’s 2.85.

David Langis May 4, 2009 - 11:37 AM

Thanks a lot, In the 2.85 release I have, there is no documentation so I was not aware of this new option. Is the documentation of version 2.85 available?

Technical Support May 4, 2009 - 2:04 PM

Unfortunately, it’s in disassembled form right now and we have no compiled CHM and Microsoft Document Explorer help files.

David Langis May 4, 2009 - 11:46 AM

It seems that there are more than one version 2.85, The release I have is dated 22/01/2009. In this release, the __EGWS_BSE_WALK_HORZ_NO_EDIT and __EGWS_BSE_WALK_VERT_NO_EDIT options do not exist. I guess this could explain some problems I have that you said were fixed. I will download the latest one and check all this. Thanks a lot for your patience.

David Langis May 4, 2009 - 12:43 PM

It works well with the latest version 2.85. However, it does not work with the Tab and Shift+Tab keys. Is there an option to navigate to left and right cells using the tab keys while the cell are in editing mode?

Technical Support May 4, 2009 - 2:07 PM

Yes. The CExtGridWnd class in Prof-UIS 2.85 supports set of actions called standard accelerators (copy, cut and paste for example). Standard accelerator commands are defined as the __EGSA_*** constants. The Tab key functionality is also assumed as the standard accelerator. The Tab and Shift+Tab keys can be optionally used for in-row or in-column focus moving. There are the following constants for that:

#define __EGSA_IN_ROW_TAB_NEXT                  0x00000800
#define __EGSA_IN_ROW_TAB_PREV                  0x00001000
#define __EGSA_IN_COLUMN_TAB_NEXT               0x00002000
#define __EGSA_IN_COLUMN_TAB_PREV               0x00004000
#define __EGSA_IN_ROW_TAB                       (__EGSA_IN_ROW_TAB_NEXT|__EGSA_IN_ROW_TAB_PREV)
#define __EGSA_IN_COLUMN_TAB                    (__EGSA_IN_COLUMN_TAB_NEXT|__EGSA_IN_COLUMN_TAB_PREV)

You should invoke the following code to make the grid window moving focus to right/left cells in the same row on Tab key pressing:
CExtGridWnd & wndGrid = . . .
wndGrid.m_dwSupportedAccelCommands |= __EGSA_IN_ROW_TAB;


David Langis May 4, 2009 - 3:10 PM

Thanks, it works. Is there an option similar to the __EGWS_BSE_WALK_HORZ_NO_EDIT to prevent automatic inplace edition when using the tab keys in the same way than with the arrow keys?

Technical Support May 6, 2009 - 12:35 PM

We added a new flag __EGSA_TAB_NO_FOCUS. Please re-download 2.85 from the same location.

David Langis May 6, 2009 - 2:15 PM

Thanks a lot, it works as I want it. I had to modify it a bit and repeat the changes i made in OnGbwAnalyzeCellKeyEvent because I sometimes have hidden columns and just incrementing the focused column is not enough, I need to increment it up to the next visible column. When I say hidden column, I know there is an option to hide the cell contents but I need to completely hide a column. Maybe this could be a feature request, there is a lot of situations where a column contains important data that should be hidden to the user but still present on the table.

Thanks for the help, it is much appreciated.

Technical Support May 7, 2009 - 1:46 PM

The CExtGridWnd control supports hidden column and rows. This feature is used by the filtering feature demonstrated in the FilteredGrids sample application.
Please take a look at the CExtGridWnd::ColumnHide(), CExtGridWnd::RowHide(), CExtGridWnd::ColumnUnHideAll() and CExtGridWnd::RowUnHideAll() methods.


David Langis May 8, 2009 - 6:57 AM

Right, I forgot about it. I don’t use it as it does not actually hide the columns but rather removes them from the grid and sets them aside so they can be brought back. The problem with this method is that it changes the order of the columns which means that the hidden columns must be taken into account when reading storing data after edition or in some event handling. I chose to hide the columns by setting the extents to 0 and add the hidden flag to the cells. This way, the order of the columns is preserved which makes data management a lot simpler. On the other hand, I have to manage these hidden columns for keyboard navigation.

Technical Support Apr 30, 2009 - 9:22 AM

This message is related to the first issue only. You described situation when the page size is changed during scrolling. We improved this situation handling in the CExtScrollBar class. Please update the source code for the following method:

void CExtScrollBar::ScrollBar_TrackMouseLButtonDown( MSG * pMSG )
{
	ASSERT_VALID( this );
	if( ! m_bCompleteRepaint )
		return;
CPoint point( short(LOWORD(DWORD(pMSG->lParam))), short(HIWORD(DWORD(pMSG->lParam))) );
CExtPopupMenuTipWnd * pATTW = OnAdvancedPopupMenuTipWndGet();
CExtPaintManager::PAINTSCROLLBARDATA _psbd( this );
	_psbd.AdjustHT( point );
	if( (! m_bProcessingHover) || m_bProcessingClick || (! _psbd.m_bEnabled ) || _psbd.m_eSBMHT == CExtPaintManager::__ESBMHT_NOWHERE )
	{
		if( _psbd.m_eSBMHT == CExtPaintManager::__ESBMHT_NOWHERE || (! _psbd.m_bEnabled ) )
		{
			if( pATTW != NULL )
				pATTW->Hide();
			SendMessage( WM_CANCELMODE );
			Invalidate();
			UpdateWindow();
			return;
		}
	}
	if( ! m_bPopupInactiveLightMode )
		ActivateTopParent();
bool bAnimationLocked = AnimationClient_CacheGeneratorIsLocked();
	if( ! bAnimationLocked )
	{
		AnimationClient_CacheGeneratorLock();
		AnimationClient_CacheNextStateMinInfo( false, __EAPT_BY_PRESSED_STATE_TURNED_ON );
	}
	if( m_bEnableHookSpy )
		HookSpyUnregister();
	m_nSBMHT = INT(_psbd.m_eSBMHT);
	m_bProcessingClick = m_bProcessingHover = true;
	m_bProcessingOutClick = false;
	if( ! bAnimationLocked )
	{
 		AnimationClient_CacheNextStateMinInfo( true, __EAPT_BY_PRESSED_STATE_TURNED_ON );
		AnimationClient_CacheGeneratorUnlock();
	}
	Invalidate();
	UpdateWindow();
	if( pATTW != NULL )
		OnAdvancedPopupMenuTipWndDisplay( *pATTW, m_nSBMHT, true );
INT nScrollPosStart = _psbd.m_DSI.nPos, nScrollPos = _psbd.m_DSI.nPos;
	m_nHelperTrackPos = _psbd.m_DSI.nPos;
	m_bHelperHaveTrackPos = true;
CRect rcArea = _psbd.GetAreaRectHT();
const UINT nTimerID_zero_start = 401;
const UINT nTimerID_1st_slow = 402;
const UINT nTimerEllapse_1st_slow = 400;
const UINT nTimerID_2nd_fast = 403;
const UINT nTimerEllapse_2nd_fast = 100;
HWND hWndOwn = GetSafeHwnd();
	ASSERT( hWndOwn != NULL && ::IsWindow( hWndOwn ) );
HWND hWndParent = ::GetParent( hWndOwn );
bool bVirtualMode = false, bFinalNotify = true;
#if (!defined __EXT_MFC_NO_SCROLLWND)
CExtScrollWnd * pExtScrollWnd = NULL;
	if( hWndParent != NULL )
	{
		CWnd * pWndParentPermanent = CWnd::FromHandlePermanent( hWndParent );
		if( pWndParentPermanent != NULL )
		{
			pExtScrollWnd = DYNAMIC_DOWNCAST( CExtScrollWnd, pWndParentPermanent );
#if (!defined __EXT_MFC_NO_SCROLLITEMWND)
			if( pExtScrollWnd != NULL )
			{
				CExtScrollItemWnd * pExtScrollItemWnd = DYNAMIC_DOWNCAST( CExtScrollItemWnd, pWndParentPermanent );
				if( pExtScrollItemWnd != NULL )
				{
					DWORD dwScrollType = __ESIW_ST_NONE;
					if( _psbd.m_bHorzBar )
						dwScrollType = pExtScrollItemWnd->SiwScrollTypeHGet();
					else
						dwScrollType = pExtScrollItemWnd->SiwScrollTypeVGet();
					if( dwScrollType == __ESIW_ST_VIRTUAL )
						bVirtualMode = true;
				}
			}
#endif
		}
	}
#endif
bool bStopFlag = false;
CPoint ptCursor( point );
INT nStepSize = 0L;
bool bUpStep = false;
bool bMouseButtonsNotSwapped = ( ::GetSystemMetrics( SM_SWAPBUTTON ) != 0 ) ? false : true;
	switch( _psbd.m_eSBMHT )
	{
	case CExtPaintManager::__ESBMHT_BUTTON_UP:
		bUpStep = true;
		// continue falling here ...
	case CExtPaintManager::__ESBMHT_BUTTON_DOWN:
		nStepSize = GetStepSize();
#if (!defined __EXT_MFC_NO_SCROLLWND)
		if( pExtScrollWnd != NULL )
		{
			int nDir = ( _psbd.m_eSBMHT == CExtPaintManager::__ESBMHT_BUTTON_DOWN ) ? (+1) : (-1);
			CSize _size = pExtScrollWnd->OnSwGetLineSize( nDir );
			nStepSize = _psbd.m_bHorzBar ? _size.cx : _size.cy;
			if( nStepSize <= 0L )
				nStepSize = GetStepSize();
		}
#endif
		break;
	case CExtPaintManager::__ESBMHT_PAGE_UP:
		bUpStep = true;
		// continue falling here ...
	case CExtPaintManager::__ESBMHT_PAGE_DOWN:
		nStepSize = (INT)_psbd.m_DSI.nPage;
#if (!defined __EXT_MFC_NO_SCROLLWND)
		if( pExtScrollWnd != NULL )
		{
			int nDir = ( _psbd.m_eSBMHT == CExtPaintManager::__ESBMHT_PAGE_DOWN ) ? (+1) : (-1);
			CSize _size = pExtScrollWnd->OnSwGetPageSize( nDir );
			nStepSize = _psbd.m_bHorzBar ? _size.cx : _size.cy;
		}
#endif
		if( nStepSize <= 0L )
			nStepSize = GetStepSize();
		break;
	case CExtPaintManager::__ESBMHT_THUMB:
		break;
	}
bool bMenuMode = false;
	if( CExtPopupMenuWnd::IsMenuTracking() )
	{
		CWnd * pWnd = GetParent();
		for( ; pWnd != NULL; pWnd = pWnd->GetParent() )
		{
			if( pWnd->IsKindOf( RUNTIME_CLASS(CExtPopupMenuWnd) ) )
			{
				bMenuMode = true;
				break;
			}
			if( (pWnd->GetStyle()&WS_CHILD) == 0 )
				break;
		}
	}
INT nMx = INT( _psbd.m_DSI.nMax - _psbd.m_DSI.nPage + 1 );
INT nScrollLimit = _psbd.m_DSI.nMax - _psbd.m_DSI.nMin - _psbd.m_DSI.nPage + 1;
	ASSERT( nScrollLimit >= 0 );
	if( nStepSize > nScrollLimit )
		nStepSize = nScrollLimit;
CRect rcScrollable = _psbd.m_rcBar;
	if( _psbd.m_bHorzBar )
	{
		rcScrollable.left = _psbd.m_rcButtonUp.right;
		rcScrollable.right = _psbd.m_rcButtonDown.left;
	}
	else
	{
		rcScrollable.top = _psbd.m_rcButtonUp.bottom;
		rcScrollable.bottom = _psbd.m_rcButtonDown.top;
	}
	ScrollBar_CaptureSet();
	if( nStepSize != 0L )
		::PostMessage( hWndOwn, WM_TIMER, WPARAM(nTimerID_zero_start), LPARAM(0L) );
	for( MSG msg; ::IsWindow( hWndOwn ) && (!bStopFlag); )
	{
		if( ! PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE) )
		{
			if( ! ::IsWindow( hWndOwn ) )
				break;
			::WaitMessage();
			continue;
		}
		bool bAnalyzeThumb = false;
		switch( msg.message )
		{
		case WM_LBUTTONDBLCLK:
		case WM_LBUTTONUP:
		case WM_RBUTTONDBLCLK:
		case WM_RBUTTONDOWN:
		case WM_RBUTTONUP:
		case WM_MBUTTONDBLCLK:
		case WM_MBUTTONDOWN:
		case WM_MBUTTONUP:
		case WM_CANCELMODE:
		case WM_ACTIVATEAPP:
		case WM_KEYDOWN:
		case WM_KEYUP:
			bStopFlag = true;
		break;
		case WM_CAPTURECHANGED:
			if( (HWND)msg.wParam != hWndOwn )
				bStopFlag = true;
		break;
		case WM_MOUSEMOVE:
			if( m_nSBMHT == INT(CExtPaintManager::__ESBMHT_THUMB) )
			{
				if(		( ! CExtPopupMenuWnd::IsKeyPressed( bMouseButtonsNotSwapped ? VK_LBUTTON : VK_RBUTTON,true) )
					||	CExtPopupMenuWnd::IsKeyPressed( VK_MBUTTON )
					||	CExtPopupMenuWnd::IsKeyPressed( bMouseButtonsNotSwapped ?  VK_RBUTTON : VK_LBUTTON,true )
					||	( (!bMenuMode) && CExtPopupMenuWnd::IsMenuTracking() )
					)
				{
					bStopFlag = true;
					break;
				}
				PeekMessage(&msg,NULL,msg.message,msg.message,PM_REMOVE);
				bAnalyzeThumb = true;
				::GetCursorPos( &ptCursor );
				::ScreenToClient( hWndOwn, &ptCursor );
				break;
			}
			if( nStepSize == 0 )
				break;
		case WM_TIMER:
			{
				if(		( ! CExtPopupMenuWnd::IsKeyPressed( bMouseButtonsNotSwapped ? VK_LBUTTON : VK_RBUTTON,true) )
					||	CExtPopupMenuWnd::IsKeyPressed( VK_MBUTTON )
					||	CExtPopupMenuWnd::IsKeyPressed( bMouseButtonsNotSwapped ? VK_RBUTTON : VK_LBUTTON,true )
					||	( (!bMenuMode) && CExtPopupMenuWnd::IsMenuTracking() )
					)
				{
					bStopFlag = true;
					break;
				}
				if( msg.hwnd != hWndOwn )
					break;
				if( msg.wParam != nTimerID_zero_start && msg.wParam != nTimerID_1st_slow && msg.wParam != nTimerID_2nd_fast )
					break;
				if( msg.wParam == nTimerID_zero_start )
					::SetTimer( hWndOwn, nTimerID_1st_slow, nTimerEllapse_1st_slow, NULL );
				else if( msg.wParam == nTimerID_1st_slow )
				{
					::KillTimer( hWndOwn, nTimerID_1st_slow );
					CExtPaintManager::stat_PassPaintMessages();
					::SetTimer( hWndOwn, nTimerID_2nd_fast, nTimerEllapse_2nd_fast, NULL );
				}
				ASSERT( nStepSize != 0L );
				PeekMessage(&msg,NULL,msg.message,msg.message,PM_REMOVE);
				::GetCursorPos( &ptCursor );
				::ScreenToClient( hWndOwn, &ptCursor );
				bool bPause = false;
				if( ! rcArea.PtInRect( ptCursor ) )
					bPause = true;
				else
				{
					if( m_nSBMHT == INT(CExtPaintManager::__ESBMHT_PAGE_UP) || m_nSBMHT == INT(CExtPaintManager::__ESBMHT_PAGE_DOWN) )
					{
						CExtPaintManager::PAINTSCROLLBARDATA _psbd2( this );
						_psbd2.AdjustHT( ptCursor );
						INT nSBMHT2 = INT( _psbd.m_eSBMHT );
						if( nSBMHT2 != m_nSBMHT )
							bPause = true;
						else
						{
							CRect rcArea2 = _psbd2.GetAreaRectHT();
							if( ! rcArea2.PtInRect( ptCursor ) )
								bPause = true;
							else
							{
								if( _psbd2.m_bHorzBar )
								{
									if( m_nSBMHT == INT(CExtPaintManager::__ESBMHT_PAGE_UP) )
									{
										if( ptCursor.x >= _psbd2.m_rcThumb.left )
											bPause = true;
									}
									else if( m_nSBMHT == INT(CExtPaintManager::__ESBMHT_PAGE_DOWN) )
									{
										if( ptCursor.x <= _psbd2.m_rcThumb.right )
											bPause = true;
									}
								}
								else
								{
									if( m_nSBMHT == INT(CExtPaintManager::__ESBMHT_PAGE_UP) )
									{
										if( ptCursor.y >= _psbd2.m_rcThumb.top )
											bPause = true;
									}
									else if( m_nSBMHT == INT(CExtPaintManager::__ESBMHT_PAGE_DOWN) )
									{
										if( ptCursor.y <= _psbd2.m_rcThumb.bottom )
											bPause = true;
									}
								}
							}
						}
					}
				}
				if( bPause )
				{
					if( ! m_bProcessingOutClick )
					{
						m_bProcessingOutClick = true;
						Invalidate();
					}
					if( pATTW != NULL )
						pATTW->Hide();
					continue;
				}
				if( bUpStep )
				{
					nScrollPos -= nStepSize;
					if( nScrollPos < _psbd.m_DSI.nMin )
						nScrollPos = _psbd.m_DSI.nMin;
				}
				else
				{
					nScrollPos += nStepSize;
					if( nScrollPos > nMx )
						nScrollPos = nMx;
				}
				if( _GetScrollPos( true ) != nScrollPos )
				{
					bool bSendScrollingNotification = true, bTrackPos = true;
					if( hWndParent != NULL )
					{
						switch( m_nSBMHT )
						{
						case (CExtPaintManager::__ESBMHT_BUTTON_UP):
							if( m_bSendActionNotifications )
								::SendMessage(
									hWndParent,
									_psbd.m_bHorzBar ? WM_HSCROLL : WM_VSCROLL,
									MAKEWPARAM( ( _psbd.m_bHorzBar ? SB_LINELEFT : SB_LINEUP ), 0 ),
									LPARAM(m_hWnd)
									);
							if( ! bVirtualMode )
								_SetScrollPos( nScrollPos, bTrackPos, true, bSendScrollingNotification );
							else
								bFinalNotify = (!m_bSendActionNotifications);
						break;
						case (CExtPaintManager::__ESBMHT_BUTTON_DOWN):
							if( m_bSendActionNotifications )
								::SendMessage(
									hWndParent,
									_psbd.m_bHorzBar ? WM_HSCROLL : WM_VSCROLL,
									MAKEWPARAM( ( _psbd.m_bHorzBar ? SB_LINERIGHT : SB_LINEDOWN ), 0 ),
									LPARAM(m_hWnd)
									);
							if( ! bVirtualMode )
								_SetScrollPos( nScrollPos, bTrackPos, true, bSendScrollingNotification );
							else
								bFinalNotify = (!m_bSendActionNotifications);
						break;
						case (CExtPaintManager::__ESBMHT_PAGE_UP):
							if( m_bSendActionNotifications )
								::SendMessage(
									hWndParent,
									_psbd.m_bHorzBar ? WM_HSCROLL : WM_VSCROLL,
									MAKEWPARAM( ( _psbd.m_bHorzBar ? SB_PAGELEFT : SB_PAGEUP ), 0 ),
									LPARAM(m_hWnd)
									);
							if( ! bVirtualMode )
								_SetScrollPos( nScrollPos, bTrackPos, true, bSendScrollingNotification );
							else
								bFinalNotify = (!m_bSendActionNotifications);
						break;
						case (CExtPaintManager::__ESBMHT_PAGE_DOWN):
							if( m_bSendActionNotifications )
								::SendMessage(
									hWndParent,
									_psbd.m_bHorzBar ? WM_HSCROLL : WM_VSCROLL,
									MAKEWPARAM( ( _psbd.m_bHorzBar ? SB_PAGERIGHT : SB_PAGEDOWN ), 0 ),
									LPARAM(m_hWnd)
									);
							if( ! bVirtualMode )
								_SetScrollPos( nScrollPos, bTrackPos, true, bSendScrollingNotification );
							else
								bFinalNotify = (!m_bSendActionNotifications);
						break;
						case (CExtPaintManager::__ESBMHT_THUMB):
							bTrackPos = true;
							if( ! bVirtualMode )
								_SetScrollPos( nScrollPos, bTrackPos, true, bSendScrollingNotification );
							else
								bFinalNotify = false;
						break;
						}
					}
					if( pATTW != NULL && ( ! bAnalyzeThumb ) )
						OnAdvancedPopupMenuTipWndDisplay( *pATTW, m_nSBMHT, true );
				}
				CExtPaintManager::PAINTSCROLLBARDATA _psbd2( this );
				::memcpy( &_psbd.m_DSI, &_psbd2.m_DSI, sizeof(SCROLLINFO) );
				nMx = INT( _psbd.m_DSI.nMax - _psbd.m_DSI.nPage + 1 );
				nScrollLimit = _psbd.m_DSI.nMax - _psbd.m_DSI.nMin - _psbd.m_DSI.nPage + 1;
				ASSERT( nScrollLimit >= 0 );
				if( nStepSize > nScrollLimit )
					nStepSize = nScrollLimit;
				_psbd.AdjustHT( ptCursor );
				bool bProcessingOutClick =
					( m_nSBMHT == INT(_psbd.m_eSBMHT) )
						? false : true;
				rcArea = _psbd.GetAreaRect( CExtPaintManager::e_scroll_bar_mouse_hover_type_t(m_nSBMHT) );
				if( m_bProcessingOutClick != bProcessingOutClick )
				{
					bool bAnimationLocked = AnimationClient_CacheGeneratorIsLocked();
					if( ! bAnimationLocked )
					{
						AnimationClient_CacheGeneratorLock();
 						AnimationClient_CacheNextStateMinInfo( false, __EAPT_BY_PRESSED_STATE_TURNED_OFF );
					}
					m_bProcessingOutClick = bProcessingOutClick;
					if( ! bAnimationLocked )
					{
 						AnimationClient_CacheNextStateMinInfo( true, __EAPT_BY_PRESSED_STATE_TURNED_OFF );
						AnimationClient_CacheGeneratorUnlock();
					}
					Invalidate();
					UpdateWindow();
				}
			}
		break;
		default:
		{
			if(		( ! CExtPopupMenuWnd::IsKeyPressed( bMouseButtonsNotSwapped ? VK_LBUTTON : VK_RBUTTON,true) )
				||	CExtPopupMenuWnd::IsKeyPressed( VK_MBUTTON )
				||	CExtPopupMenuWnd::IsKeyPressed( bMouseButtonsNotSwapped ? VK_RBUTTON : VK_LBUTTON,true )
				||	( (!bMenuMode) && CExtPopupMenuWnd::IsMenuTracking() )
				)
				bStopFlag = true;
		}
		break;
		}
		if( ! ::IsWindow( hWndOwn ) )
			bStopFlag = true;
		if( bStopFlag || nScrollLimit == 0L )
			break;
		if( bAnalyzeThumb )
		{
			LONG nPixelOffset = _psbd.m_bHorzBar ? (ptCursor.x - point.x) : (ptCursor.y - point.y);
			LONG nPixelExtent = _psbd.m_bHorzBar ? (rcScrollable.Width() - _psbd.m_rcThumb.Width()) : (rcScrollable.Height() - _psbd.m_rcThumb.Height());
			if( nPixelExtent <= 0 )
			{
				bStopFlag = true;
				break;
			}
			if( abs(nPixelOffset) > nPixelExtent )
				nPixelOffset = (nPixelOffset < 0) ? (-nPixelExtent) : nPixelExtent;
			INT nShift = ( nPixelExtent == 0 || nPixelOffset == 0 ) ? 0 : ::MulDiv( nScrollLimit, abs(nPixelOffset), nPixelExtent );
			nScrollPos = nScrollPosStart;
			if( nPixelOffset < 0 )
			{
				nScrollPos -= nShift;
				if( nScrollPos < _psbd.m_DSI.nMin )
					nScrollPos = _psbd.m_DSI.nMin;
			}
			else
			{
				nScrollPos += nShift;
				if( nScrollPos > nMx )
					nScrollPos = nMx;
			}
			if( ! bVirtualMode )
			{
				if( _GetScrollPos( true ) != nScrollPos )
				{
					_SetScrollPos( nScrollPos, true );
					if( pATTW != NULL )
						OnAdvancedPopupMenuTipWndDisplay( *pATTW, m_nSBMHT, true );
				}
				bFinalNotify = true;
			}
			CExtPaintManager::PAINTSCROLLBARDATA _psbd2( this );
			::memcpy( &_psbd.m_DSI, &_psbd2.m_DSI, sizeof(SCROLLINFO) );
			nMx = INT( _psbd.m_DSI.nMax - _psbd.m_DSI.nPage + 1 );
			nScrollLimit = _psbd.m_DSI.nMax - _psbd.m_DSI.nMin - _psbd.m_DSI.nPage + 1;
			ASSERT( nScrollLimit >= 0 );
			if( nStepSize > nScrollLimit )
				nStepSize = nScrollLimit;
			_psbd.AdjustHT( ptCursor );
			rcArea = _psbd.GetAreaRect( CExtPaintManager::__ESBMHT_THUMB );
			continue;
		}
		if(		m_bPopupInactiveLightMode
			&&	(	msg.message == WM_TIMER
				||	(__EXT_MFC_WM_MOUSEFIRST <= msg.message && msg.message <= __EXT_MFC_WM_MOUSELAST )
				)
			)
			::PeekMessage(&msg,NULL,msg.message,msg.message,PM_REMOVE);
		else
		if( ! AfxGetThread()->PumpMessage() )
			break;
	}
	if( ! ::IsWindow( hWndOwn ) )
		return;
	if( nStepSize != 0L )
	{
		::KillTimer( hWndOwn, nTimerID_1st_slow );
		::KillTimer( hWndOwn, nTimerID_2nd_fast );
	}
	bAnimationLocked = AnimationClient_CacheGeneratorIsLocked();
	if( ! bAnimationLocked )
	{
		AnimationClient_CacheGeneratorLock();
		if( AnimationClient_StateGet(true).IsEmpty() )
			AnimationClient_CacheNextStateMinInfo( false, __EAPT_BY_PRESSED_STATE_TURNED_OFF );
	}
	if( bFinalNotify )
		_SetScrollPos( nScrollPos, false, true, true );
	m_nSBMHT = INT(CExtPaintManager::__ESBMHT_NOWHERE);
	m_bProcessingClick = m_bProcessingOutClick = m_bProcessingHover = false;
	if( ! bAnimationLocked )
	{
		::GetCursorPos( &ptCursor );
		ScreenToClient( &ptCursor );
		_psbd.AdjustHT( ptCursor );
		m_nSBMHT = INT(_psbd.m_eSBMHT);
 		AnimationClient_CacheNextStateMinInfo( true, __EAPT_BY_PRESSED_STATE_TURNED_OFF );
		AnimationClient_CacheGeneratorUnlock();
	}
	Invalidate();
	UpdateWindow();
	m_nHelperTrackPos = -1;
	m_bHelperHaveTrackPos = false;
	ScrollBar_CaptureRelease();
	if( pATTW != NULL )
		OnAdvancedPopupMenuTipWndDisplay( *pATTW, INT(_psbd.m_eSBMHT), false );
	::SendMessage( hWndParent, _psbd.m_bHorzBar ? WM_HSCROLL : WM_VSCROLL, MAKEWPARAM( SB_ENDSCROLL, 0 ), LPARAM(m_hWnd) );
	if( m_bEnableHookSpy )
		HookSpyRegister( __EHSEF_MOUSE_ALL_WITHOUT_WHEEL|__EHSEF_WND_PROC_IN|__EHSEF_PRE_TRANSLATION );
}

David Langis Apr 30, 2009 - 12:43 PM

It solves the issue regarding the overlap with the scroll bar button but it created a new one. The scroll bar seems to hesitate between two positions in some situations. Also, the length of the tracking bar is still not constant. Would there be way to implement scrolling by item using pixels? I mean that scrolling one tick to the right for example would revert to scrolling N pixels to the right. This way, the tracking bar would have a constant length and the scroll bars would behave like standard scroll bars. Try it in the simple grid sample and enlarge one of the column so it is very wide compared to the other columns, it does not behave well.

Regards,
David

Technical Support May 2, 2009 - 6:54 AM

The thumb button size depends from two values: number of the scrollable items visible on the screen (this is called page size) and number of all the items (this is called scrolling range). If you are using columns/rows as scrollable items, then the page size can be different when the column widths/row heights are different. Our grids and other scrollable windows display scrollbars with variable size of the thumb button in such case and we think this is correct. If you have less than 10000 columns/rows in your grid, then you can use pixel-by-pixel scrolling to see scroll bars with more persistent sizes of their thumb buttons. You should use the __ESIS_STH_PIXEL / __ESIS_STV_PIXEL styles instead of the __ESIS_STH_ITEM / __ESIS_STV_ITEM styles for that.