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.
Subject |
Author |
Date |
|
tera tera
|
May 1, 2009 - 4:18 AM
|
Hello.
There is time when a focus is not set by child control even if I click CExtControlBar.
When I clicked non-client areas of Bar.
void CLogCtrl::OnSetFocus(CWnd* pOldWnd)
{
CRichEditCtrl::OnSetFocus(pOldWnd);
}
Please revise it.
|
|
Technical Support
|
May 2, 2009 - 12:40 PM
|
We tried to reproduce this but the rich editor receives the focus gain event. Please provide us with more details about what exactly we should do to reproduce this?
|
|
tera tera
|
May 2, 2009 - 4:56 PM
|
Hello. caption of the docking bar of the non-focus,
Do not click it. You drag it.
Then a focus is not transmitted
This reproduces even control except richEdit. I am troubled.
If you do not understand it, please ask me a question again.
|
|
Technical Support
|
May 3, 2009 - 2:22 PM
|
Yes you are right. The caption of a control bar indicates the active state of the bar. If the bar is active, then the user performs or has finished some action with the bar. The active bar state does not always mean focusing of its child window. The CExtControlBar::IsBarWindowActive() method returns theactive state of the control bar. The active state is a property which is supported independently of the focused state of the bar’s child window.
|
|
tera tera
|
May 3, 2009 - 6:08 PM
|
Hello. In CExtControlBar, I stick CView.
However, a focus is not set in drag.
The input of the key does not come in CView even if I perform key input for CView because a focus is not set.
I am troubled.
Please teach a good method. Thanks
|
|
Technical Support
|
May 4, 2009 - 11:33 AM
|
Yes, you are absolutely right. Please let us explain you the following two situations:
Situation 1: User just clicks on the caption of the CExtControlBar window. As result, the bar becomes active, its caption is highlighted as active and its child window becomes focused. That is what the user expects from click on the bar’s caption.
Situation 2: User changes location of the CExtControlBar window via drag-n-dropping its caption. As result, the bar is activated, it’s caption is highlighted but it’s child window does not become focused because drag-n-dropping is not the same as click on bar’s caption. The bar drag-n-dropping and resizing are needed to change layout of control bar windows. These actions may be needed to make the view window larger or smaller. But these actions are not for focusing bar’s child window.
The CExtControlBar::_Dragging_OnStop() internal virtual method is invoked when the bar drag-n-dropping is complete. You can override this method and set the focus to the bar window and it will focus its child window automatically
|
|
Lars Mohr
|
Apr 30, 2009 - 9:12 AM
|
Hello Support Team! The select status of an item is changed with a left-button-up message, but is there a delay of > 2 sec between down and up message the select status change doesn’t work. You can see this with Prof-UIS Controls sample, too. Regards
|
|
Technical Support
|
Apr 30, 2009 - 10:01 AM
|
Thank you for reporting us this issue. To fix it please update the source code for the following two methods:
bool CExtTreeCtrl::OnTreeMouseClick(
HTREEITEM hti,
DWORD dwHitTestFlags,
int nMouseButton,
int nClick,
UINT nMouseEventFlags,
CPoint point
)
{
ASSERT_VALID( this );
if( hti == NULL )
return false;
switch( nMouseButton )
{
case VK_LBUTTON:
{
DWORD dwTreeStyle = TreeGetStyle();
bool bMultiSelection = ( ( dwTreeStyle & __EXT_TREE_MULTIPLE_SELECTION ) != 0 ) ? true : false;
bool bSelectDisabledItems = ( ( dwTreeStyle & __EXT_TREE_SELECT_DISABLE_ITEMS ) != 0 ) ? true : false;
bool bFocusDisabledItems = ( ( dwTreeStyle & __EXT_TREE_FOCUS_DISABLE_ITEMS ) != 0 ) ? true : false;
bool bSelectCollapsedItems = ( ( dwTreeStyle & __EXT_TREE_SELECT_COLLAPSED_ITEMS ) != 0 ) ? true : false;
bool bSubtractSelection = ( ( dwTreeStyle & __EXT_TREE_SUBTRACT_SELECTION ) != 0 ) ? true : false;
bool bSingleExpand = ( ( GetStyle() & TVS_SINGLEEXPAND ) != 0 ) ? true : false;
bool bEditLabels = ( ( GetStyle() & TVS_EDITLABELS ) != 0 ) ? true : false;
bool bItemIsEnabled = OnQueryItemEnabledState( hti );
static HTREEITEM g_htiLastLButtonDownItem = NULL;
switch( nClick )
{
case 0:
g_htiLastLButtonDownItem = hti;
// continue falling after drag detection ...
case 1:
{
if( ::GetFocus() != m_hWnd )
SetFocus();
if( g_htiLastLButtonDownItem != hti )
return true;
if( ( dwHitTestFlags & __EXT_TVHT_ONCONTROL ) != 0 )
{
CRect rcControl;
VERIFY( TreeItemRectGet( hti, rcControl, e_tirt_control ) );
ASSERT( ! rcControl.IsRectEmpty() );
if( m_hWndChildControl != NULL )
{
CRect rc;
::GetWindowRect( m_hWndChildControl, &rc );
if( rc == rcControl )
return true;
SendMessage( WM_CANCELMODE );
}
m_hWndChildControl = OnInplaceControlCreate( hti, rcControl );
if( m_hWndChildControl != NULL )
m_htiInplaceEdited = hti;
return true;
}
if( ( dwHitTestFlags & __EXT_TVHT_ONITEMBUTTON ) != 0 )
{
//if( ( nMouseEventFlags & (MK_CONTROL|MK_SHIFT) ) != 0 )
// return true;
HTREEITEM htiFocus = GetFocusedItem();
if( htiFocus != NULL )
{
if( TreeItemIsExpanded( hti )
&& HasAncestor( hti, htiFocus )
)
{
if( ( ! bFocusDisabledItems )
&& ( ! bItemIsEnabled )
)
FocusItem( NULL, false, false );
else
FocusItem( hti, bSelectDisabledItems || bItemIsEnabled, true );
}
}
SendMessage( WM_CANCELMODE );
Expand( hti, TVE_TOGGLE );
Invalidate();
return true;
}
DWORD dwSelectionAreaFlags =
__EXT_TVHT_ONITEMICON|__EXT_TVHT_ONITEMLABEL
|__EXT_TVHT_ONCONTROL|__EXT_TVHT_ONCHECKBOX;
bool bFullRowSelection = ( ( GetStyle() & TVS_FULLROWSELECT ) != 0 ) ? true : false;
if( bFullRowSelection )
dwSelectionAreaFlags |= __EXT_TVHT_ONITEMINDENT|__EXT_TVHT_ONITEMRIGHT;
if( ( dwHitTestFlags & dwSelectionAreaFlags ) != 0
&& ( bFocusDisabledItems || bItemIsEnabled )
)
{
TREEITEMINFO_t & _TII = TreeItemInfoGet( hti );
if( bEditLabels
&& (hti == GetFocusedItem())
&& ( bFullRowSelection
|| ( dwHitTestFlags & __EXT_TVHT_ONITEMLABEL ) != 0
)
)
{
if( ( m_hWndChildControl == NULL
|| ( ! ::IsWindow( m_hWndChildControl ) )
)
&& ::GetFocus() == m_hWnd
&& m_nLastMouseButtonEventType[0] == 0 // if WM_LBUTTONUP after WM_LBUTTONDOWN, i.e. if not after WM_LBUTTONDBLCLK
)
{
KillTimer( m_nDelayedEditingTimerID );
m_wndContentExpand.Deactivate();
SetTimer( m_nDelayedEditingTimerID, ::GetDoubleClickTime() + 1 , NULL );
}
return true;
}
if( OnQueryItemEnabledState( hti ) )
{
switch( _TII.m_eCheckBoxType )
{
case e_cbt_check_box:
switch( _TII.m_nCheckBoxState )
{
case 0:
_TII.m_nCheckBoxState = 1;
break;
case 1:
_TII.m_nCheckBoxState = 0;
break;
}
break;
case e_cbt_tri_state_check_box:
switch( _TII.m_nCheckBoxState )
{
case 0:
_TII.m_nCheckBoxState = 1;
break;
case 1:
_TII.m_nCheckBoxState = 2;
break;
case 2:
_TII.m_nCheckBoxState = 0;
break;
}
break;
case e_cbt_radio:
_CheckRadioBox( hti );
break;
} // switch( _TII.m_eCheckBoxType )
} // if( OnQueryItemEnabledState( hti ) )
HTREEITEM htiFocus = GetFocusedItem();
if( bSingleExpand
&& htiFocus == hti
&& ( nMouseEventFlags & (MK_CONTROL|MK_SHIFT) ) == 0
)
{
SendMessage( WM_CANCELMODE );
Expand( hti, TVE_TOGGLE );
Invalidate();
return true;
}
bool bSelectFocusedFinally = true;
if( bSubtractSelection
&& ( nMouseEventFlags & (MK_CONTROL|MK_SHIFT) ) == MK_CONTROL
)
{
AnchorItemSet( hti );
SendMessage( WM_CANCELMODE );
SelectItem( hti, !IsItemSelected( hti ), IsItemSelected( hti ) );
FocusItem( hti );
Invalidate();
if( m_wndContentExpand.GetSafeHwnd() != NULL )
m_wndContentExpand.Invalidate();
return true;
}
HTREEITEM htiAnchor = AnchorItemGet();
if( ( nMouseEventFlags & (MK_CONTROL|MK_SHIFT) ) != MK_SHIFT )
AnchorItemSet( hti );
if( htiFocus != NULL )
{
if( bMultiSelection
&& ( nMouseEventFlags & MK_SHIFT ) == MK_SHIFT
)
{
if( bSubtractSelection && htiAnchor != NULL )
SelectItemRange( htiAnchor, htiFocus, false, !bSelectCollapsedItems, bSelectDisabledItems );
SelectItemRange( hti, htiAnchor, true, !bSelectCollapsedItems, bSelectDisabledItems );
}
}
bool bUnselectOtherItems =
(
( ! bMultiSelection )
|| ( ( nMouseEventFlags & (MK_CONTROL|MK_SHIFT) ) == 0 )
)
? true : false;
SendMessage( WM_CANCELMODE );
if( ( ! bSelectDisabledItems ) && ( ! bItemIsEnabled ) )
bSelectFocusedFinally = false;
if( ! bSelectFocusedFinally )
SelectItem( hti, false );
FocusItem( hti, bSelectFocusedFinally, bUnselectOtherItems, true );
Invalidate();
if( m_wndContentExpand.GetSafeHwnd() != NULL )
m_wndContentExpand.Invalidate();
if( nClick == 0 && OnTreeItemDoDragDetect( hti, dwHitTestFlags, nMouseButton, nClick, nMouseEventFlags, point ) )
{
g_htiLastLButtonDownItem = NULL;
return true;
}
return true;
}
}
break;
case 2:
g_htiLastLButtonDownItem = NULL;
if( ( dwHitTestFlags & (__EXT_TVHT_ONITEMICON|__EXT_TVHT_ONITEMLABEL) ) != 0
&& ( bFocusDisabledItems || bItemIsEnabled )
&& ! bSingleExpand
)
{
if( ::GetFocus() != m_hWnd )
SetFocus();
SendMessage( WM_CANCELMODE );
if( ItemHasChildren( hti ) )
Expand( hti, TVE_TOGGLE );
Invalidate();
return true;
}
break;
} // switch( nClick )
}
return true; // case VK_LBUTTON
case VK_RBUTTON:
{
if( ::GetFocus() != m_hWnd )
SetFocus();
switch( nClick )
{
case 0:
if( OnTreeItemDoDragDetect( hti, dwHitTestFlags, nMouseButton, nClick, nMouseEventFlags, point ) )
return true;
// continue falling after drag detection ...
case 1:
{
CPoint ptScreen = point;
ClientToScreen( &ptScreen );
SendMessage( WM_CONTEXTMENU, WPARAM(m_hWnd), MAKELPARAM(ptScreen.x,ptScreen.y) );
}
return true;
} // switch( nClick )
}
break; // case VK_RBUTTON
default:
switch( nClick )
{
case 0:
if( OnTreeItemDoDragDetect( hti, dwHitTestFlags, nMouseButton, nClick, nMouseEventFlags, point ) )
return true;
// continue falling after drag detection ...
} // switch( nClick )
break;
} // switch( nMouseButton )
return false;
}
bool CExtControlBar::stat_DoDragDetect(
HWND hWnd,
const POINT & ptWndClient
)
{
if( hWnd == NULL || (! ::IsWindow( hWnd ) ) )
return false;
CPoint ptScreen = ptWndClient;
::ClientToScreen( hWnd, &ptScreen );
while( ::DragDetect( hWnd, ptScreen ) )
{
POINT ptCursorPos = { -32767, -32767 };
if( ! ::GetCursorPos( &ptCursorPos ) )
return false;
if( ptScreen == ptCursorPos )
continue; //only drag time elapsed but mouse is not moved
return true;
}
return false;
}
|
|
Technical Support
|
Apr 30, 2009 - 9:21 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 );
}
|
|
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.
|
|
Offer Har
|
Apr 28, 2009 - 2:18 PM
|
Dear Support, We have a CExtGridCell derived class (actually CExtGridCellComboBox derived) The design we have is very object-oriented, so that the cell observes changes in the data, and if, for example the string to display in the cell changes, it does it by itself. The only problem is that the cell cannot draw itself, nor can it ask somebody to do it for him, which breaks the whole design. Is there any chance we are missing something? if not, how can this be done, this realy breaks oue whole design. Thanks, Ron.
|
|
Technical Support
|
May 4, 2009 - 2:08 PM
|
The details in your last message are important. So, we have new ideas. You have very powerful grid cells and they are the only object which can do updating. It’s OK. There are no problems. Now we need to clarify what is updating? You can save the new information from the network into any of your grid cells. This is simple. The next thing is to repaint the renewed/updated grid cell. But the grid cell does not know it’s location inside the grid window and it does not know whether it’s currently displayed in the grid’s client area. The fastest way to redraw the grid cell in such situation is to do the following: 1) Use the data provider which knows the grid window reference. We described you how to do this with the ready to use source code. 2) Detect whether the grid cell is displayed in the grid’s client area. Solution for this sub task is hidden inside our previous answer. You can ask the grid window for displayed row/column ranges (CExtScrollItemWnd::OnSiwGetVisibleRange() ), walk through displayed range, get grid cell pointers using the CExtGridWnd::GridCellGet() method and compare returned pointers with the this pointer of grid cell which is renewed/updated. So, this should enough quickly compute row/column indexes of the grid cell if it’s visible inside the grid’s client area. We suspect your grid cells may know column index. If yes, then the search algorithm is even faster. You can invoke the CExtGridWnd::GridCellRectsGet() method to get the rectangular area of the grid cell in the client coordinates of the grid window for using as parameter of the InvalidateRect() API.
|
|
Offer Har
|
May 4, 2009 - 6:23 PM
|
Dear Support, Thanks for all you details answers, I think we are ready now to go and implement this solution. Ron.
|
|
Technical Support
|
Apr 29, 2009 - 11:43 AM
|
Please let us know what you need to repaint in your grid cell class? There are lot of virtual methods in the CExtGridCell class for painting it and its parts. The entire grid cell is painted in two steps using the CExtGridCell::OnPaintBackground() and CExtGridCell::OnPaintForeground() virtual methods. Last one invokes many other CExtGridCell::OnPaint***() virtual methods for painting cell parts.
|
|
Offer Har
|
Apr 29, 2009 - 11:49 AM
|
I new the cell to redraw itself when the data in it changes, all its parts (buttons, text, colors, bitmaps... everything) So, if I’m in a cell’s scope this will be enough?: void CMyCell::UpdateMe() { // Do some changes to cell’s string & color etc. ... // Now re-paint the cell: OnPaintBackground();
OnPaintForeground();
}
Thanks, Ron.
|
|
Technical Support
|
Apr 30, 2009 - 6:39 AM
|
Your method should look like:
void CMyCell::UpdateMe( CExtGridWnd & wndGrid, LONG nColNo, LONG nRowNo, INT nColType = 0, INT nRowType = 0, bool bUpdateNow = false )
{
// Do some changes to cell’s string & color etc.
. . .
If( wndGrid.GetSafeHwnd() == NULL )
return;
CRect _rcRedraw;
if( wndGrid.GridCellRectsGet( nColNo, nRowNo, nColType, nRowType, NULL, & rcRedraw ) )
return; // cell is outside visible range
wndGrid.InvalidateRect( &rcRedraw );
if( bUpdateNow )
wndGrid.UpdateWindow();
}
|
|
Offer Har
|
May 3, 2009 - 6:24 AM
|
Dear Support, I saw your mail about the steps I need to take to make a cell paint itself. 1. It’s a little hard for me to understand why thei partition between cells and the grid is needed - can give an example? 2. I still don’t understand how your solution to pass the grid wnd class to the cell will do - from your answer, I need also the row, col, ro type, col type tec etc. 3. Why isn’t calling OnPaintBackgound() & OnPaintForground() from the cell enough, as you suggested at the beginning? Ron.
|
|
Technical Support
|
May 3, 2009 - 2:20 PM
|
As we said, the grid and data provider in Prof-UIS are similar to the view and document in MFC. If you understand the MFC’s document view architecture design, you should understand the design of grids in Prof-UIS. What you need is your grid and data provider classes. We will declare both of them preliminary:
class CYourDataProvider;
class CYourGrid;
Here is the data provider: // in .h file
class CYourDataProvider : public CExtMDP < CExtGridDataProviderMemory >
{
public:
DECLARE_DYNCREATE( CYourDataProvider );
CYourGrid & m_wndGrid;
CYourDataProvider( CYourGrid & wndGrid )
: m_wndGrid( wndGrid )
{
}
};
// in .cpp file
IMPLEMENT_DYNCREATE( CYourDataProvider, CExtGridDataProviderMemory );
Here is the grid: // in .h file
class CYourGrid : public CExtGridWnd
{
public:
DECLARE_DYNCREATE( CYourGrid );
virtual CExtGridDataProvider & OnGridQueryDataProvider()
{
ASSERT_VALID( this );
if( m_pDataProvider != NULL )
{
ASSERT_VALID( m_pDataProvider );
return (*m_pDataProvider);
}
m_pDataProvider = new CYourDataProvider( *this );
ASSERT_VALID( m_pDataProvider );
return (*m_pDataProvider);
}
};
// in .cpp file
IMPLEMENT_DYNCREATE( CYourGrid, CExtGridWnd );
That is enough to let any method of your grid cell classes to invoke the following code: void CSomeYourGridCell::SomeMethod()
{
. . .
CYourDataProvider * pDP = STATIC_DOWNCAST( CYourDataProvider, DataProviderGet() );
CYourGridWnd & wndGrid = pDP->m_wndGrid;
. . .
}
Now your grid cells know the grid window object reference. But we think this approach is not good and you should pass the grid window as parameter. The grid cells does not know their location in the grid window and you may need to repaint entire grid. The grid cells cannot know their location because the row/column insertion and sorting routines will require resetting of location information in many cell objects what should make the grid window million times slower.
|
|
Offer Har
|
May 4, 2009 - 7:51 AM
|
OK, I understand that you do not encourage me to use this solution. Maybe you can help me find other solution for the problem I am facing: 1. I have a control-bar with a grid. 2. Some cells in the grid are drop-list cells or text cells , which preset objects in our system. 3. Objects can be added, removed or renamed. 4. The system is distributed over LAN - the objects can be added/removed/renamed in any station. This is the problem: A. In the grid the user selected object X B. In a remote station somebody renamed object X or removed object X. C. The cell needs to immediately display the name name of object X, or remove the selection if object X is deleted from the system. I have observers to assist me, or I can run in a loop and update all cells: 1. If I use observers, then the cell is the one that gets the notification, and this is the problem I am currently facing. 2. If I run in a loop over all cells, I need some virtrual function added to the all base cell class like virtual bool Update() , that will check the cell for changes, and will return true if the grid needs to be refreshed (change in data of the cell), this approach will involoved changing the code in Prof-UIS library which I rather not do. What do you suggest? Thanks, Ron.
|
|
Technical Support
|
May 4, 2009 - 11:34 AM
|
The first thing to check before updating the grid on particular computer is whether the grid is running some in place cell editor using the CExtGridBaseWnd::GetSafeInplaceActiveHwnd() method. If this method returns non-NULL window handle, then you should send the WM_CANCELMODE message to it. Now there is no cell editing and you can update the grid. The row removing will repaint the grid. You can check whether the row to be removed is focused and move focus to the next row using the CExtGridBaseWnd::FocusGet() / CExtGridBaseWnd::FocusSet() . This will keep some row focused in the grid and this is the good style. You don’t need to check whether the row selected. The selection is synchronized automatically. Next task is updating the renamed and/or somehow modified rows. This task should be performed in the different way, not like you described. Please define some message like:
#define WM_SYNCHRONIZE_MY_GRID (WM_USER+123)
Then please add the message handler for this message. The handler method will do the following things: 1) It will invoke the grid’s CExtScrollItemWnd::OnSiwGetVisibleRange() method which returns the CRect object describing ranges of rows and columns currently displayed in grid’s client area. The grid is displaying rows with indices from CRect::top to CRect::bottom (including first and last). 2) Next thing is walk through the rows in range [ CRect::top . . . CRect::bottom ] and update object names and/or their values. 3) Additionally, you can immediately return from the handler method if the grid window has no the WS_VISIBLE standard window style. We will explain you why this is the good idea closer to the bottom of this message. That’s all what the WM_SYNCHRONIZE_MY_GRID message handler should do. It’s work should always be finished very fast because the number of rows displayed in the grid’s client area is always not large. The next thing is to send the WM_SYNCHRONIZE_MY_GRID message to the grid window everywhere it’s needed. This message should be sent when the grid is scrolled vertically, resized, displayed and when some other computer in your application notified this computer about changes. So, you should handle the WM_VSCROLL , WM_SIZE and WM_SHOWWINDOW messages. Each message handler should invoke the parent class method and then just send the WM_SYNCHRONIZE_MY_GRID message to the grid window. That’s finally all. But, of course, there are some space for optimizations is left. The good idea is to keep the list of some objects describing the grid modification actions to do in the WM_SYNCHRONIZE_MY_GRID message handler. This message handler method should not do anything if there are no modification commands present in the list. In conclusion, this design does not need to keep row/column numbers in your grid cell classes. You don’t need to keep the map from row indices to grid objects/rows and this means your grid can be quickly sorted. If you need to bind some additional data to each row, then you can add some outer header column at left or right, make it zero pixels widths and keep grid cell objects of your type there. These header grid cells can describe anything additional related to each grid row. For instance, you may have some Object Name column in your grid but the text strings in this column are just user friendly object names and they are not the internal technical names used in data exchange between computer names in your network. This means you may need to keep internal technical names somewhere and additional zero width header column with your cell objects is the very good place for such technical information. Besides, the row removing and renaming commands handled by the WM_SYNCHRONIZE_MY_GRID message handler may have technical object names and specifications - not the user friendly names. So, when the WM_SYNCHRONIZE_MY_GRID message handler walks through the displayed names, it should compare technical object names in the renaming command description object with the technical object name in you cell object stored in the zero width header column. Each renaming command description object should be removed from the list of commands after handling. This means the list of commands will be empty only when the user will scroll vertically through entire grid. But this is optimal solution because you don’t need to walk through all the grid each time when some object is renamed. Please note, when adding such renaming command into the commands list you should first walk through the command list and remove previous renaming command of the same object. This will allow you to keep the list of commands more compact.
|
|
Offer Har
|
May 4, 2009 - 11:47 AM
|
Dear Support, I have a problem with the modification of cell’s data as you descripbed it. The grid is a container, it does not know what kinds of cells there are in it - we have a lot of customized cells... they read data from different locations, display different color, images and names. The only way for the grid to update the content of the cells is by asking the cells to do it, that’s why I need some virtual Update function that the cells will invoke. It’s impossible for anybody to send this message - think of it as a database that have many views - the database does not know who is looking at what piece of data - only the viewers can do that - that’s why we use the subject/observer pattern, so that data will be left alone... Also, the data is not plain text - there are images, colors, drop lists elemnts that are removed (not a row removed, but an item in a drop-list that was the selected item) And fianly, this database have a lot of different tables. so each cell type knows how to look at a specif table to decide row to display a row in this table (again, name, color, image, tool-tip and so on). One grid can display data in cell from location table and in another cell data from a user table. I still think there is no way your design will work in this complex scenario... Thanks, Ron.
|
|
tera tera
|
Apr 28, 2009 - 3:55 AM
|
Hello. Will not the appointment of the paper be possible from a program? Thanks
|
|
Technical Support
|
Apr 28, 2009 - 12:20 PM
|
Sorry but it is not supported.
|
|
tera tera
|
Apr 30, 2009 - 6:11 PM
|
Hello. Cannot you set it by the following programs?
Is there a problem? CWinApp* pWinApp=AfxGetApp(); // Get default printer settings.
PRINTDLG pd;
pd.lStructSize = (DWORD) sizeof(PRINTDLG);
if ( ! pWinApp->GetPrinterDeviceDefaults(&pd) ){
return -1;
} // Lock memory handle.
DEVMODE FAR* pDevMode =
(DEVMODE FAR*)::GlobalLock( pd.hDevMode );
LPDEVNAMES lpDevNames;
LPTSTR lpszDriverName, lpszDeviceName, lpszPortName;
HANDLE hPrinter; if (pDevMode){
// Unlock memory handle.
lpDevNames = (LPDEVNAMES)GlobalLock(pd.hDevNames);
lpszDriverName = (LPTSTR )lpDevNames + lpDevNames->wDriverOffset;
lpszDeviceName = (LPTSTR )lpDevNames + lpDevNames->wDeviceOffset;
lpszPortName = (LPTSTR )lpDevNames + lpDevNames->wOutputOffset; ::OpenPrinter(lpszDeviceName, &hPrinter, NULL); if ( Check_Paper ( hPrinter , m_iSize ) == 0 ){
pDevMode->dmPaperSize = m_iSize;
}
if ( Check_PaperOrientation ( hPrinter , m_iOrient ) == 0 ){
pDevMode->dmOrientation = m_iOrient;
} ::DocumentProperties(NULL,hPrinter,lpszDeviceName,pDevMode,
pDevMode, DM_IN_BUFFER|DM_OUT_BUFFER); // Sync the pDevMode.
// See SDK help for DocumentProperties for more info.
::ClosePrinter(hPrinter);
GlobalUnlock( pd.hDevNames );
GlobalUnlock( pd.hDevMode );
}
|
|
Technical Support
|
May 2, 2009 - 12:50 PM
|
We are sorry but we cannot use this code because it works with ANSI/MBCS versions of MFC and does not work with Unicode MFC.
|
|
tera tera
|
Apr 27, 2009 - 7:11 PM
|
|
|
Technical Support
|
May 3, 2009 - 2:23 PM
|
We are working on this issue.
|
|
Kevin Eshbach
|
Apr 27, 2009 - 9:44 AM
|
Our product uses Prof-UIS for the docking, floating, etc. windows and I have been running our application under Purify to see if anything bad is happening and Purify flagged an uninitialized memory read in ExtCreateRegion. I’ve attached a call stack with the problem. I looked at the code and everything seems to be fine. Can you confirm my findings that Purify is returning a bogus message? If no problem is present would it be possible to tweak the code in the future so Purify won’t flag it again? [W] UMR: Uninitialized memory read in ExtCreateRegion {1 occurrence}
Reading 2784 bytes from 0x00211438 (2784 bytes at 0x00211438 uninitialized)
Address 0x00211438 is argument #3 of ExtCreateRegion
Address 0x00211438 is 448 bytes into a 3232 byte block at 0x00211278
Address 0x00211438 points to a Global/LocalAlloc’d block
Thread ID: 0x1f0
Error location
[c:\windows\system32\gDI32.DLL ip=0x67F11DCC]
CExtBitmap::GenerateColorHRGN(bool,DWORD,DWORD)const [d:\code\thirdparty\foss\prof-uis\agi\2.82\src\extcmdicon.cpp:5903]
sizeof(RGNDATAHEADER)
+ (sizeof(RECT) * nMaxParts),
pRgnData
=> );
if( hRgnResult != NULL )
{
::CombineRgn(
CExtBitmap::GenerateColorHRGN(bool,DWORD,DWORD)const [d:\code\thirdparty\foss\prof-uis\agi\2.82\src\extcmdicon.cpp:5751]
CExtPaintManager::DockMarkerBase::CreateFromBitmaps(CRect,eDockMarkerType_t::CExtPaintManager,DWORD,CExtBitmap const&,CExtBitmap const&) [d:\code\thirdparty\foss\prof-uis\agi\2.82\src\extpaintmanager2.cpp:8972]
CExtPaintManager::DockMarkerBase::CreateFromBitmapResources(CRect,eDockMarkerType_t::CExtPaintManager,DWORD,char const*,char const*,char const*,char const*,HINSTANCE__ *,HINSTANCE__ *) [d:\code\thirdparty\foss\prof-uis\agi\2.82\src\extpaintmanager2.cpp:8887]
CExtPaintManager::DockMarkerBeta2::Create(bool,eDockMarkerType_t::CExtPaintManager,CRect) [d:\code\thirdparty\foss\prof-uis\agi\2.82\src\extpaintmanager2.cpp:9901]
CExtPaintManager::DockMarkerBase::Create(bool,eDockMarkerType_t::CExtPaintManager,CRect) [d:\code\thirdparty\foss\prof-uis\agi\2.82\src\extpaintmanager2.cpp:9735]
CExtPaintManager::DockMarker_CreateWnds(HWND__ *,eDockMarkerType_t::CExtPaintManager,CRect,CTypedPtrArray<CPtrArray,CExtDynDockMarkerWnd *>&,int,CExtDynDockMarkerWnd *) [d:\code\thirdparty\foss\prof-uis\agi\2.82\src\extpaintmanager2.cpp:10662]
CExtDynDockMarkerWnd::CreateOuterMarkers(CFrameWnd *,bool,CExtPaintManager *) [d:\code\thirdparty\foss\prof-uis\agi\2.82\src\extcontrolbar.cpp:24146]
CAgUiDynamicControlBar::_DraggingStart(CPoint const&,CPoint const&,CSize) [c:\dev\agimain\source\uif\utilities\aguipersutilities\aguidynamiccontrolbar.cpp:1236]
CExtControlBar::OnLButtonDown(UINT,CPoint) [d:\code\thirdparty\foss\prof-uis\agi\2.82\src\extcontrolbar.cpp:10143]
CWnd::OnWndMsg(UINT,UINT,long,long *) [f:\sp\vctools\vc7libs\ship\atlmfc\src\mfc\wincore.cpp:2167]
CWnd::WindowProc(UINT,UINT,long) [f:\sp\vctools\vc7libs\ship\atlmfc\src\mfc\wincore.cpp:1741]
CControlBar::WindowProc(UINT,UINT,long) [f:\sp\vctools\vc7libs\ship\atlmfc\src\mfc\barcore.cpp:504]
CExtControlBar::WindowProc(UINT,UINT,long) [d:\code\thirdparty\foss\prof-uis\agi\2.82\src\extcontrolbar.cpp:8641]
Allocation location
[C:\WINDOWS\system32\KERNEL32.DLL ip=0x6C802140]
CExtBitmap::GenerateColorHRGN(bool,DWORD,DWORD)const [d:\code\thirdparty\foss\prof-uis\agi\2.82\src\extcmdicon.cpp:5764]
CExtBitmap::GenerateColorHRGN(bool,DWORD,DWORD)const [d:\code\thirdparty\foss\prof-uis\agi\2.82\src\extcmdicon.cpp:5751]
CExtPaintManager::DockMarkerBase::CreateFromBitmaps(CRect,eDockMarkerType_t::CExtPaintManager,DWORD,CExtBitmap const&,CExtBitmap const&) [d:\code\thirdparty\foss\prof-uis\agi\2.82\src\extpaintmanager2.cpp:8972]
CExtPaintManager::DockMarkerBase::CreateFromBitmapResources(CRect,eDockMarkerType_t::CExtPaintManager,DWORD,char const*,char const*,char const*,char const*,HINSTANCE__ *,HINSTANCE__ *) [d:\code\thirdparty\foss\prof-uis\agi\2.82\src\extpaintmanager2.cpp:8887]
CExtPaintManager::DockMarkerBeta2::Create(bool,eDockMarkerType_t::CExtPaintManager,CRect) [d:\code\thirdparty\foss\prof-uis\agi\2.82\src\extpaintmanager2.cpp:9901]
CExtPaintManager::DockMarkerBase::Create(bool,eDockMarkerType_t::CExtPaintManager,CRect) [d:\code\thirdparty\foss\prof-uis\agi\2.82\src\extpaintmanager2.cpp:9735]
CExtPaintManager::DockMarker_CreateWnds(HWND__ *,eDockMarkerType_t::CExtPaintManager,CRect,CTypedPtrArray<CPtrArray,CExtDynDockMarkerWnd *>&,int,CExtDynDockMarkerWnd *) [d:\code\thirdparty\foss\prof-uis\agi\2.82\src\extpaintmanager2.cpp:10662]
CExtDynDockMarkerWnd::CreateOuterMarkers(CFrameWnd *,bool,CExtPaintManager *) [d:\code\thirdparty\foss\prof-uis\agi\2.82\src\extcontrolbar.cpp:24146]
CAgUiDynamicControlBar::_DraggingStart(CPoint const&,CPoint const&,CSize) [c:\dev\agimain\source\uif\utilities\aguipersutilities\aguidynamiccontrolbar.cpp:1236]
|
|
Technical Support
|
Apr 28, 2009 - 2:40 AM
|
The CExtBitmap::GenerateColorHRGN() and CExtPaintManager::stat_HBITMAPtoHRGN() methods in Prof-UIS are generating the HRGN handles using the ::ExtCreateRegion() Win32 API which uses pre-allocated memory buffers containing the RGNDATAHEADER header data structure and chain of RECT data structures. The size of chain is computed dynamically and has some allocation align. As result, some chains at the rest of allocated memory block can be unused and really uninitialized. We believe the GDI should not try to access this rest of chain because the RGNDATAHEADER header contains information about correct number of used and initialized RECT data structures. The Purify and DevPartner systems does not always perform correct detection of uninitialized memory access in such cases. But we improved the CExtBitmap::GenerateColorHRGN() and CExtPaintManager::stat_HBITMAPtoHRGN() methods and made them filling the just allocated or re-allocated HGLOBAL memory with zero values. This should make these methods compatible with Purify and DevPartner systems.
HRGN CExtBitmap::GenerateColorHRGN(
bool bRTL,
COLORREF clrTransparent,
COLORREF clrTolerance // = RGB(0,0,0)
) const
{
if( IsEmpty() )
{
ASSERT( FALSE );
return NULL;
}
ULONG nBPP = GetBPP();
if( nBPP != 32 )
{
CExtBitmap other = (*this);
other.Make32(false);
return other.GenerateColorHRGN( bRTL, clrTransparent, clrTolerance );
}
CSize _sizeBitmap = GetSize();
ULONG nScanLineSize = stat_RcScanLineSize( _sizeBitmap.cx, nBPP ); LPBYTE p32bitColorSurface = stat_RcSurface( m_pImageBuffer );
ASSERT( p32bitColorSurface != NULL );
static DWORD g_nReallocSize = ( g_PaintManager.m_bIsWinNT4 ? 1 : 200 ); DWORD nMaxParts = g_nReallocSize; HANDLE hGlobal = ::GlobalAlloc( GMEM_MOVEABLE, sizeof(RGNDATAHEADER) + (
sizeof(RECT) * nMaxParts ) );
RGNDATA * pRgnData = (RGNDATA *) ::GlobalLock( hGlobal );
::memset( LPVOID(pRgnData), 0, sizeof(RGNDATAHEADER) + (
sizeof(RECT) * nMaxParts ) );
pRgnData->rdh.dwSize = sizeof(RGNDATAHEADER);
pRgnData->rdh.iType = RDH_RECTANGLES;
pRgnData->rdh.nCount = pRgnData->rdh.nRgnSize = 0;
::SetRect( &pRgnData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0 );
BYTE nLowRed = GetRValue( clrTransparent );
BYTE nLowGreen = GetGValue( clrTransparent );
BYTE nLowBlue = GetBValue( clrTransparent );
BYTE nHighRed = BYTE( min( 0xff, ( nLowRed + GetRValue(clrTolerance) ) )
);
BYTE nHighGreen = BYTE( min( 0xff, ( nLowGreen + GetGValue(clrTolerance) ) )
);
BYTE nHighBlue = BYTE( min( 0xff, ( nLowBlue + GetBValue(clrTolerance) ) )
);
HRGN hRgnResult = NULL;
for( INT _nY = 0; _nY < _sizeBitmap.cy; _nY++ )
{
INT nY = _sizeBitmap.cy - _nY - 1;
for( INT nX = 0; nX < _sizeBitmap.cx; nX++ )
{
LPLONG ptrLinePart = (LPLONG)p32bitColorSurface + nX;
INT nSavedX = nX;
for( ; nX < _sizeBitmap.cx; ptrLinePart++, nX++ )
{
BYTE nColorPart = GetRValue( (*ptrLinePart) );
if( nColorPart >= nLowRed && nColorPart <= nHighRed )
{
nColorPart = GetGValue(
(*ptrLinePart) );
if( nColorPart >= nLowGreen &&
nColorPart <= nHighGreen )
{
nColorPart = GetBValue(
(*ptrLinePart) );
if( nColorPart >= nLowBlue
&& nColorPart <= nHighBlue )
break;
} // if( nColorPart >= nLowGreen && nColorPart <= nHighGreen )
} // if( nColorPart >= nLowRed && nColorPart <= nHighRed )
} // for( ; nX < _sizeBitmap.cx; ptrLinePart++, nX++
)
if( nX > nSavedX )
{
if( pRgnData->rdh.nCount >= nMaxParts )
{
::GlobalUnlock( hGlobal );
DWORD dwPrevParts = nMaxParts;
nMaxParts += g_nReallocSize;
hGlobal = ::GlobalReAlloc( hGlobal,
sizeof(RGNDATAHEADER) + (sizeof(RECT) * nMaxParts), GMEM_MOVEABLE );
pRgnData = (RGNDATA *) ::GlobalLock( hGlobal );
::memset( LPVOID( LPBYTE(pRgnData) +
sizeof(RGNDATAHEADER) + ( sizeof(RECT) * dwPrevParts ) ), 0, sizeof(RECT) * ( nMaxParts - dwPrevParts ) );
} // if( pRgnData->rdh.nCount >= nMaxParts )
LPRECT pRect = (LPRECT)&pRgnData->Buffer;
::SetRect( &pRect[pRgnData->rdh.nCount], nSavedX, nY, nX, nY + 1 );
if( nSavedX < pRgnData->rdh.rcBound.left )
pRgnData->rdh.rcBound.left =
nSavedX;
if( nY < pRgnData->rdh.rcBound.top )
pRgnData->rdh.rcBound.top = nY;
if( nX > pRgnData->rdh.rcBound.right )
pRgnData->rdh.rcBound.right = nX;
if( (nY + 1) > pRgnData->rdh.rcBound.bottom
)
pRgnData->rdh.rcBound.bottom = nY+1;
pRgnData->rdh.nCount ++;
if( pRgnData->rdh.nCount == DWORD(
g_PaintManager.m_bIsWinNT4 ? 1 : 2000 ) )
{
if( bRTL )
{
INT nPart, nLeft, nRight,
nCount = INT( pRgnData->rdh.nCount );
LPRECT pRect =
(LPRECT)&pRgnData->Buffer;
for( nPart = 0; nPart <
nCount; nPart ++, pRect ++ )
{
nLeft =
_sizeBitmap.cx - pRect->left;
nRight =
_sizeBitmap.cx - pRect->right;
pRect->right =
nLeft;
pRect->left =
nRight;
} // for( nPart = 0; nPart <
nCount; nPart ++, pRect ++ )
} // if( bRTL )
HRGN hRgnPart = ::ExtCreateRegion(
NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * nMaxParts), pRgnData );
if( hRgnResult != NULL )
{
::CombineRgn( hRgnResult,
hRgnResult, hRgnPart, RGN_OR );
::DeleteObject( hRgnPart );
} // if( hRgnResult != NULL )
else
hRgnResult = hRgnPart;
pRgnData->rdh.nCount = 0;
::SetRect( &pRgnData->rdh.rcBound,
MAXLONG, MAXLONG, 0, 0 );
} // if( pRgnData->rdh.nCount == (
g_PaintManager.m_bIsWinNT4 ? 1 : 2000 ) )
} // if( nX > nSavedX )
} // for( INT nX = 0; nX < _sizeBitmap.cx; nX++ )
p32bitColorSurface += nScanLineSize;
} // for( INT _nY = 0; _nY < _sizeBitmap.cy; _nY++ )
if( bRTL )
{
INT nPart, nLeft, nRight, nCount = INT( pRgnData->rdh.nCount );
LPRECT pRect = (LPRECT)&pRgnData->Buffer;
for( nPart = 0; nPart < nCount; nPart ++, pRect ++ )
{
nLeft = _sizeBitmap.cx - pRect->left;
nRight = _sizeBitmap.cx - pRect->right;
pRect->right = nLeft;
pRect->left = nRight;
} // for( nPart = 0; nPart < nCount; nPart ++, pRect ++ )
} // if( bRTL )
HRGN hRgnPart = ::ExtCreateRegion( NULL, sizeof(RGNDATAHEADER) +
(sizeof(RECT) * nMaxParts), pRgnData );
if( hRgnResult != NULL )
{
::CombineRgn( hRgnResult, hRgnResult, hRgnPart, RGN_OR );
::DeleteObject( hRgnPart );
} // if( hRgnResult != NULL )
else
hRgnResult = hRgnPart;
::GlobalFree( hGlobal );
return hRgnResult;
}
HRGN CExtPaintManager::stat_HBITMAPtoHRGN(
HBITMAP hBitmap,
COLORREF clrTransparent,
COLORREF clrTolerance // = RGB(0,0,0)
)
{
if( hBitmap == NULL )
{
ASSERT( FALSE );
return NULL;
} // if( hBitmap == NULL )
HDC hDstDC = ::CreateCompatibleDC( NULL );
if( hDstDC == NULL )
{
ASSERT( FALSE );
return NULL;
} // if( hDstDC == NULL )
BITMAP _bmpInfoSrcBmp;
::memset( &_bmpInfoSrcBmp, 0, sizeof(BITMAP) );
::GetObject( hBitmap, sizeof(BITMAP), &_bmpInfoSrcBmp ); BITMAPINFOHEADER _bmpInfoHdr = {
sizeof(BITMAPINFOHEADER),
_bmpInfoSrcBmp.bmWidth,
_bmpInfoSrcBmp.bmHeight,
1,
32,
BI_RGB,
0,
0,
0,
0,
0
};
LPVOID p32bitColorSurface = NULL;
HBITMAP hDstDIB = ::CreateDIBSection( hDstDC, (BITMAPINFO *)&_bmpInfoHdr, DIB_RGB_COLORS, &p32bitColorSurface, NULL, 0 );
if( hDstDIB == NULL )
{
ASSERT( FALSE );
::DeleteDC( hDstDC );
return NULL;
} // if( hDstDIB == NULL )
ASSERT( p32bitColorSurface != NULL );
HBITMAP hOldDst = (HBITMAP) ::SelectObject( hDstDC, hDstDIB ); HDC hSrcDC = ::CreateCompatibleDC( hDstDC );
if( hSrcDC == NULL )
{
ASSERT( FALSE );
::DeleteObject( ::SelectObject( hDstDC, hOldDst ) );
::DeleteDC( hDstDC );
return NULL;
} // if( hSrcDC == NULL )
BITMAP _bmpInfoDstDIB;
::memset( &_bmpInfoDstDIB, 0, sizeof(BITMAP) );
::GetObject( hDstDIB, sizeof(BITMAP), &_bmpInfoDstDIB );
for( ; (_bmpInfoDstDIB.bmWidthBytes % 4) != 0; _bmpInfoDstDIB.bmWidthBytes ++ ); HBITMAP hOldSrc = (HBITMAP) ::SelectObject( hSrcDC, hBitmap );
::BitBlt( hDstDC, 0, 0, _bmpInfoSrcBmp.bmWidth, _bmpInfoSrcBmp.bmHeight, hSrcDC, 0, 0, SRCCOPY ); static const DWORD g_nReallocSize = 200; DWORD nMaxParts = g_nReallocSize; HANDLE hGlobal = ::GlobalAlloc( GMEM_MOVEABLE, sizeof(RGNDATAHEADER) + (
sizeof(RECT) * nMaxParts ) );
RGNDATA * pRgnData = (RGNDATA *) ::GlobalLock( hGlobal );
::memset( LPVOID(pRgnData), 0, sizeof(RGNDATAHEADER) + (
sizeof(RECT) * nMaxParts ) );
pRgnData->rdh.dwSize = sizeof(RGNDATAHEADER);
pRgnData->rdh.iType = RDH_RECTANGLES;
pRgnData->rdh.nCount = pRgnData->rdh.nRgnSize = 0;
::SetRect( &pRgnData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0 );
BYTE nLowRed = GetRValue( clrTransparent );
BYTE nLowGreen = GetGValue( clrTransparent );
BYTE nLowBlue = GetBValue( clrTransparent );
BYTE nHighRed = BYTE( min( 0xff, ( nLowRed + GetRValue(clrTolerance) ) )
);
BYTE nHighGreen = BYTE( min( 0xff, ( nLowGreen + GetGValue(clrTolerance) ) )
);
BYTE nHighBlue = BYTE( min( 0xff, ( nLowBlue + GetBValue(clrTolerance) ) )
);
BYTE * pDstColorSurface = (BYTE *)_bmpInfoDstDIB.bmBits + (_bmpInfoDstDIB.bmHeight - 1) * _bmpInfoDstDIB.bmWidthBytes; HRGN hRgnResult = NULL;
for( int nY = 0; nY < _bmpInfoSrcBmp.bmHeight; nY++ )
{
for( int nX = 0; nX < _bmpInfoSrcBmp.bmWidth; nX++ )
{
LPLONG ptrLinePart = (LPLONG)pDstColorSurface + nX;
int nSavedX = nX;
for( ; nX < _bmpInfoSrcBmp.bmWidth; ptrLinePart++,
nX++ )
{
BYTE nColorPart = GetRValue( (*ptrLinePart) );
if( nColorPart >= nLowRed && nColorPart <= nHighRed )
{
nColorPart = GetGValue(
(*ptrLinePart) );
if( nColorPart >= nLowGreen &&
nColorPart <= nHighGreen )
{
nColorPart = GetBValue(
(*ptrLinePart) );
if( nColorPart >= nLowBlue
&& nColorPart <= nHighBlue )
break;
} // if( nColorPart >= nLowGreen && nColorPart <= nHighGreen )
} // if( nColorPart >= nLowRed && nColorPart <= nHighRed )
} // for( ; nX < _bmpInfoSrcBmp.bmWidth;
ptrLinePart++, nX++ )
if( nX > nSavedX )
{
if( pRgnData->rdh.nCount >= nMaxParts )
{
::GlobalUnlock( hGlobal );
DWORD dwPrevParts = nMaxParts;
nMaxParts += g_nReallocSize;
hGlobal = ::GlobalReAlloc( hGlobal,
sizeof(RGNDATAHEADER) + (sizeof(RECT) * nMaxParts), GMEM_MOVEABLE );
pRgnData = (RGNDATA *) ::GlobalLock( hGlobal );
::memset( LPVOID( LPBYTE(pRgnData) +
sizeof(RGNDATAHEADER) + ( sizeof(RECT) * dwPrevParts ) ), 0, sizeof(RECT) * ( nMaxParts - dwPrevParts ) );
} // if( pRgnData->rdh.nCount >= nMaxParts )
LPRECT pRect = (LPRECT)&pRgnData->Buffer;
::SetRect( &pRect[pRgnData->rdh.nCount], nSavedX, nY, nX, nY + 1 );
if( nSavedX < pRgnData->rdh.rcBound.left )
pRgnData->rdh.rcBound.left =
nSavedX;
if( nY < pRgnData->rdh.rcBound.top )
pRgnData->rdh.rcBound.top = nY;
if( nX > pRgnData->rdh.rcBound.right )
pRgnData->rdh.rcBound.right = nX;
if( (nY + 1) > pRgnData->rdh.rcBound.bottom
)
pRgnData->rdh.rcBound.bottom = nY+1;
pRgnData->rdh.nCount ++;
if( pRgnData->rdh.nCount == 2000 )
{
HRGN hRgnPart = ::ExtCreateRegion(
NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * nMaxParts), pRgnData );
if( hRgnResult != NULL )
{
::CombineRgn( hRgnResult,
hRgnResult, hRgnPart, RGN_OR );
::DeleteObject( hRgnPart );
} // if( hRgnResult != NULL )
else
hRgnResult = hRgnPart;
pRgnData->rdh.nCount = 0;
::SetRect( &pRgnData->rdh.rcBound,
MAXLONG, MAXLONG, 0, 0 );
} // if( pRgnData->rdh.nCount == 2000 )
} // if( nX > nSavedX )
} // for( int nX = 0; nX < _bmpInfoSrcBmp.bmWidth; nX++ )
pDstColorSurface -= _bmpInfoDstDIB.bmWidthBytes;
} // for( int nY = 0; nY < _bmpInfoSrcBmp.bmHeight; nY++ ) HRGN hRgnPart =
::ExtCreateRegion( NULL, sizeof(RGNDATAHEADER) +
(sizeof(RECT) * nMaxParts), pRgnData );
if( hRgnResult != NULL )
{
::CombineRgn( hRgnResult, hRgnResult, hRgnPart, RGN_OR );
::DeleteObject( hRgnPart );
} // if( hRgnResult != NULL )
else
hRgnResult = hRgnPart;
::GlobalFree( hGlobal );
::SelectObject( hSrcDC, hOldSrc );
::DeleteDC( hSrcDC );
::DeleteObject( ::SelectObject( hDstDC, hOldDst ) );
::DeleteDC( hDstDC );
return hRgnResult;
}
|
|
tera tera
|
Apr 27, 2009 - 1:32 AM
|
Hello. I want to make a ribbon button of such a placement.
Please teach a realization method.
|
|
Technical Support
|
Apr 27, 2009 - 11:04 AM
|
The upper 3 buttons is a tool group like the Bold Italic Underline tool group in the RibbonBar sample. The other two buttons are simple ribbon buttons.
Please run the RibbonBar sample application, select the Mailings ribbon tab page and take a look at the Preview Results button group. This group of buttons is very similar to what you need. It contains a tool group of buttons with media player like commands and editor in the center. This tool group is at the top row of the Preview Results button group. The next two rows are occupied by the simple ribbon buttons.
|
|
John Ritzenthaler
|
Apr 24, 2009 - 9:44 AM
|
How can I specify the tooltip text for individual rows in the dropdown list of a CExtComboBox?
|
|
Technical Support
|
Apr 24, 2009 - 1:58 PM
|
The feature you are looking for is definitively not a combo box.
|
|
Offer Har
|
Apr 24, 2009 - 7:41 AM
|
Dear Support, When we have a CExtGridCellComboBox with many items, we see three problems: 1. If there is not enough space to drop down the list, because it’s so big, it will open in the wrong place. 2. If there are many long items in it, it will occupy all the sceen. 3. Sometimes there is a black rectangle at the bottom of the list, if there is a scroll-bar for the list, and there is a place to show only ’half’ item it will fill it with a black rectangle. Which of these issues are you familiar with? Will they be fixed for the next version? When is the next version supposed to be relesed? Is there any way to have a resizaeable drop list? Thanks, Ron.
|
|
Technical Support
|
Apr 24, 2009 - 12:19 PM
|
The popup list box menus displayed by grid cells and built in text field buttons in toolbars, menus and ribbons are improved in Prof-UIS 2.85. Now these popup list boxes are measured automatically before they displayed on the screen. The new CExtGridCell::OnPopupListBoxQueryMaxSize() virtual method limits the maximal sizes of popup list box menus. As a result, the list box of the combo box cell will be completely under tje cell or over it depending on where the available space is larger. The black rectangle at the bottom issue looks like new. We need more details about how to reproduce it without occasional happy cases. The popup menu supports the TPMX_RIBBON_RESIZING and TPMX_RIBBON_RESIZING_VERTICAL_ONLY flags. They are used by resizable gallery popup menus displayed by ribbon galleries. This style makes resizable any other menus and displays resizing area at the bottom side of the menu like it’s in the ribbon gallery menus, but not all the menus are supporting automatic layout recalculation on resizing. We need to check this additionally for popup list box menus. In the simple case you should overrode the CExtGridCell::OnButtonPopupMenuTrack() virtual method, copy source code from the original method and add the TPMX_RIBBON_RESIZING flag or TPMX_RIBBON_RESIZING|TPMX_RIBBON_RESIZING_VERTICAL_ONLY flags into invocation of the CExtPopupMenuWnd::TrackPopupMenu() method.
|
|
Offer Har
|
Apr 24, 2009 - 6:00 AM
|
Dear Support, I have an CExtResizableDialog derived dialog inside an CExtControlBar derived control-bar. This is the way I create the dialog inside the control-bar derived class:
m_pDockedControl->Create(IDD, this);
CRect rc;
m_pDockedControl->GetClientRect(rc);
SetInitDesiredSizeFloating(CSize(rc.Width(), rc.Height())); I later in the code show the control-bar:
m_pMainFrm->ShowControlBar(pBar, bShow, FALSE);
The problem is that the size of the child dialog does not adjust to the size of the control-bar, so all my controls, that use anchors are not displayed properly.
I checked the size of the control-bar and the dialgo in it:
CRect rc;
pBar->GetClientRect(rc);
CRect rc1;
pBar->m_pDockedControl->GetClientRect(rc1); and saw this for rc: left 0 long
top 0 long
right 354 long
bottom 399 long
and this for rc1: left 0 long
top 0 long
right 32767 long
bottom 32767 long
There is clearly something wring here, as the size of the the child must derive from it parent. Please note that if I resize the control-bar it becomes OK... that means that the child knows its parent, but for some reason it does not resize according to it. Am I doing something wring? Is this a bug? Thanks, Ron.
|
|
Technical Support
|
Apr 24, 2009 - 12:18 PM
|
The CFrameWnd::RecalcLayout() method should be invoked after SetInitDesiredSizeFloating , after CExtControlBar::FrameEnableDocking() and initial docking of all the bars and before querying rectangles. When the CExtControlBar window is just created, then its size and location are temporary and its parent window is the main frame window. But when you completely initialized the main frame window and docked the CExtControlBar window initially, then the control bar’s parent window is some control bar container window (CExtDockBar in Prof-UIS, CDockBar in MFC).
|
|
Hendrik Stephani
|
Apr 24, 2009 - 5:43 AM
|
I have used code to make my framewindow snapping to other windows. I use the WM_ENTERSIZEMOVE and WM_EXITSIZEMOVE to get the information about entering and leaving the move/size mode and the WM_MOVING and the WM_SIZING message the adjust the windows to each other. Since I use Prof-UIS framewindow (deriving from CExtNCW<CFrameWnd>) I don’t get the WM_MOVING and WM_SIZING messages anymore. What am I doing wrong?
|
|
Technical Support
|
Apr 24, 2009 - 12:20 PM
|
Thank you for reporting this issue. The WM_MOVING and WM_SIZING messages are sent by Prof-UIS 2.85. You can request the pre-release version by email.
|
|
tera tera
|
Apr 23, 2009 - 8:34 PM
|
Hello. When DLL is huge and wears a link.
A link error comes. error LNK1210 insufficient memory for incremental link; relink with /INCREMENTAL:NO I want to speed up build time.
So, I want to incremental link
|
|
Technical Support
|
Apr 24, 2009 - 2:00 PM
|
|
|
Maxim Maximov
|
Apr 22, 2009 - 9:03 AM
|
Hello! I just added CExtToolControlBar to my app, here’s initialization: VERIFY(
g_CmdManager->ProfileSetup(
theApp.m_pszProfileName,
GetSafeHwnd() // HWND of the frame window
)
);
VERIFY(
g_CmdManager->UpdateFromToolBar(
theApp.m_pszProfileName,
IDR_MAINFRAME
)
);
VERIFY(
g_CmdManager->UpdateFromMenu(
theApp.m_pszProfileName,
IDR_MAINFRAME)
);
VERIFY(
g_CmdManager->UpdateFromMenu(
theApp.m_pszProfileName,
IDR_ProfitRangerTYPE)
);
if( !m_wndToolBar.Create(
_T( "Toolbar name" ),
this,
AFX_IDW_TOOLBAR
)
|| !m_wndToolBar.LoadToolBar( IDR_MAINFRAME )
)
{
TRACE0( "Failed to create toolbar" );
return -1;
} Toolbar is displayed, but when I press a button, nothing happens (menu works like a charm). What is wrong? 2. I added these lines of code to allow docking:
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
DockControlBar(&m_wndToolBar);
But DockContolBar fails on winfrm2.cpp, line 92:
==
pDockBar = (CDockBar*)GetControlBar(dwDockBarMap[i][0]);
ASSERT(pDockBar != NULL);
== Please, help
|
|
Technical Support
|
Apr 22, 2009 - 11:33 AM
|
First of all, please use the CExtControlBar::FrameEnableDocking() static method for enabling redockable bars in your main frame window instead of the MFC’s CFrameWnd::EnableDocking() method. This note is not related to the m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY); line of code. It would be helpful to take a look at entire CMainFrame::OnCreate() method in your project. We suspect the problem can be hidden somewhere else.
|
|
Maxim Maximov
|
Apr 22, 2009 - 8:20 AM
|
Hello! I have Prof-UIS installed in "D:/Prof-Uis". I added paths manually in "Directories" (Include, Source, Libraries) as explained in documentation. When I link my project (MDI, created with native ClassWizard, MFC Static, Not Using Unicode), I receive following messages:
1>stdafx.cpp
1> Automatically linking with Prof-UIS library: ProfUIS284snd.lib
1> (Professional User Interface Suite)
[skipped]
1>LINK : D:\work\dealing\hedge\ProfitRanger\Debug\ProfitRanger.exe not found or not built by the last incremental link; performing full link
1>ProfUIS284snd.lib(ExtButton.obj) : warning LNK4099: PDB ’vc90.pdb’ was not found with ’d:/Prof-UIS/Bin_900\ProfUIS284snd.lib’ or at ’D:\work\dealing\hedge\ProfitRanger\Debug\vc90.pdb’; linking object as if no debug info
1>ProfUIS284snd.lib(ExtCheckListWnd.obj) : warning LNK4099: PDB ’vc90.pdb’ was not found with ’d:/Prof-UIS/Bin_900\ProfUIS284snd.lib’ or at ’D:\work\dealing\hedge\ProfitRanger\Debug\vc90.pdb’; linking object as if no debug info
1>ProfUIS284snd.lib(ExtCmdIcon.obj) : warning LNK4099: PDB ’vc90.pdb’ was not found with ’d:/Prof-UIS/Bin_900\ProfUIS284snd.lib’ or at ’D:\work\dealing\hedge\ProfitRanger\Debug\vc90.pdb’; linking object as if no debug info
1>ProfUIS284snd.lib(ExtCmdManager.obj) : warning LNK4099: PDB ’vc90.pdb’ was not found with ’d:/Prof-UIS/Bin_900\ProfUIS284snd.lib’ or at ’D:\work\dealing\hedge\ProfitRanger\Debug\vc90.pdb’; linking object as if no debug info
1>ProfUIS284snd.lib(ExtColorCtrl.obj) : warning LNK4099: PDB ’vc90.pdb’ was not found with ’d:/Prof-UIS/Bin_900\ProfUIS284snd.lib’ or at ’D:\work\dealing\hedge\ProfitRanger\Debug\vc90.pdb’; linking object as if no debug info
And so on.
So, in debug mode I cannot step into Prof UIS functions. What is wrong?
|
|
Technical Support
|
Apr 22, 2009 - 11:33 AM
|
Sometimes the PDB files become corrupted or even absent. Please check there is some gigabytes of free space on your drive d:/ and on that drive where your project is. Then please rebuild Prof-UIS and your project completely. If you compiled Prof-UIS on other computer and then moved its compiled libraries into your computer and both computers have different Visual Studio installations due to different installed service packs and updates, then this problem also should disappear after rebuilding Prof-UIS and your project. Such warnings may also appear if your project is trying to link with the Prof-UIS libraries built on older version of Visual C++. One more reason of these warnings is described here: http://social.msdn.microsoft.com/forums/en-US/vcgeneral/thread/7fd0c8d0-dd9d-45cc-9229-a184a2a88c1a
|
|
tera tera
|
Apr 22, 2009 - 4:08 AM
|
Hello. I want to add the footer of multiple lines and the header of multiple lines to PPVW. Thanks,
|
|
Technical Support
|
Apr 22, 2009 - 11:32 AM
|
This feature is not implemented yet. But, in Prof-UIS 2.85 you can reserve additional space at page borders. The CExtPPVW_Printable::m_rcPageMarginsHM property is the rectangle describing outer page margins in MM_HIMETRIC values. These margins are the white empty space near page borders. You can extend these margins and use additional white space for painting your custom content. The CExtPPVW_Printable::OnPrepareDC() virtual method is invoked for each CMetaFileDC of each printed/previewed page.
|
|
tera tera
|
Apr 22, 2009 - 3:57 AM
|
Hello. Cannot PPVW pull a ruled line?
|
|
Technical Support
|
Apr 22, 2009 - 11:32 AM
|
This feature is not implemented yet. But, in Prof-UIS 2.85 you can reserve additional space at page borders. The CExtPPVW_Printable::m_rcPageMarginsHM property is the rectangle describing outer page margins in MM_HIMETRIC values. These margins are the white empty space near page borders. You can extend these margins and use additional white space for painting your custom content. The CExtPPVW_Printable::OnPrepareDC() virtual method is invoked for each CMetaFileDC of each printed/previewed page.
|
|
tera tera
|
Apr 23, 2009 - 3:50 AM
|
Hello. I create a function by myself.
|
|
tera tera
|
Apr 22, 2009 - 3:54 AM
|
Hello. When string protrudes, I lower a font and want to draw a character
|
|
Technical Support
|
Apr 22, 2009 - 11:32 AM
|
We think you should switch to using multi line text. If your text is wider than page widths even with smaller font, then the print previewing subsystem simply cannot help you.
|
|
tera tera
|
Apr 22, 2009 - 7:38 PM
|
Hello. As for the Excel of Microsoft, a character is displayed small. Thanks,
|
|
tera tera
|
Apr 22, 2009 - 3:50 AM
|
Hello. When I use CExtPPVW for a grid, Does the whole disposal of grids become slow?
|
|
Technical Support
|
Apr 22, 2009 - 11:31 AM
|
The CExtPPVW template class simply implements the OnCmdMsg() virtual method for handling/updating the standard ID_FILE_PRINT*** commands. It does not allocate any resources and does not affect the behavior of grid cells. When the print/preview mode is on, the CExtPPVW template class creates an internal preview window inside the grid window. This preview window is destroyed when you close the print/preview mode and all the resources are de-allocated at this moment.
|
|
tera tera
|
Apr 21, 2009 - 7:45 PM
|
Hello. I want to prohibit the float of this bar.
And can you prohibit docking?
|
|
Technical Support
|
Apr 22, 2009 - 11:30 AM
|
Please use a custom CExtControlBar -derived class which implements the CExtControlBar::FloatControlBar() and CExtControlBar::ToggleDocking() virtual methods. Both methods should have empty bodies and should not invoke the parent class methods. But if your control bar is inside a tabbed bar group, you will be able to float entire tabbed bar group. The tabbed bar group is also a kind of resizable control bar. It’s the CExtDynTabControlBar window in case of simple resizable control bars. It’s the CExtDynamicTabbedControlBar in case of dynamic resizable control bars. So, you may need to create a similar class derived from one of these classes with the same virtual methods. In case of simple resizable control bars, to make Prof-UIS using your tabbed bar class you should handle the CExtControlBar::g_nMsgCreateTabbedBar registered message:
class C_YOUR_DynTabControlBar : public CExtDynTabControlBar
{
. . .
};
ON_REGISTERED_MESSAGE( CExtControlBar::g_nMsgCreateTabbedBar, OnMsgCreateTabbedBar )
LRESULT CMainFrame::OnMsgCreateTabbedBar( WPARAM wParam, LPARAM lParam )
{
lParam;
CExtDynTabControlBar ** ppBar = (CExtDynTabControlBar **)wParam;
(*ppBar) = new C_YOUR_DynTabControlBar;
return 0L;
}
In case of dynamic resizable control bars you should implement the CExtDynamicBarSite::OnDbsCreateTabbedBarInstance() virtual method and instantiate your CExtDynamicTabbedControlBar -derived object in it. You can all the bars be docked into the same tabbed group with your non-floating bar. You should override the CExtControlBar::_CanDockToTabbedContainers() virtual method for that and simply return false from it.
|
|