There are three places where menus show up in the new MFC functionality (Feature Pack):
In menu bars (CMFCMenuBar)
In popup menus (CMFCPopupMenu)
In the 'dropdown menu' version of CMFCButton
I want to put icons (high-color and with transparancy) in the menus in all of them. I have found CFrameWndEx::OnDrawMenuImage() which I can use to custom draw the icons in front of the menu bar items. It's not very convenient, having to implement icon drawing in 2008, but it works. For the others I haven't found a solution yet. Is there an automagic way to set icons for menus?
This is how I got it to work:
First
, as the others said, create an invisible toolbar next to your main toolbar (I'm using the usual names based on AppWizard's names):
MainFrm.h:
class CMainFrame
{
//...
CMFCToolBar m_wndToolBar;
CMFCToolBar m_wndInvisibleToolBar;
//...
};
MainFrm.cpp:
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
//...
// Normal, visible toolbar
if(m_wndToolBar.Create(this,
TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC))
{
VERIFY( m_wndToolBar.LoadToolBar(
theApp.m_bHiColorIcons ? IDR_MAINFRAME_256 : IDR_MAINFRAME) );
// Only the docking makes the toolbar visible
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
DockPane(&m_wndToolBar);
}
// Invisible toolbar; simply calling Create(this) seems to be enough
if(m_wndInvisibleToolBar.Create(this))
{
// Just load, no docking and stuff
VERIFY( m_wndInvisibleToolBar.LoadToolBar(IDR_OTHERTOOLBAR) );
}
}
Second: The images and toolbar resources
IDR_MAINFRAME and IDR_MAINFRAME_256 were generated by AppWizard. The former is the ugly 16 color version and the latter is the interesting high color version.
Despite its name, if I remember correctly, even the AppWizard-generated image has 24bit color depth. The cool thing: Just replace it with a 32bit image and that'll work, too.
There is the invisible toolbar IDR_OTHERTOOLBAR: I created a toolbar with the resource editor. Just some dummy icons and the command IDs. VS then generated a bitmap which I replaced with my high color version. Done!
Note
Don't open the toolbars with the resource editor: It may have to convert it to 4bit before it can do anything with it. And even if you let it do that (because, behind Visual Studio's back, wou're going to replace the result with the high color image again, ha!), I found that it (sometimes?) simply cannot edit the toolbar. Very strange.
In that case I advise to directly edit the .rc file.
I believe (but I may be wrong) that these classes are the same as the BCGToolbar classes that were included in MFC when Microsoft bought BCG. If so, you can create a toolbar with and use the same ID on a toolbar button as in the menu items you want to create icons for, and they should appear automatically. Of course, you don't have to actually display the toolbars.
In BCGToolbar, it's enough to create a toolbar in the resources & load it (but not display the window), but the toolbar button must have the same ID as the menu item you want to link it to.
Try using this function:
CMFCToolBar::AddToolBarForImageCollection(UINT uiResID,
UINT uiBmpResID=0,
UINT uiColdResID=0,
UINT uiMenuResID=0,
UINT uiDisabledResID=0,
UINT uiMenuDisabledResID=0);
So e.g.:
CMFCToolBar::AddToolBarForImageCollection(IDR_TOOLBAROWNBITMAP_256);
Worked very well for me.
One thing that can catch a person by surprise is that for customizable (ie, non-locked) toolbars, the first toolbar you make, the framework splits up and turns into some sort of palette bitmap of all icons in the program. If you try to add more toolbars later (or different toolbars) that have bitmaps (or pngs) with a different color depth than that first one, they seem to fail because it can't add them to the same palette.
Related
I have created some (CMFCToolBar) toolbars and added buttons and icons to them. I read on Microsoft's official website that CMFCToolBar takes 23x22 button size and 16x15 icon size (ref: link).
If I use 16x15 for the icons, then icons appear blurry. This is because the icons are originally with size 16x16. I used the function SetSizes(CSize (23,23), CSize(16,16)) to change icon size but the icons do not appear right:
Is there another way to set icon and button size?
Update
I called the SetSize function before create toolbar but the icon still appear a little blurry:
I want to know if there is a way to set Icon/button Transparent or make it clear like we can set toolbar transparent through TBSTYLE_TRANSPARENT in CreateEx function.
SetSizes is a static function that affects the complete library.
It should be called before you create any toolbar or menu object.
Best location is in InitInstance of you applicxation.
But my tipp: Use the sizes that are recommended! 16x15 and 23x22....
Transparency can be done with standard 32bit RGB/A bitmaps.
If you have a 16 color bitmap you should use RGB(192,192,192) as the standard color for the background. It is automatically replaced with the needed background color.
This has been answered here too.
I´ve been trying to add the buttons to an undocked QDockWidget window as I normally do for a QDialog, but with no success as follows:
QDockWidget* dw = new QDockWidget(QString("Stream %1").arg(i + 1), this);
dw->setWindowFlags((dw->windowFlags() | Qt::WindowMaximizeButtonHint |
Qt::WindowMinimizeButtonHint | Qt::WindowCloseButtonHint));
When I undock them they still only have the [X] close button.
What am I missing?
Development environment info:
Windows 10 x64,
Visual Studio 2015,
Qt 5.7.1,
C++
I figured out how to do it. You have to connect to the QDockWidget toplevelChanged(bool) signal.
connect(ui.dockWidget, SIGNAL(topLevelChanged(bool)), this, SLOT(dockWidget_topLevelChanged(bool)));
Then you need to check if its floating and set the window hints.
void MyClass::dockWidget_topLevelChanged(bool)
{
QDockWidget* dw = static_cast<QDockWidget*>(QObject::sender());
if (dw->isFloating())
{
dw->setWindowFlags(Qt::CustomizeWindowHint |
Qt::Window | Qt::WindowMinimizeButtonHint |
Qt::WindowMaximizeButtonHint |
Qt::WindowCloseButtonHint);
dw->show();
}
}
I'm afraid you can't do it that way, as QDockWidget look and feel is essentially hard coded in the QStyle your application is using, as stated in the documnetation (here in the "Appearance" section). Basically, QDockWidget is a borderless window, and the title bar and its structure(title, buttons, etc) is just painted using the style.
To overcome this, you may use a QProxyStyle to paint the minimize and maximize buttons, but these would not be "real" buttons but just their pixmaps. Hence, you would still need to perform some tinkering to handle the clicks to those virtual buttons (e.g. catching the click event on the title bar and determining if it happened inside one of these buttons).
Another possible solution is to subclass QDockWidget and implement all the painting and click event handling there. Beaware that if you want to support multiple platforms you may need to use QStyle::drawControl() to paint the extra buttons, instead of painting everything by yourself (e.g. drawing a pixmap).
I hope this helps you. Good luck with your project.
Ok, so my intention is to "prettify" a UI I'm working on. I'm familiar with using GDI+ to manually draw my controls but my target today is simply BitBlitting png's on my DC directly.
That works nice and fine with the main frame, a few buttons and perhaps some menus.
My question is - how would you skin something more complicated like a combobox, listview or more "dynamic" controls using such skins?
Thank you. My target platform is Windows and I'm using C++ with the wxWidgets framework.
To 'skin' an existing control you'll have to subclass the window and catch the draw messages.
roughly:
// Subclass the control
WNDPROC lpfnOldCtrlProc;
lpfnOldCtrlProc = (WNDPROC)SetWindowLong(ControlHwnd, GWL_WNDPROC,
(DWORD)WinSubClassFunc );
and in your WinSubClassFunc:
switch( message )
{
case WM_DRAWITEM: // owner-draw the item
However, if you want to fully 'skin' a control e.g. change all elements of a ComboBox (border, entrybox, dropdown button, droplist etc.) then this becomes really messy.
Personally, I find it is easier to create your own control from scratch than try to subclass an existing control which consists of multiple window items.
The above methods works fine for e.g. using a standard combobox with a droplist and subclass it to make it contain a droplist of colour bars.
When using the CreateSimpleReBar in WTL the main menu bar has this blue color on mouse hover and not the native vista/7 round and transparent shape. Also for some reason the menu bar seems taller then the usual native one.
Does CreateSimpleReBar draw the menu itself or am I missing something?
http://imageshack.us/photo/my-images/259/wtlmainmenu.png/
HWND hWndCmdBar = m_CmdBar.Create(m_hWnd, rcDefault, NULL, ATL_SIMPLE_CMDBAR_PANE_STYLE);
// attach menu
m_CmdBar.AttachMenu(GetMenu());
// load command bar images
m_CmdBar.LoadImages(IDR_MAINFRAME);
// remove old menu
SetMenu(NULL);
// Set m_hWndToolBar member
CreateSimpleReBar(ATL_SIMPLE_REBAR_NOBORDER_STYLE);
// Add a band to the rebar represented by m_hWndToolBar
AddSimpleReBarBand(hWndCmdBar);
CreateSimpleReBar creates a rebar control, and the menu is one of the rebar bands, created by m_CmdBar.Create - WTL's CCommandBarCtrl class. The latter custom-draws the menu to mimic OS behavior, including blue highlighting with COLOR_MENUHILIGHT (atlctrlw.h).
I have a VS2008 C++ application for Windows XP SP3 developed using WTL 8.1. My application contains a tab control that flickers when the application border is resized.
My window hierarchy looks like this:
CFrameWindowImpl CMainFrm
|-CSplitterWindow Splitter
|-CTabView Configuration Tabs
| |-CDialogImpl Configuration View 1
| |-CDialogImpl Configuration View 2
| |-CDialogImpl Configuration View 3
|-CDialogImpl Control View
The solution I'm trying is to make the CFrameWindowImpl derived class use the WS_EX_COMPOSITED style and all windows beneath it use the WS_EX_TRANSPARENT style. Unfortunately, this makes the tab control buttons show as an empty black bar and the controls of any Configuration View to not show at all.
If I remove the WS_EX_COMPOSITED and WS_EX_TRANSPARENT styles, the form displays properly, but the CTabView and everything beneath it flickers horribly when resized.
What do I need to change to eliminate the flicker and draw the controls properly?
Thanks,
PaulH
Edit:
Got it working. I removed all the WS_EX_TRANSPARENT styles per Mark Ransom's suggestion. I put the WS_EX_COMPOSITED style on only the CTabCtrl (contained within the CTabView). Other controls get double-buffering as needed through WTL::CDoubleBufferImpl<>.
A window flickers because it gets erased before it's drawn. To eliminate this you need to disable erasing of the window entirely and use double buffering - draw the window contents into a bitmap, then copy the bitmap to the window. Because the bitmap contains the entire contents including the background, there's no need to erase anymore.
It looks like WS_EX_COMPOSITED will handle the double buffering automatically, but you still probably need to use a NULL background brush and/or handle the WM_ERASEBKGND message.
Whats not mentioned in MSDN is that the Desktop Window Manager - the component that hooks window painting on Windows Vista and 7 to perform the desktop composition necessary to get the aero glass effect - does NOT implement WS_EX_COMPOSITED.
Which means all the work you put into getting this style to work on XP, is doomed to become irrelevent on Vista or later.
The other problem with WS_EX_COMPOSITED - and why it was an optional style and not a default on XP: The double buffering only picks up painting performed during the BeginPaint / EndPaint block of the parent window. Lots of, even standard controls, perform painting outside of their WM_PAINT handlers, and as a result the backbuffer gets only partially painted.
Sadly, the result is, the only way to "eliminate" flicker in native API apps is to try to minimize it: WS_CLIPCHILDREN and WS_CLIPSIBLINGS can help if you dont have overlapping controls - to ensure that each control's area is painted only once. And ensure that the main dialog does not perform any flood filling in WM_ERASEBKGND
It is not, in my experience, possible to use double-buffering for anything that contains child controls (unless they all fully support WM_PRINT, which most do not).