Subject |
Author |
Date |
|
Paul Cowan
|
Aug 20, 2007 - 1:14 PM
|
How can I get a CExtDateTimeWnd control to display in the regional long date format?
|
|
Technical Support
|
Aug 22, 2007 - 11:24 AM
|
The CExtDateTimeWnd::OnInitializeItemsArray() virtual method initializes all the fields in the date time control. It creates all the fields in the sequence which is defined by the currently installed locale. Unfortunately the long date format is not supported yet, but it is possible to override the CExtDurationWnd::OnQueryItemText() virtual method for replacing a month number with the corresponding name.
|
|
David Skok
|
Aug 20, 2007 - 12:16 PM
|
I am using the CExtGridCellInplaceSlider in a CExtGridWnd. I monitor changes in cell value by overriding OnScrollPosSet. If I drag the slider or use Alt+left right arrow keys this function is called with pWndGrid valid which has been working fine. I recently noticed that if I set the value directly by entering the number OnScrollPosSet is called with pWndGrid set to NULL. I need pWndGrid to ultimately get the pointer to the document that needs to be altered. It appears that the only way I can do that in the case of direct entry is by overriding OnInplaceControlTextInputComplete. Is there some other central location that I might catch where the scroll position is being set that includes a valid pWndGrid so that I do not have to override two functions?
|
|
Technical Support
|
Aug 21, 2007 - 6:17 AM
|
Please look at the following method declaration in the CExtGridCellInplaceSlider class: virtual ULONG ScrollPosSet( ULONG nScrollPos );
virtual ULONG OnScrollPosSet(
ULONG nScrollPos,
CExtGridWnd * pWndGrid = NULL,
LONG nColNo = 0L,
LONG nRowNo = 0L,
INT nColType = 0,
INT nRowType = 0
); Here is the source code of the ScrollPosSet() method which simply calls OnScrollPosSet() : ULONG CExtGridCellInplaceSlider::ScrollPosSet( ULONG nScrollPos )
{
ASSERT_VALID( this );
return OnScrollPosSet( nScrollPos );
} That means you can call directly the OnScrollPosSet() method and specify all the needed parameters.
|
|
David Skok
|
Aug 21, 2007 - 7:11 AM
|
Thank you for the response.
I looked further and would like to suggest that you change the source to CExtGridCellInplaceSlider::OnInplaceControlTextInputComplete as follows:
// Remove // ScrollPosSet( nVal );
// Put in it’s place OnScrollPosSet( nVal, &wndGrid, nColNo, nRowNo, nColType, nRowType );
Currently OnScrollPosSet is hit if an individual uses direct entry, drags the slider or uses Alt+arrow keys however in the case of direct entry not all of the parameters are filled in if direct entry is used. Why use ScrollPosSet when it is possible to directly call OnScrollPosSet in OnInplaceControlTextInputComplete. This way a user of this cell type can catch a changed value by overriding one method rather than two and always count on having the parameters filled in. PS - ScrollPosSet is NOT called when a user drags the slider or uses the Alt+arrow keys anyway and even so overriding it is likely to have little value if cells don’t know where they are or what grid they are in.
Just a suggestion.
|
|
Technical Support
|
Aug 22, 2007 - 11:11 AM
|
We are agree with you completely. Thank you. Here is the updated source code void CExtGridCellInplaceSlider::OnInplaceControlTextInputComplete(
HWND hWndInplaceControl,
CExtGridWnd & wndGrid,
LONG nVisibleColNo,
LONG nVisibleRowNo,
LONG nColNo,
LONG nRowNo,
INT nColType,
INT nRowType,
__EXT_MFC_SAFE_LPCTSTR sTextNew,
bool bSaveChanges
)
{
ASSERT_VALID( this );
ASSERT( hWndInplaceControl != NULL && ::IsWindow(hWndInplaceControl) );
ASSERT_VALID( (&wndGrid) );
if( bSaveChanges )
{
TCHAR * strStop = NULL;
ULONG nVal = 0L;
nVal = _tcstoul( LPCTSTR(sTextNew), &strStop, 10 );
if( nVal != ULONG_MAX )
{
if( nVal < 0L )
nVal = 0L;
if( nVal > m_nScrollTotalRange )
nVal = m_nScrollTotalRange;
// ScrollPosSet( nVal );
OnScrollPosSet(
nVal,
&wndGrid,
nColNo,
nRowNo,
nColType,
nRowType
);
}
}
wndGrid.OnGridCellInplaceControlTextInputComplete(
*this,
hWndInplaceControl,
nVisibleColNo,
nVisibleRowNo,
nColNo,
nRowNo,
nColType,
nRowType,
sTextNew,
bSaveChanges
);
}
|
|
Paul Cowan
|
Aug 20, 2007 - 8:56 AM
|
Are there any example of how to add a toolbar to a dialog? I’ve tried, but I only get one button in the middle of the toolbar.
|
|
Paul Cowan
|
Aug 20, 2007 - 2:24 PM
|
OK, thanks. I have the toolbar in the dialog now. Now I have a problem where the ON_UPDATE_COMMAND_UI messages are not beeing called until a button is clicked. After setting false for pCmdUI->Enable, the button can never reenabled.
|
|
Technical Support
|
Aug 21, 2007 - 6:49 AM
|
The command updating mechanism for toolbars and menus used in the dialog window should work exactly like in the frame window and typically you should not do anything special for that. Toolbar buttons are updated by the toolbar’s owner window. By default, the toolbar’s owner window is its parent dialog or frame window. The toolbar’s owner window is detected automatically, but in some cases like non-modal dialogs, you may need to specify the toolbar’s owner window explicitly by invoking its CWnd::SetOwner() method. Please let us know more details about the dialog window in your project or send us a test project so we can help you find out what is wrong.
|
|
Technical Support
|
Aug 20, 2007 - 12:17 PM
|
You can find toolbars inserted as custom dialog controls in the ProfUIS_Controls sample. Just drop a custom control onto the dialog form and copy its properties from a similar control in ProfUIS_Controls. Then add the CExtToolControlBar property to the dialog class, add DDX entry for it in dialog’s DoDataExchange() method, load the toolbar in the OnInitDialog() method and invoke CWnd::RepositionBars(0,0xFFFF,0) code both in dialog’s OnInitDialog() and OnSize() methods to let the toolbar stick to the dialog’s border.
|
|
Andrew Moulden
|
Aug 17, 2007 - 1:57 PM
|
Hi,
I’m a new Prof-UIS user and I’m struggling to understand how I’m meant to deallocate memory with Prof-UIS derived classes, in particular with a CExtPropertyItem derived class.
In all past projects I have worked on the golden rule has been that if I instantiate an object on the heap with operator ’new’ then it is my responsibility to release memory for that object via a destructor call. If an object is instantiated in a third-party library then such an object is normally obtained via a Create() function and released via a Destroy() or Delete() function.
I can find no instructions in the Prof-UIS documentation which tell me which objects are my responsibility to delete, and which objects will be deleted by Prof-UIS. I therefore assumed that I would have to delete any objects I create on the heap via ’new’. However when I study the source of your samples for CExtPropertyGridCtrl I note that you create a CExtPropertyStore object and explicitly make comments in the code that this object should be deleted as its memory was allocated dynamically. You then go on to create many objects derived from the CExtPropertyValue class, and you instantiate these via operator ’new’ but you *don’t* call delete on these. Why not? Nowhere in the docs does it say that the CExtPropertyStore parent of these objects will handle the memory deallocation. How are Prof-UIS users meant to know which objects they should delete?
Also I don’t understand the usage of the CExtPropertyItem.Delete() method. You say that this should be called rather than using the ’delete’ operator, but what if I create a CExtPropertyValue-derived class which makes its own heap allocations? How do I destroy this object? Will CExtPropertyItem.Delete() call my own destructor, or should I first call the Destroy() method to release base class memory, and then destroy my own objects separately?
I apologise if this seems so trivial to the authors of the Prof-UIS library, and I realise I am probably misunderstanding this issue, but due to the dynamic nature of the app I am working on it is extremely important to me that I know exactly how to release memory from the numerous objects I am creating.
Many thanks for your time.
Andrew
|
|
Technical Support
|
Aug 18, 2007 - 8:54 AM
|
Even in MFC some objects are self deleted (e.g. frames and views) while other ones should be deleted from your code directly. We think the most convenient design is provided by GDI wrapper classes like CDC . You can create an HDC handle manually and attach it to a CDC object using the CDC::Attach() method or you can let the CDC object to create a HDC handle using some of CDC::Create***() methods. But a HDC handle is always deleted automatically in the CDC::~CDC() destructor. If you need a HDC handle to be deleted automatically, then you should detach it from the CDC handle using the CDC::Detach() method.
As for the property items (values, categories and stores), there are two options of using the in property grid control:
1) You are using a property grid (the CExtPropertyGridCtrl class) without the combo box bar when the combo box bar is simply not used and hidden or even not created in the property grid control. The CExtPropertyStore* property store is attached to the property grid control using the CExtPropertyGridCtrl::PropertyStoreSet() method and detached using the same method with NULL in its parameter. The CExtPropertyGridCtrl class never deletes the property store pointer and you should delete it in your code,
2) You are using a property grid with the CExtPropertyGridComboBoxBar combo box bar and inserting property store pointers into it as combo box items using the CExtPropertyGridComboBoxBar::PropertyStoreInsert() method. The combo box bar removes all the property stores at shutdown because it is based on the combo box common control which automatically deletes its string collection when the combo box window is destroyed. The combo box bar handles the item selection event in it and attaches the selected property store to the property grid control using the CExtPropertyGridCtrl::PropertyStoreSet() method as it is described in #1 above. The combo box bar does not delete property stores either.
In both cases property stores are not deleted. Why? Property stores describe properties of some objects in your application. It is convenient to create and destroy the property store tree of each of your objects in its constructor and destructor. You know exactly that only you manages property stores and nobody else will ever destroy them.
Each CExtPropertyStore property store contains a tree-like structure of CExtPropertyValue property values and CExtPropertyCategory property categories. All three classes are derived from the CExtPropertyItem class which provides a set of methods for managing the collection of child property items. Your code allocates new property categories/values and insert them into theparent store/category using the CExtPropertyItem::ItemInsert() method. If you delete the property store, then all the child trees of property items become deleted automatically. This is convenient because in a typical task the property store tree structure is initialized once when it needs to be displayed in the property grid control. If you need to change the tree structure of property storeās tree, then you should use the CExtPropertyItem::ItemRemove() method which removes and destroys tree brunches. Then you can insert new brunches. So, you should use C++’s delete operator for property stores only.
The CExtPropertyItem::Delete() virtual method is really needed for internal use in combined property values only. The combined property values in one property store contains pointers to other property values from other property stores. So, child property values should not be deleted by a combined property value. That is why all property items use the CExtPropertyItem::Delete() virtual method instead of C++’s delete operator.
|
|
Suhai Gyorgy
|
Aug 17, 2007 - 8:53 AM
|
Dear Support,
I’ve been trying to use your CExtGridWnd::GridColumnDefaultValueBind method. When specifying a column index >= zero, everything works fine. Your Help file says if I set first parameter (column index) as a negative value, the method will bind the given cell to all columns. I tried this version (would save me a loop), but any subsequent GridCellGet call with NULL as parameter for CRuntimeClass failed. Stepping through your code for CExtGridWnd::GridColumnDefaultValueBind , I can’t see where it handles negative column index value differently from non-negative values. Could you please check this issue? Or would you like me to make a small sample application for demonstrating this problem?
Thank you!
|
|
Technical Support
|
Aug 17, 2007 - 1:20 PM
|
We confirm the problem with the method description in help. Thank you. The method was not designed to assign the default value for one column only because it is not often needed to assign all the grid cells in all columns with the same value.
|
|
Pierre MEDART
|
Aug 17, 2007 - 6:13 AM
|
We have replaced a CMenuBar with a CExtMenuControlBar.
We used to performe some customer specific operation (updating the menu depending on the other products installed) in the OnInitMenu of our application.
How can we do it again ?
Regards
|
|
Suhai Gyorgy
|
Aug 17, 2007 - 6:30 AM
|
There is an article describes how to build popup menus dynamically at run time.
|
|
Pierre MEDART
|
Aug 23, 2007 - 3:32 AM
|
OK let’s make things clear. It is not a pop-up menu.
We have replaced the MFC CMenuBar with a CExtMenuControlBar as described in the help delivered with ProfUI.
Previoulsy we used the OnInitMenu() to perform various action such as if the use has the Shift key down we displayed some special menu.
This no longer works since the OnInitMenu is never reached with the MenuBar.
The LRESULT CMainFrame::OnExtMenuPrepare(WPARAM wParam, LPARAM lParam) as described in the article just doesn’t work (catch it for the popup but not the mainframemenu)
How can we fix this?
|
|
Suhai Gyorgy
|
Aug 23, 2007 - 7:50 AM
|
CExtMenuControlbar is derived from CExtToolControlBar, so actually the very top level menu items are toolbar buttons in this case. Read this article: Constructing Menus Dynamically at Run Time. The second chapter, called Menu Bar, talks about how to change these toolbar buttons which represent the toplevel menu items.
|
|
Michael Bailey
|
Aug 16, 2007 - 11:39 PM
|
Hi,
I’m looking for the proper way to free/delete all the memory used by EnableCustomization(). When I call the following code, I get a bunch of memory leaks when shutting down.
if(!CCustomizeDlg::EnableCustomization(this,__ECSF_DEFAULT)) { ASSERT( FALSE ); return -1; }
Is there a shutdown function I should be calling in DestroyWindow()?
Thanks, Mike
|
|
Michael Bailey
|
Aug 18, 2007 - 10:34 PM
|
Problem solved.
Added AfxOleInit(); to the CApp::InitInstance() no more leaks. Not sure why this is the case, but it works great and the 1000’s of leaks are plugged.
Thanks for the help. Prof-UI is a great tool.
Mike
|
|
Technical Support
|
Aug 19, 2007 - 9:58 AM
|
The OLE initialization is essential because the customization subsystem uses OLE drag-and-drop APIs for menu items and toolbar buttons. But this should have to do with memory leaks. We guess the source of these leaks was specific to your project only.
|
|
Technical Support
|
Aug 17, 2007 - 8:09 AM
|
There are no API that would allows you deinitialize the customization subsystem directly. Everything should be closed and deallocated automatically. If you have memory leaks of MFC/Prof-UIS objects, there must be some problem in the application shutdown. For instance, it may be closed by the ExitThread() or PostQuitMessage() APIs so the destructors won’t be called. Please check if the DestroyWindow() virtual method of the main frame class and the ExitInstance() virtual method of application class are invoked at shutdown. You can also configure the debugger to break on any exceptions before shutdown and clarify what happens during shutdown. Any unhandled exceptions may also crash your application even without any popup message boxes.
|
|
Suhai Gyorgy
|
Aug 17, 2007 - 1:42 AM
|
Just a guess: Have you followed the steps described in the Feature Article Prof-UIS Customization Subsystem ? If so, can you reproduce the problem in any of the customized ProfUIS samples ( in BitmapEditor, for example )?
|
|
Darren Oliver
|
Aug 16, 2007 - 2:27 PM
|
Dear Tech Support,
Is there a way to redraw the cell? Currently the text is updated only when the mouse is dragged over the cell.
The CExtGridCellString is inside a CExtGridWnd
Thanks
|
|
Darren Oliver
|
Aug 17, 2007 - 11:05 AM
|
Thank you, your solution worked perfectly.
|
|
Technical Support
|
Aug 17, 2007 - 6:09 AM
|
First, you should get rectangular cell coordinates in the grid control’s client coordinate system: CExtGridWnd & wndGrid = . . .
LONG nColNo = . . .
LONG nRowNo = . . .
CRect rcCellLocation;
if( ! wndGrid.GridCellRectsGet(
nColNo,
nRowNo,
0,
0,
NULL,
&rcCellLocation
)
)
return . . . The CExtGridWnd::GridCellRectsGet() method returns true > if the rcCellLocation rectangle was filled with correct cell rectangle coordinates in the grid’s client coordinate system. This method returns false</codde> if it is not possible to compute cell coordinates (cell at column <code>nColNo column and row nRowNo is outside the visible cell range or method parameters are invalid). Then you should invalidate the part of the grid control which contains the cell at nColNo and nRowNo wndGrid.InvalidateRect( &rcCellLocation ); This code delays repainting of grid control’s part which contains the specified grid cell. If you don not need delayed repainting and grid control’s surface on the screen should be updated immediately, then the next line of code should be wndGrid.UpdateWindow(); If you want to repaint several cells immediately, you should invoke the UpdateWindow() method only once after all the cells were invalidated.
|
|
David Skok
|
Aug 16, 2007 - 10:07 AM
|
My application has several CExtCustomControlBars. If I pin one of them open and right click on the title bar (of the Controlbar) code gets stuck in an endless loop here:
CExtControlBar.cpp
void CExtControlBar::OnRButtonUp(UINT nFlags, CPoint point) ... ... ... CWnd * pWndChild = GetWindow( GW_CHILD ); if( pWndChild != NULL ) { HWND hWndOwn = m_hWnd; if( stat_QueryFocusChangingEnabled( this, pWndChild->m_hWnd ) ) { pWndChild->SetFocus(); CExtPopupMenuWnd::PassMsgLoop( true ); <***** NEVER RETURNS FROM HERE if( ! ::IsWindow( hWndOwn ) ) { delete pPopup; return; } m_bWindowActive = true; SendMessage( WM_NCPAINT ); } }
The default context Prof-UIS menu is not overridden anywhere. It displays if click on un-pinned ControlBar title. I do not see this problem in any of your samples.
Any idea what I might have done wrong?
Thanks
|
|
David Skok
|
Aug 16, 2007 - 11:42 AM
|
My apologies, I discovered the source of the problem was the return value of OnIdle( Count ) that I overrode in my application. This bug was in there for quite some time and I just discovered it now. It happens.
|
|
Pierre MEDART
|
Aug 16, 2007 - 3:46 AM
|
Hi
In our application we have to dynamically associate menu id with command (contextual menu).
The issue we face is that once a CmdID is associated with a function, it will remain.
Is there a way to clean this message map ?
Thanks
|
|
Technical Support
|
Aug 17, 2007 - 10:54 AM
|
The command hander methods, which are based on ON_COMMAND message map entries, are static and generated at compile time only. You should not operate with message map entries dynamically. The dynamic range of commands should be handled/updated in an overridden OnCmdMsg() virtual method only. It may be difficult to handle all the possible commands in one OnCmdMsg() method of the main frame or dialog class. You can derive your classes responsible for handling dynamic commands from the CCmdTarget class. The main frame’s OnCmdMsg() method should detect which CCmdTarget -based object should handle/update each particular command and invoke its OnCmdMsg() method.
|
|
DAN MAZILU
|
Aug 15, 2007 - 9:04 AM
|
PageVisibleSet method don’t hide the hwnd attached with the page when PageVisibleSet is invoked to hide the item(it is clear when you try to hide the selected tab page). I already sent a mail with a demo project.... Also, I have another problem - seems that a CTreeCtrl embedded in a CExtResizableDialog attached in CExtTabPageContainerWnd does not show the scroll bar..... I will send you a demo project...
|
|
DAN MAZILU
|
Aug 21, 2007 - 7:37 AM
|
I sent the mail - thanks for help
|
|
Technical Support
|
Aug 23, 2007 - 3:48 PM
|
Please find the following member of the CDlgDemoTreeCtrl class in your project: CExtWRB<CExtWFF< CTreeCtrl > > m_treeCtrl; and replace it with CExtWFF < CTreeCtrl > m_treeCtrl; You will also need to replace CExtWRB<CExtWFF< CTreeCtrl > >& m_wndTree = m_treeCtrl; code with the CTreeCtrl & m_wndTree = m_treeCtrl; code in the CDlgDemoTreeCtrl::OnInitDialog() method. The scroll bars will appear in the tree control after these modifications. Please do not use the CExtWRB template class with the controls which have scroll bars. The CExtWRB template class re-computes and re-paints window non-client area making it looking like a thin 1 pixel border. But scroll bars of the tree control are not scroll bar windows. Thay are rather parts of the window non-client area and they are not based on HWND handles. So, the CExtWRB template class simply kills scroll bars. The CExtWRB template class is designed for non-scrollable windows like CExtResizableDialog . When using CExtWRB with windows inside resizable control bars, the thin border looks like it is around many windows inside dockable panes in Visual Studio .NET and Visual Studio 2005. But the tree control already has a nice thin border.
|
|
DAN MAZILU
|
Aug 21, 2007 - 2:26 AM
|
I already sent the mail with treectrl page on Wednesday, August 15, 2007, subject ’Fw: CExtTabPageContainerWnd’. If you don’t have this mail tell me and I will send again....
|
|
Technical Support
|
Aug 21, 2007 - 7:00 AM
|
No, we did not receive it. Could you send it again? Please also make sure that the zipped project is small enough, i.e. it does not contain redundant files like with .ncb extension.
|
|
Technical Support
|
Aug 17, 2007 - 1:07 PM
|
Thank you for reporting the problem. You can fix it by updating the source code of this method: bool CExtTabPageContainerWnd::PageVisibleSet(
INT nItemIndex,
bool bVisible // = true
)
{
ASSERT_VALID( this );
CExtTabWnd::TAB_ITEM_INFO * pTII =
m_pWndTab->ItemGet( nItemIndex );
ASSERT( pTII != NULL );
ASSERT_VALID( pTII );
if( PageSelectionGet() == nItemIndex )
PageSelectionSet( -1 );
bool bRet =
pTII->VisibleSet( bVisible );
HWND hWnd = PageHwndGetSafe( nItemIndex );
ASSERT( hWnd != NULL && ::IsWindow( hWnd ) );
if( hWnd != NULL )
::ShowWindow( hWnd, SW_HIDE );
if( PageSelectionGet() == nItemIndex )
PageSelectionSet( -1 );
_RepositionBarsImpl();
return bRet;
} Could you insert a tree control into the test project you sent us to reproduce the problem with hidden scroll bars?
|
|
Henry Tso
|
Aug 15, 2007 - 8:59 AM
|
Hi,
I want to set the icon display in right side of the button. So I search the help file. I see a method "SetAlign" now is defined in your help file (ver 2.80), but I can’t use this function because this function is not defined in "ExttButton.h". And I found another same function "SetIconAlignment", but I don’t know how to use this function. Because I don’t know how to give the paramenter. Of cause, your help file without define this function. Would you help me. Thanks
|
|
Henry Tso
|
Aug 15, 2007 - 9:24 AM
|
Thanks for your quick reply. I see the example too. But I suggestion your help file need update at the next time release. It may very helpful for end-user. Otherwise we need search the sample code for our usage, I think it is not make sense. ˆˆ
|
|
Suhai Gyorgy
|
Aug 15, 2007 - 2:38 PM
|
I feel I need to let you know that I’m not part of the ProfUIS Support team. And even though I agree that Help file should be updated, I think it’s very important to let the users have the new feature as soon as possible (especially that this feature was requested).
|
|
Suhai Gyorgy
|
Aug 15, 2007 - 9:16 AM
|
You should check the PageButtons class inside ProfUIS_Controls sample. It demonstrates usage of these new methods (SetTextAlignment and SetIconAlignment)
|
|
M Priya
|
Aug 13, 2007 - 10:26 AM
|
Hello,
I tried using CExtResizablePropertySheet with CExtResizablePropertyPage. However, the title and subtitle are not appearing. Please help.
Regards
|
|
Xiaoli Bi
|
Aug 30, 2007 - 9:52 AM
|
Can you support me on the issue? I have 2 user license and 90 days supporting.
|
|
Xiaoli Bi
|
Aug 27, 2007 - 8:04 PM
|
Here are some codes from my project: CCalibratorResizablePropertySheet wizard( _T("Calibrator")); wizard.SetSliceImageData(pImageData); // add pages CCalibrateRawImagePropertyPage page1(&wizard); wizard.AddPage( &page1 ); CCalibrateCheckDICOMPropertyPage page2(&wizard); wizard.AddPage( &page2 ); CCalibrateCropImagePropertyPage page3(&wizard); wizard.AddPage( &page3 ); CCalibrateContourPropertyPage page4(&wizard); wizard.AddPage( &page4 ); CCalibrateResultPropertyPage page5(&wizard); wizard.AddPage( &page5 ); // comment this line and next lines to set simple tabbed mode (non-wizard) wizard.SetWizardMode();
// these lines are fully available with MFC 7.0 or later only // comment them to set old classic wizard mode // leave them intact to use wizard 97 mode wizard.m_psh.dwSize = sizeof(wizard.m_psh); wizard.m_psh.dwFlags |= (PSH_WIZARD97 |PSH_WATERMARK |PSH_WIZARDHASFINISH); // comment the following line if the tiled watermark bitmap is not needed wizard.m_psh.pszbmWatermark = MAKEINTRESOURCE(ID_CALIBRATE_WIZARD_WATERMARK); //wizard.m_psh.hInstance = ::AfxGetInstanceHandle(); page1.m_psp.dwFlags |= PSP_DEFAULT|PSP_USEHEADERTITLE|PSP_USEHEADERSUBTITLE; page1.m_psp.pszHeaderTitle = _T("Title of page 1"); page1.m_psp.pszHeaderSubTitle = _T("Subtitle of page 1"); page2.m_psp.dwFlags |= PSP_DEFAULT|PSP_USEHEADERTITLE|PSP_USEHEADERSUBTITLE; page2.m_psp.pszHeaderTitle = _T("Title of page 2"); page2.m_psp.pszHeaderSubTitle = _T("Subtitle of page 2");
|
|
Xiaoli Bi
|
Aug 27, 2007 - 7:59 PM
|
I am crazy for the same issue. Can you tell me how to fix it? I use the propertysheet in MFC extensition DLL project.
|
|
Technical Support
|
Aug 31, 2007 - 10:18 AM
|
The disappearing page title bug is a 50% bug. It depends on the property sheet initialization sequence. It’s absent in our ResizablePropertySheet sample application while it may present in your project. The CExtResizablePropertySheet class needs to anchor its child window because this is needed by its resizable features and it needs to subclass child controls with Prof-UIS classes and re-paint its surface for theme skinning purposes. These are some differences between the CExtResizablePropertySheet class in Prof-UIS and the CPropertySheet class in MFC. The CPropertySheet class does not create the inner content of the property sheet. This is performed by the PropertySheet() Win32 API. So, we are using a delayed initialization in the CExtResizablePropertySheet class. That is why it is very important to initialize it exactly like you we do it in the ResizablePropertySheet sample.
|
|
Technical Support
|
Aug 13, 2007 - 1:07 PM
|
We still did not receive enough information about the problem. Would you send us your project so we can check it?
|
|
M Priya
|
Aug 13, 2007 - 4:46 PM
|
Hello,
I am having the following problems with Hyperlink and Property Sheets
1. Hyperlink has no hand cursor. Don’t know how to get it.
2. Property Sheet has no title or subtitle on following pages.
I have enclosed a project which demonstrates this (sent by email)
1. For compiling with just MFC (no ProfUIS), use the Build Configuration "Debug". Shows the title and the subtitle of the property page.
2. For compiling with ProfUIS, use the Build configuration "ProfUIS-Debug". Shows both problems listed above.
Thanks Jay
|
|
Technical Support
|
Aug 14, 2007 - 2:48 AM
|
You already replied your questions in other threads. Actually there is not enough information to find out what might be wrong. In fact, you simply say the problem exists and nothing else. Please send us your project demonstrating the problems or provide us with remote access to your desktop so we can help you.
Because there are no any problems with the hand cursor over hyperlink controls in our sample applications and there are no problems with titles in the ResizablePropertySheet sample. There must be something specific to your project.
|
|
M Priya
|
Aug 14, 2007 - 1:32 PM
|
I sent a sample project which illustrates the problem clearly. Since there is no way to include stuff in the forum replies, I have sent it by email. Did you get it? Looks like you have not got it yet.
If there is not enough information, that is because it is nothing complicated. Just create a dialog box project from scratch, replace the dialog box with a property sheet/page wizard and using your classes, the title and subtitle are absent.
Please let me know if you haven’t received the sample by email.
|
|
Technical Support
|
Aug 15, 2007 - 11:36 AM
|
We received your e-mail, fixed the problems in your project and sent a modified version of your project back. The e-mail was sent 3:27PM EST on 8/14/2007. We suspect this email may have been filtered out or got into your Junk E-mail folder. So please check this. We can upload this email on our web site and give you the link or send to some other email address if you provide it to us.
|
|
Technical Support
|
Aug 14, 2007 - 1:33 PM
|
We have just sent you an email with the fixed project and our comments.
|
|
Malcolm D
|
Aug 12, 2007 - 6:15 PM
|
|
|
Technical Support
|
Aug 14, 2007 - 2:34 AM
|
The "input enabled" check boxes are currently part of Prof-UIS but these are still experimental. Although we do not have plans to enhance this feature in the nearest future, if you have some suggestions about this feature (please remind the details) and it does not take much time, we will certainly implement this.
|
|
Malcolm D
|
Aug 12, 2007 - 6:07 PM
|
|
|
Christophe Guibert
|
Aug 12, 2007 - 2:18 PM
|
Hello, I’m currently using the powerful CExtReportGridWnd to display structured data and would like to walk the columns and rows in the order their have been left by the user in the grid, including collapsed rows.
Using ReportColumnGetStartPosition() and ReportColumnGetNext() enumerate the displayed columns in the order they were registered, not the user order.
Using the ItemGetRoot() and ItemGetNext() enumerate only the shown rows (not those which are collapsed when one or several fields are used as group criteria).
Could you please give hints to : - walk columns in the order they are displayed in the grid ? - walk rows in the order where they appear, even when not expanded ?
Thank you in advance,
Best Regards,
Christophe Guibert
|
|
Suhai Gyorgy
|
Aug 12, 2007 - 2:57 PM
|
This is how ItemGetNext is shown in Help file: virtual HTREEITEM ItemGetNext(
HTREEITEM hTreeItem,
bool bSiblingOnly,
bool bExpandedWalk,
bool bWalkDeeper
) const;
Though I didnt try, but I guess if you use false as 3rd parameter, it should give you collapsed items as well. If it doesn’t, it might be a bug.
|
|
Christophe Guibert
|
Aug 13, 2007 - 1:24 PM
|
I thank you for your suggestion, but collapsed items are not traversed whatever the parameter I give, especially the third.
In Prof-UIS 2.80, there’s even a fourth boolean parameter (bIncludeHidden, not yet documented), and it seems to have no effect. Is this a bug ?
The other point is to enumerate columns in the order they are set by the end-user. Any idea ?
Best Regards,
Christophe Guibert
|
|
Technical Support
|
Aug 14, 2007 - 2:54 AM
|
The CExtTreeGridWnd::Item***() APIs are based on HTREEITEM handles and can be used for accessing any tree row. But if you want to access visible rows, you should use the CExtGridWnd class APIs (including its based classes) which are based on plain row indices. The CExtGridWnd::OnSiwGetVisibleRange() method returns a CRect object with the first/last displayed row indices in the CRect::top and CRect::bottom members. In order to convert the plain row indices into HTREEITEM handles and vice versa, you should use the CExtTreeGridWnd::ItemGetByVisibleRowIndex() and CExtTreeGridWnd::ItemGetVisibleIndexOf() methods. So, you can enumerate the entire scrollable range from zero up to CExtGridWnd::RowCountGet()-1 or visible row range returned by the CExtGridWnd::OnSiwGetVisibleRange() method.
|
|
Christophe Guibert
|
Aug 15, 2007 - 1:37 PM
|
Dear Technical Support,
Considering a tree like this one : root: -item 1 -child item 2 -child item 3 -item 4 -child item 5
When using ItemGetNext() from the root, it will walk the tree until reaching -child item3 with siblingOnly=false, then return null and not the item 4. Is this on purpose ?
Nevertheless, I’ve built a recursive function to walk the tree, using ItemGetNext and ItemGetParent , changing siblingOnly, and building a list of pointers to items. This satisfy my need.
Thank you for your support.
Best Regards
Christophe Guibert
|
|
Suhai Gyorgy
|
Aug 14, 2007 - 2:34 AM
|
I use this code to walk the columns in the order they appear on the screen. LONG lColNo = ColumnCountGet();
for (LONG l = 0L; l < lColNo; l++)
{
CExtReportGridColumn *pRGC = (CExtReportGridColumn *)GridCellGetOuterAtTop(l, 0L);
// do something here
}
In my testing, it seems that ItemGetNext(hItem, false, false, true, false); gives just what you need. Can you reproduce the problem in a small sample application?
|
|
Christophe Guibert
|
Aug 14, 2007 - 4:34 PM
|
Hello Suhai,
Thank you for the column order trick which works fine !
However, the ItemGetNext(hItem, false, false, true, false); does not work for me : only one leaf row item is enumerated from the tree root when grouping is used, and whatever the group item state : expanded or collapsed. The only correct behavior is when the tree is flat (no groups).
Still searching a way to enumerate both collapsed and expanded row items in the ReportGrid.
Best Regards,
Christophe Guibert
|
|
M Priya
|
Aug 11, 2007 - 10:20 PM
|
The example (for example "Load .." in "Compound Properties") have it, but could not find anyway of doing that. Please help.
|
|
Technical Support
|
Aug 12, 2007 - 10:43 AM
|
The CExtHyperLinkButton class implements a hyperlink control. It is derived from CExtButton . That means the hyperlink is just a repainted button control. The CExtButton::SetBtnCursor() method allows you to assign a cursor to any kind of buttons in Prof-UIS (including CExtHyperLinkButton ) which are derived from the CExtButton class. This method is invoked in the CExtHyperLinkButton class constructor and assigns a hand like cursor to it. So, each hyperlink control should display the hand cursor automatically.
|
|
M Priya
|
Aug 12, 2007 - 1:07 PM
|
Well Is there anything specific to be done to get this?
I have declared the hyperlink like this:
CExtHyperLinkButton m_purchaseNow;
In the dialog editor, I have it as a Button and in InitDialog(), I assign a URL to it.
Any other steps besides these?
|
|
Technical Support
|
Aug 12, 2007 - 1:23 PM
|
Actually it is enough to get it working. You can compare your code with that used in the Prof-UIS Controls, where you can find an example of the hyperlink. Would you also tell us what is not working?
|
|
M Priya
|
Aug 13, 2007 - 10:23 AM
|
Hello,
As I mentioned, the link appears, but no cursor. How do I get this? I need this ASAP.
Regards
|
|
M Priya
|
Aug 12, 2007 - 1:27 PM
|
I tried looking at a few samples and I don’t see anything that is different. I have racked by brains about this. I looked in "Compound Properties" sample which has 4 hyperlinks each of which lead to actions within the program and also nicely change over to a hand cursor when I mouse-over. But same is not available to my program!
|
|
Technical Support
|
Aug 14, 2007 - 2:25 AM
|
In Prof-UIS, the resource identifiers in range of 29000 to 31000 are reserved for internal usage. We suspect some identifiers in your project may intersect this range. Please check the identifiers in resource.h of your project. In any case, you can always send us a test project so we can hep you find out what is wrong.
|
|
M Priya
|
Aug 11, 2007 - 8:11 PM
|
I am getting a memory fault in the following code when I try to use the property sheet: Works fine with just MFC property sheet. I replaced CPropertySheet with CExtResizablePropertySheet everywhere. No other changes. Please advise.
inline void __EXT_MFC_MEMCPY( void * dest, size_t sizeInBytes, const void * src, size_t count ) { #if _MFC_VER >= 0x0800 memcpy_s( dest, sizeInBytes, src, count ); #else memcpy( dest, src, count ); sizeInBytes; #endif }
|
|
Technical Support
|
Aug 12, 2007 - 10:40 AM
|
You said you had replaced CPropertySheet with CExtResizablePropertySheet . Did you also replace CPropertyPage with CExtResizablePropertyPage ?
|
|
M Priya
|
Aug 12, 2007 - 1:10 PM
|
Yes, I tried with both. Using only CExtResizablePropertySheet and using CExtResizablePropertySheet. with CExtResizablePropertyPage. However, I have not yet tried to replace *all* instances of CPropertyPage with CExtResizablePropertyPage, just the first. I wanted to get a look before I did all of them. Should I try replacing all of them? It is a quite bit of work, so I hesitated.
|
|
Technical Support
|
Aug 12, 2007 - 1:20 PM
|
You should replace all instances otherwise it won’t work.
|
|
M Priya
|
Aug 12, 2007 - 5:16 PM
|
I tried that. It is now working better. However, the title and subtitle on the pages are not appearing (in Wizard mode).
|
|
Suhai Gyorgy
|
Aug 10, 2007 - 6:57 AM
|
Dear Support,
I have some small buttons (CExtButton ) which have only an icon on them, but no text. I want each of them to have focus rect when it is in focus. By default, focus rect is only around the text part of the button, but you have a CExtButton::SetFocusMode method, with which I can change this default behaviour and make the focus rect drawn around the client area of the button. But this still doesn’t allow me to have focus rect for a button without text. I’ve stepped through your code CExtPaintManagerXP::PaintPushButton and I see that the code which would draw the focus rect is inside an if-block with the following condition: if( rectCaption.bottom > rectCaption.top
&& rectCaption.right > rectCaption.left
)
{ // if we have valid area for text & focus rect
...
}
So rectFocus is not checked, and even though I have valid rectFocus in that code, the invalid rectCaption keeps me from getting to the code which would draw the focus rect. Please check this issue! Thank you!
|
|
Technical Support
|
Sep 24, 2007 - 12:19 PM
|
Unfortunately you cannot do that.
The button is drawn in the CExtPaintManager::PaintPushButton() virtual method and in its overridden versions. Here is the code that draws the focus rectangle: if( _ppbd.m_bDrawFocusRect
&& ( ( !sTitle.IsEmpty() ) || _ppbd.m_nFocusMode == __EBFM_CLIENT_AREA )
&& rcFocus.bottom > rcFocus.top
&& rcFocus.right > rcFocus.left
)
{
rcFocus.DeflateRect( 2, 2 );
dc.DrawFocusRect( &rcFocus );
} As for the forum, that you for this suggestions. We look into it, may be it will be not difficult to implement it.
|
|
Suhai Gyorgy
|
Aug 14, 2007 - 9:17 AM
|
I can also reproduce this problem in your ProfUIS_Controls sample.
Test #1: Insert line
m_btnPushButton.SetFocusMode(CExtPaintManagerXP::__EBFM_CLIENT_AREA); in CPageButtons::OnInitDialog. Build, run sample, check CheckBox for "Show Focus Rect", press tab couple of times. Result: Focus rect is shown around client area of pushbutton.
Test #2: Insert line
m_btnPushButton.SetWindowText(_T("")); right after the line with SetFocusMode we inserted in Test #1. Build, run sample, check CheckBox for "Show Focus Rect", press tab couple of times. Result: Focus rect is not shown anywhere inside pushbutton.
Please let me know if you encounter the same problem! Thank you.
|
|
Technical Support
|
Aug 28, 2007 - 3:33 AM
|
The bug is fixed. Thank you again. You can download the updated source code from our ftp site.
|
|
Suhai Gyorgy
|
Sep 24, 2007 - 4:56 AM
|
Dear Support,
I haven’t compiled your new source code till now, so I couldn’t confirm the changes earlier. But now I see the fix is there, works nicely, thank you very much!
One more question concerning this issue: Our buttons are very-very small (18x18 pixel), the pictures in them cover almost the entire area of the button. Because of this, the focus rect is drawn over the picture. Is there a way I could change the distance between the button border and the focus rect? Only for these buttons, of course.
Chris
P.S.: Do you have any plans improving your forum in a way that the readers could sort the forum by date of last post? It’d be really great.
|
|
Technical Support
|
Aug 17, 2007 - 1:01 PM
|
Thank you for reporting the problem. The programmer who is responsible for this feature is on vacation and will be back on August 26. He will certainly fix this. Thank you again.
|
|
Hans Bergmeister
|
Aug 10, 2007 - 4:06 AM
|
Hello,
we want to use CExtIconEditDlg to edit two color bitmaps.
We managed to get CExtIconEditDlg to work properly with a two color palette.
But we have problems to extract a two color HIBTMAP (bitmap with one bit per pixel) from the resulting m_icon member. What is the right way to do this?
|
|
Technical Support
|
Aug 10, 2007 - 6:06 AM
|
First of all you should create a mono bitmap: INT nWidth = . . .
INT nHeight = . . .
CBitmap bmpMono;
VERIFY( bmpMono.CreateBitmap( nWidth, nHeight, 1, 1, NULL ) ); Then you should create a DC for it: CDC dcMono;
VERIFY( dcMono.CreateCompatibleDC( NULL ) );
CBitmap * pOldBitmapFromMonoDC = dcMono.SelectObject( & bmpMono ); You also have some bitmap from the image editor window. You should also create a DC for it and select this bitmap in its DC. Then you should draw using the BitBlt(),/code> API from the second DC into <code>dcMono . Finally you should restore the old selected bitmaps in both DCs and destroy DCs. As a result, you have a 2-BPP bitmap in bmpMono .
|
|
Hans Bergmeister
|
Aug 10, 2007 - 7:19 AM
|
Hello,
many thanks for your response.
This is what we have done already:
CExtIconEditDlg dlg; INT nWidth = . . . INT nHeight = . . .
CBitmap bmpMono; VERIFY( bmpMono.CreateBitmap( nWidth, nHeight, 1, 1, NULL ) );
dlg.m_icon.AssignFromHBITMAP((HBITMAP)bmpMono.GetSafeHandle(), (COLORREF)-1);
if (dlg.DoModal() == IDOK) { CDC dcMono; VERIFY( dcMono.CreateCompatibleDC( NULL ) ); CBitmap * pOldBitmapFromMonoDC = dcMono.SelectObject( & bmpMono );
CBitmap oBmpDlg; CBmpDlg.Attach(dlg.m_icon.m_bmpNormal.CreateBitmap(NULL, (COLORREF)-1));
CDC dcMemDlg; dcMemDlg.CreateCompatibleDC(NULL); CBitmap* poOldBitmapDlg = dcMemDlg.SelectObject(&oBmpDlg);
dcMono.BitBlt(0, 0, bmp.bmWidth, bmp.bmHeight, &dcMemDlg, 0, 0, SRCCOPY);
dcMemDlg.SelectObject(poOldBitmapDlg); dcMono.SelectObject(pOldBitmapFromMonoDC); }
but everything, what we finally receive in dcMono is a completely black bitmap, regardless, which image we created in the editor. What is wrong?
|
|
Technical Support
|
Aug 11, 2007 - 12:21 PM
|
We are sure we provided you with the correct way of creating one bit per pixel bitmaps. Please update the CMainDlg::OnButtonEdit() method in the IconEditor sample. void CMainDlg::OnButtonEdit()
{
int nSel = m_wndList.GetCurSel();
if( nSel < 0 )
{
::AfxMessageBox(
_T("Please select icon in list"),
MB_OK|MB_ICONINFORMATION
);
return;
}
CExtCmdIcon * pIcon = m_wndList.GetIconPtr( nSel );
ASSERT( pIcon != NULL && (! pIcon->IsEmpty()) );
CExtIconEditDlg dlg( this );
dlg.m_icon.AssignFromOther( *pIcon );
ASSERT( ! dlg.m_icon.IsEmpty() );
dlg.m_strProfileSection = _T("ResizableDialogs");
dlg.m_strProfileEntryWindow = _T("IconEditor-Window");
dlg.m_strProfileEntryIconEditor = _T("IconEditor-EditorControl");
CSize _sizeIcon = pIcon->GetSize();
CString strColors;
INT nBitsPerPixel = pIcon->m_bmpNormal.GetBPP();
if( nBitsPerPixel >= 24 )
strColors = _T("16.777.216 (16M)");
else if( nBitsPerPixel == 16 )
strColors = _T("65.536 (64K)");
else if( nBitsPerPixel == 15 )
strColors = _T("32.768 (32K)");
else
strColors.Format( _T("%ld"), 1L << nBitsPerPixel );
dlg.m_strAlternateCaption.Format(
_T("Icon Editor - %dx%d, %s colors"),
_sizeIcon.cx, _sizeIcon.cy,
(LPCTSTR)strColors
);
// dlg.m_bEatTransparentColor = false;
if( dlg.DoModal() != IDOK )
{
/////// return;
}
ASSERT( ! dlg.m_icon.IsEmpty() );
pIcon->AssignFromOther( dlg.m_icon );
m_wndList.RecalcListLayout();
HBITMAP hBitmapColored = NULL;
COLORREF clrTransparent = COLORREF(-1L);
VERIFY( dlg.m_icon.ExtractEditableBitmap( hBitmapColored, clrTransparent ) );
ASSERT( hBitmapColored != NULL );
VERIFY( CExtPaintManager::stat_SerializeBitmap( _T("C:\\1.bmp"), false, &hBitmapColored ) );
CExtBitmap bmpColored;
bmpColored.FromBitmap( hBitmapColored );
::DeleteObject( hBitmapColored ); // we don’t need it anymore
CSize sizeBmp = bmpColored.GetSize();
int nCountOfBytesPerLine = sizeBmp.cx / 8 + ( ( ( sizeBmp.cx % 8 ) != 0 ) ? 1 : 0 );
int nCountOfBytesInBitmap = nCountOfBytesPerLine * sizeBmp.cy;
BYTE * pBinarySurface = new BYTE [ nCountOfBytesInBitmap ];
int nCounter, nX, nY;
for( nCounter = 0; nCounter < nCountOfBytesInBitmap; nCounter ++ )
pBinarySurface[ nCounter ] = BYTE(0xFF); // make each pixel white
double lfHue, lfSaturation, lfLuminance;
BYTE * pCurrSurfacePtr = pBinarySurface;
for( nY = 0; nY < sizeBmp.cy; nY++ )
{
for( nX = 0; nX < sizeBmp.cx; nX++ )
{
COLORREF clrColored = bmpColored.GetPixel( nX, nY );
if( clrTransparent != COLORREF(-1L)
&& clrTransparent == clrColored
)
continue;
CExtBitmap::stat_RGBtoHSL( clrColored, &lfHue, &lfSaturation, &lfLuminance );
if( lfLuminance > .5 )
continue;
int nByteIndex = nX / 8;
BYTE & _byte = pCurrSurfacePtr[ nByteIndex ];
int nBitIndex = nX % 8;
nBitIndex = 7 - nBitIndex;
BYTE nMaskValue = BYTE( 1 << nBitIndex );
_byte &= ~nMaskValue; // make this pixel black
}
pCurrSurfacePtr += nCountOfBytesPerLine;
}
//HBITMAP hBitmapMono = CreateBitmap( sizeBmp.cx, sizeBmp.cy, 1, 1, pBinarySurface );
BITMAP bi;
bi.bmType = 0;
bi.bmWidth = sizeBmp.cx;
bi.bmHeight = sizeBmp.cy;
bi.bmWidthBytes = nCountOfBytesPerLine;
bi.bmPlanes = 1;
bi.bmBitsPixel = 1;
bi.bmBits = pBinarySurface;
HBITMAP hBitmapMono = CreateBitmapIndirect( &bi );
ASSERT( hBitmapMono != NULL );
delete [] pBinarySurface;
VERIFY( CExtPaintManager::stat_SerializeBitmap( _T("C:\\2.bmp"), false, &hBitmapMono ) );
CExtBitmap bmpTmp;
bmpTmp.FromBitmap( hBitmapMono );
bmpTmp.Make32();
bmpTmp.SaveBMP_File( _T("c:\\3.bmp") );
::DeleteObject( hBitmapMono ); // we don’t need it anymore
} Then please run it and open the C:\ folder with Windows Explorer and select the Thumbnails view for this folder. You can double click any list box item in the IconEditor sample and then click OK in the opened icon editor dialog, In the C:\ folder, you will see three bitmaps created in it. 1.bmp (the hBitmapColored and bmpColored variables in the code above) is created from the icon surface and uses some random color instead of transparent pixels. 2.bmp (the hBitmapMono ) is absolutely an valid one pit per pixel bitmap file created from the previous bitmap but it is displayed absolutely incorrect for most of icons from the list box in the main dialog of the IconEditor sample. 3.bmp (the bmpTmp ) is created from the second bitmap. This third bitmap is a 32 bit per pixel bitmap without alpha channel and contains black and white opaque pixels only. This bitmap is displayed correctly in the Windows Explorer. We would like to ask you to provide more details about your task so we can find correct bitmap implementation for you.
|
|
Hans Bergmeister
|
Aug 12, 2007 - 4:10 AM
|
Hello,
many thanks for your suggestion.
You wrote: >> This third bitmap is a 32 bit per pixel bitmap without alpha channel and contains black and white opaque pixels only. << This is not exactly, what we need. We need a 1 bit per pixel bitmap as result.
Something like this:
HBITMAP hbmpSourceMono; // given bitmap with 1 bit per pixel CExtIconEditDlg dlg( this );
dlg.m_icon.AssignFromHBITMAP(hbmpSourceMono, (COLORREF)-1);
if (dlg.DoModal() == IDOK) { HBITMAP hbmpDestMono = dlg.m_icon.Extract_HBITMAP_with_1_Bit_per_Pixel(); }
We are looking for that "Extract_HBITMAP_with_1_Bit_per_Pixel()" function, that results in a HBITMAP with 1 bit per pixel.
Or in other words: the complete procedure of editing bitmaps with CExtIconEditDlg should maintain the original color depth.
|
|
Technical Support
|
Aug 12, 2007 - 10:39 AM
|
The source code in our previous message allows you to convert any source bitmap into a destination 1BPP bitmap (1 bit per pixel bitmap). If the source bitmap contains only RGB(0,0,0) and RGB(255,255,255) pixels, the destination bitmap will be exactly the same. We believe the generated 1BPP bitmap is correct. The only real problem is that it cannot be painted correctly by Windows GDI APIs for bitmap painting and even Windows Explorer does not display it correctly. Prof-UIS uses the same technique for generating 1 BPP bitmaps used for painting docked toolbar grippers in Office XP style. But our 1BPP bitmap is not painted using BitBlt() API. We use it for creating a pattern brush and fill the gripper area using it. The 1BPP pattern is painted correctly using this approach. So, we can offer you the following solution:
1) We will create a function from our code for converting any bitmap into a 1BPP bitmap. You could use it for converting after editing. So, you will keep only 1BPP bitmaps in memory.
2) Before painting and editing, you will convert 1BPP bitmaps into 32BPP bitmaps like it is demonstrated in the last lines of our code which generate the third bitmap.
|
|
Hans Bergmeister
|
Aug 12, 2007 - 10:56 AM
|
Hello,
many thanks for your support.
>> 1) We will create a function from our code for converting any bitmap into a 1BPP bitmap. You could use it for converting after editing. So, you will keep only 1BPP bitmaps in memory. << This would be great. Thank you very much in advance.
Woud it be also possible, to make the function more flexible and to allow converting any bitmap into a xBPP bitmap? In this way one could input any xBPP bitmap into CExtIconEditDlg and could output the resulting bitmap after DoModal() in the same color format.
|
|
Technical Support
|
Aug 14, 2007 - 2:58 AM
|
Here is the function for creating a 1 BPP bitmap HBITMAP ConvertBitmapToMono(
HBITMAP hBitmapColored, // source bitmap of any format, must be not NULL
bool bDeleteColoredBitmapOnSuccess = false, // delete hBitmapColored if the returned handle is not NULL
double lfMinWhiteLuminance = 0.5 // luminance margin between 0.0 (black) and 1.0 (white)
)
{
if( hBitmapColored == NULL
|| lfMinWhiteLuminance <= 0.0
|| lfMinWhiteLuminance >= 1.0
)
{
ASSERT( FALSE );
return NULL; // invalid parameter
}
COLORREF clrTransparent = COLORREF(-1L);
CExtBitmap bmpColored;
if( ! bmpColored.FromBitmap( hBitmapColored ) )
return NULL;
CSize sizeBmp = bmpColored.GetSize();
int nCountOfBytesPerLine = sizeBmp.cx / 8 + ( ( ( sizeBmp.cx % 8 ) != 0 ) ? 1 : 0 );
int nCountOfBytesInBitmap = nCountOfBytesPerLine * sizeBmp.cy;
BYTE * pBinarySurface = NULL;
try
{
pBinarySurface = new BYTE [ nCountOfBytesInBitmap ];
}
catch( CException * e )
{
ASSERT( FALSE );
e->Delete();
return NULL; // memory allocation error
}
catch( ... )
{
ASSERT( FALSE );
return NULL; // memory allocation error
}
ASSERT( pBinarySurface != NULL );
int nCounter, nX, nY;
for( nCounter = 0; nCounter < nCountOfBytesInBitmap; nCounter ++ )
pBinarySurface[ nCounter ] = BYTE(0xFF); // make each pixel white
double lfHue, lfSaturation, lfLuminance;
BYTE * pCurrSurfacePtr = pBinarySurface;
for( nY = 0; nY < sizeBmp.cy; nY++ )
{
for( nX = 0; nX < sizeBmp.cx; nX++ )
{
COLORREF clrColored = bmpColored.GetPixel( nX, nY );
if( clrTransparent != COLORREF(-1L)
&& clrTransparent == clrColored
)
continue;
CExtBitmap::stat_RGBtoHSL( clrColored, &lfHue, &lfSaturation, &lfLuminance );
if( lfLuminance >= lfMinWhiteLuminance )
continue;
int nByteIndex = nX / 8;
BYTE & _byte = pCurrSurfacePtr[ nByteIndex ];
int nBitIndex = nX % 8;
nBitIndex = 7 - nBitIndex;
BYTE nMaskValue = BYTE( 1 << nBitIndex );
_byte &= ~nMaskValue;
}
pCurrSurfacePtr += nCountOfBytesPerLine;
}
BITMAP bi;
bi.bmType = 0;
bi.bmWidth = sizeBmp.cx;
bi.bmHeight = sizeBmp.cy;
bi.bmWidthBytes = nCountOfBytesPerLine;
bi.bmPlanes = 1;
bi.bmBitsPixel = 1;
bi.bmBits = pBinarySurface;
HBITMAP hBitmapMono = ::CreateBitmapIndirect( &bi );
delete [] pBinarySurface;
if( hBitmapMono == NULL )
{
ASSERT( FALSE );
return NULL; // mono bitmap handle creation error
}
if( bDeleteColoredBitmapOnSuccess )
::DeleteObject( hBitmapColored );
return hBitmapMono; // success
} It is not difficult task to convert any BPP to any higher BPP. More difficult task is conversion to a lower BPP, especially when using bitmaps with indexed color format. The conversion into color BPP is called color quantization. It is performed by libraries like CxImage: http://www.codeproject.com/bitmap/cximage.asphttp://www.codeproject.com/bitmap/cquantizer.asp
|
|
Hans Bergmeister
|
Aug 14, 2007 - 3:30 AM
|
Hello,
many thanks four the code. I really appreciate your support. The code will be useful for our task.
One final question: is my assumption correct, that - regardless from the bmp format being loaded into CExtIconEditDlg - the format of the bitmap stored in CExtIconEditDlg::m_icon after returning from CExtIconEditDlg ::DoModal() is always 32 BPP ?
|
|
Technical Support
|
Aug 14, 2007 - 1:09 PM
|
The format of the returned bitmap is the same as the format of the bitmap you started editing. The bitmap cloning during editing in the undo-redo buffer of image editor control is performed by the CExtBitmap::stat_CloneBitmap() method.
|
|
Hans Bergmeister
|
Aug 15, 2007 - 1:14 AM
|
Hello,
I am afraid now, that we begin to go round in circles.
Once more:
Originally I wrote, that we do the following:
HBITMAP hbmpSourceMono; // given bitmap with 1 BPP
CExtIconEditDlg dlg( this );
dlg.m_icon.AssignFromHBITMAP(hbmpSourceMono, (COLORREF)-1);
if (dlg.DoModal() == IDOK) { ... }
with hbmpSourceMono being a monochrome bitmap with 1 BPP. I told you, that we have problems to extract a bitmap in the original 1BPP format from dlg.m_icon after calling DoModal(). Then you provided us with comprehensive source code, that fullfills this task. Finally you stated, that the format of the returned bitmap is the same as the format of the bitmap we started editing.
I am lost now. If the format of the returned bitmap is the same as the original bitmap (which was 1 BPP), why do we have those problems to extract a bitmap with 1 BPP and why do we need the comprehensive code, you provided us before???
|
|
Technical Support
|
Aug 19, 2007 - 10:05 AM
|
We have checked the image editor’s code again. It seems it returns the same image format as assigned in all cases except 1 for BPP bitmaps. Please use the function we wrote for you for adjusting 1BPP bitmaps.
|
|
Hans Bergmeister
|
Aug 21, 2007 - 12:19 PM
|
Hello,
understood, many thanks.
Your code will help to overcome this restriction. Do you plan to extend CExtIconEditDlg to make it treat all bitmap formats (including 1BPP consistently)?
|
|
Technical Support
|
Aug 22, 2007 - 12:22 PM
|
Frankly speaking, we think 1BPP bitmaps with regard to Ui is relic of past. Even if you need some simple two color (black and white for instance) graphic images, you’d better use 32-bit images with alpha channel because they can contain very smooth edges of graphic shapes. It would be extremely interesting to know why and for which purposes you are using so low color images in your project?
|
|
Hans Bergmeister
|
Aug 23, 2007 - 1:11 AM
|
Hello,
>> It would be extremely interesting to know why and for which purposes you are using so low color images in your project? << We need 1BPP bitmaps for a very specific project: these bitmaps are actually displayed on external hardware devices with small b/w displays. The bitmaps can be edited by the end user and transferred to the external hardware device. The format of the bitmaps transferred and displayed on the external hardware is 1 BPP. These bitmaps are also stored as 1BPP bitmaps in our software.
In the past we used the bitmap editor of Microsoft MSDN for these 1BPP bitmaps. This editor does not have any problems to edit such bitmaps and to maintain their format properly. Even more: it provides a specific "color palette" for 1BPP bitmaps. Instead of different colors that palette provides a selection of different b/w patterns, when editing 1BPP bitmaps.
We replaced the MSDN editor with CExtIconEditDlg and found several limitations in CExtIconEditDlg compared to MSDN. Among others we were astonished, that CExtIconEditDlg is by default not able to edit 1BPP bitmaps, that the palette is restricted to the colors already contained in the bitmap (which makes it very hard for the end user to add new colors) and that it does not provide any means for the end user to define custom colors. In the meantime we overcame all these limitations and built a neat editor. Just a few additional source code lines were needed to accomplish this.
I am a bit astonished, however, that your developers didn’t spend this small effort to make CExtIconEditDlg much more powerful and attracting.
Case closed.
|