How to allign text on ribbon button? - c++

as adding a ribbon button, I am also supplying the name for it. It is performing its desired action, but placement of string is absurd. It should not be over the image, but under it. Any suggestions please. Adding code snippet and screenshot.
RibbonButtonProp* mRibbonProperties;
bool m_bsetlargeimage = FALSE;
if (ButtonProp.Lookup(m_nMenuItemID, mRibbonProperties) != 0)
{
if (ButtonProp[m_nMenuItemID]->m_bIfSmallButton == FALSE)
{
m_PanelImage.SetImageSize(CSize(32, 32));
m_PanelImage.Load(ButtonProp[m_nMenuItemID]->m_nImageResourceId);
m_bsetlargeimage = TRUE;
}
else
{
m_PanelImage.SetImageSize(CSize(16, 16));
m_PanelImage.Load(ButtonProp[m_nMenuItemID]->m_nImageResourceId);
m_bsetlargeimage = FALSE;
}
pRibbonButton = new CMFCRibbonButton(m_nMenuItemID, m_strMenuItemName, m_PanelImage.ExtractIcon(ButtonProp[m_nMenuItemID]->m_nImageIndex));
pRibbonButton->SetAlwaysLargeImage(m_bsetlargeimage);
Print should be just under the image

There is no way to change this. This is the way ribbons are shown and drawn.
A button text in "large-mode" is always drawn below the icon. I see nothing in the code to change this behavior AND I would never change this, because it is the default behavior people want/expect to see in a standard ribbon.

Earlier
AddCategory(m_strMenuName, NULL, NULL, NULL, NULL, i, NULL);
Now
AddCategory(m_strMenuName, NULL, NULL, CSize(16,16), CSize(32, 32), i, NULL);
Explanation: It was placing the text assuming that all the image size is small only as it was not defined already while calling create.

Related

ExtractIconEx: works but occasionally crashes

I'm extracting icons from a file and displaying them in a dialog
const LPCWSTR path = L"c:\path\to\file";
const UINT nIconsCheck = ExtractIconEx(path, -1, nullptr, nullptr, 0);
if(nIconsCheck > 0)
{
HICON *iconHandles=new HICON;
const UINT nIcons = ExtractIconEx(path, 0, iconHandles, nullptr, nIconsCheck);
if(nIcons == nIconsCheck && nIcons != unsigned(-1))
{
IconSelect iconSelect(this); //dialog
for(UINT i=0; i<nIcons; i++)
{
qDebug() << i;
iconSelect.addIcon(QtWin::fromHICON(iconHandles[i])); //fromHICON returns QPixmap
DestroyIcon(iconHandles[i]);
}
iconSelect.exec();
}
}
The icons are being loaded correctly in the dialog, but sometimes it unpredictably causes the application to crash.
Any idea what is going on?
Documentation on ExtractIconEx
Edit: Thanks for the quick and helpful answers. Below is the complete working code I am using atm:
// In my case I have a QString `filePath`
// `QString::toWCharArray` retrieves a non-0-terminated string,
// so append a 0 to `path`
std::vector<WCHAR> path(unsigned(filePath.length())+1);
filePath.toWCharArray(path.data());
path.at(path.size()-1) = 0;
// Get number of icons in selected file
UINT nIcons = ExtractIconEx(path.data(), -1, nullptr, nullptr, 0);
if(nIcons == 0)
{
// Try to find associated file that contains icon(s)
// If found, `path` is replaced with the new path
WORD index=0;
DestroyIcon(ExtractAssociatedIcon(GetModuleHandle(nullptr), path.data(), &index));
// Get number of icons in associated file
nIcons = ExtractIconEx(path.data(), -1, nullptr, nullptr, 0);
}
if(nIcons > 0)
{
// Get array of HICONs
std::vector<HICON> iconHandles(nIcons);
nIcons = ExtractIconEx(path.data(), 0, iconHandles.data(), nullptr, nIcons);
for(UINT i=0; i<nIcons; i++) // Using iconHandles.size() is possibly safer,
// but AFAIK nIcons always carries the correct value
{
// Use iconHandles[i]
// In Qt you can use QtWin::fromHICON(iconHandles[i]) to generate a QPixmap
DestroyIcon(iconHandles[i]);
}
}
HICON *iconHandles=new HICON;
Here you are allocating only a single HICON object. If there are more than one icons in the given file, the next call to ExtractIconEx() creates a buffer overrun by writing past the allocated memory. You have entered the dark world of undefined behaviour.
To fix this problem, you could use a std::vector like this:
std::vector<HICON> iconHandles(nIconsCheck);
const UINT nIcons = ExtractIconEx(path, 0, iconHandles.data(), nullptr, iconHandles.size());
iconHandles.resize(nIcons); // Resize to the actual number of icons.
// Instead of: if(nIcons == nIconsCheck && nIcons != unsigned(-1))
if(!iconHandles.empty())
{
// Use icons
}
This has the advantage over manual allocation, that you don't need to delete the allocated memory. The vector destructor will do it automatically when the scope ends. Though you still have to call DestroyIcon() for each icon handle.
From the documentation you linked to:
Pointer to an array of icon handles that receives handles to the large icons extracted from the file. If this parameter is NULL, no large icons are extracted from the file.
You only gave it a pointer to one icon handle.
Allocate an array as large as the function expects; from the look of it, that means nIconsCheck elements. A vector is good for this, as zett42 says.

Using Qt control panel function in OpenCV error NULL pointer

I tried to google my question in several website but it still no answer.
My problem is look like this http://opencv-users.1802565.n2.nabble.com/Runtime-error-for-createTrackbar-in-control-panel-td7550203.html
I tried to create the control panel in OpenCV window using Qt integration as show in an example of OpenCV Document: http://docs.opencv.org/modules/highgui/doc/qt_new_functions.html
By this function, it should be separate between image window (with 'imshow()') and control panel (with in other window, called control panel).
However, it is not work when run to the code 'createTrackbar(num1, NULL, &val1 , 255, NULL);' the error message 'Null pointer' is shown. However, if I change the parameter to the window name it is work!.
My code is like this:
#include <...opencv.hpp>
#include <...highgui.hpp>
char* num1 = "testTrack";
int val1 = 100;
const string mainwin = "show";
int main()
{
while (true)
{
frame = capture();
createTrackbar(num1, NULL, &val1 , 255, NULL);
process_frame = image_processing(frame);
imshow(mainwin, process_frame);
// [Exit the system]
if (condition)
break;
}
}
Do you have any idea?
I don't know if this answer is useful after all this time, but you need to use an empty string instead of a null pointer.
Try with:
createTrackbar(num1, "", &val1 , 255, NULL);

Changing color of a specific character in an item in CListCtrl in MFC

I have a CListCtrl and I need to change the color of A SPECIFIC character/set of characters (which I choose by comparison) from the text of every cell in the list.
I know how to change the color of the entire text of the cell when I find the character/set of characters (by using 'strstr' command), but I can't find an example which shows how to change ONLY the character/set of characters.
Here is a sample of my code:
void Agenda::OnCustomdrawMyList( NMHDR* pNMHDR, LRESULT* pResult )
{
NMLVCUSTOMDRAW* pLVCD = (NMLVCUSTOMDRAW*)pNMHDR;
*pResult = CDRF_DODEFAULT;
if (CDDS_PREPAINT == pLVCD->nmcd.dwDrawStage)
{
*pResult = CDRF_NOTIFYITEMDRAW;
return;
}else if (CDDS_ITEMPREPAINT == pLVCD->nmcd.dwDrawStage)
{
*pResult = CDRF_NOTIFYSUBITEMDRAW;
return;
}else if ( (CDDS_SUBITEM | CDDS_ITEMPREPAINT) == pLVCD->nmcd.dwDrawStage )
{
// So right now I am in the stage where a SUBITEM is PREPAINTED
int nItem = pLVCD->nmcd.dwItemSpec;
int nSubItem = pLVCD->iSubItem;
char a[100];
listControl.GetItemText(nItem,nSubItem,a,100);
COLORREF textColorFound, textColorDefault;
textColorDefault = RGB(0,0,0);
pLVCD->clrText = textColorDefault;
char* startingFrom;
if( (startingFrom = strstr(a,filterText)) != NULL ) {
// Could I set a pointer here or something like that so
// the coloring could start only from 'startingFrom'
// and stop at 'strlen(filterText)' characters?
textColorFound = RGB(205,92,92);
pLVCD->clrText = textColorFound;
}
*pResult = CDRF_DODEFAULT;
}
}
listControl is the variable for my CListCtrl
the other things are pretty self-explanatory
No, you cannot do this. What you will have to do is custom-draw the text in question. This will be tricky because you will have to do it with two different calls, between which you will have to manually adjust the color and the drawing location to account for the intercharacter spacing etc. And you better hope that you don't need to do multi-line output.
Take a look at the article Neat Stuff to Do in List Controls Using Custom Draw by Michael Dunn on CodeProject to get some ideas on how to proceed.
Alternatively, if you can use the Toolkit Pro toolkit from CodeJock you can leverage their "XAML" support (I use quotes because it's not really XAML, but their own implementation of a subset of XAML) and let them do all the hard work.
Digging on the same issue; But I wouldn't go so far as modifying/adding to the default Windows behaviour for painting strings... apparently that would be the endpoint of having it owner-drawn.(aici am murit si eu :).

MFC VC++ Custom Checkbox Image

How do I get a 3-state checkbox to use a different bitmap for the Indeterminate state?
I want to change the image used by my 3-state checkboxes to use a different one; the controls are in Win98-style, and the indeterminate state of such checkboxes is difficult to distinguish from disabled checkboxes (this is presumably why they changed this for the WinXP-style controls, but I cannot use those because of other details in my project).
I'm using Visual C++ 2010, and I've defined an 8x8 bitmap in VS's Resource Editor. The bitmap's ID is IDB_INDET_CHECK.
I'm not entirely sure what the standard "technique" for something like this is; I've only really just started getting into manipulating Windows controls and MFC.
My first attempt was to create a class, CTriButton, that derives from CButton, override the DrawItem function, and try to draw it myself. I then used SubclassDlgItem to turn one of the checkboxes in my window into this class (I think?). This... sort of works? The checkbox no longer appears, and if I click on where it should be, an empty checkbox frame appears, but nothing else happens (and the debug message in my code is not being sent).
Here's the relevant code, though I'm not sure any of this is right. First, code from my window's OnInitDialog.
BOOL CAffixFilterDlg::OnInitDialog() // CAffixFilterDlg is my CDialog-derived window
{
CDialog::OnInitDialog(); // call basic version
// subclass a CButton-derived control with CTriButton
if ( CBipedHead.SubclassDlgItem(IDC_HEAD, this) ) // CBipedHead is a CTriButton member of CAffixFilterDlg, IDC_HEAD is a checkbox
SetWindowLong(CBipedHead.m_hWnd, GWL_STYLE, CBipedHead.GetStyle() | BS_OWNERDRAW); // set the ownerdraw style
else // subclassing didn't work
_ERROR("Subclassing failed."); // I do not see this error message, so SubclassDlgItem worked?
// initialization continues, but is not relevant...
UpdateWindow();
Invalidate();
return TRUE;
}
Next, the code for my custom button's DrawItem.
void CTriButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
_DMESSAGE("Drawing TriButton"); // never see this message
CDC dc;
dc.Attach(lpDrawItemStruct->hDC); //Get device context object
int nWidth = GetSystemMetrics(SM_CXMENUCHECK);
int nMargin = ( nWidth - 8 ) / 2;
CRect textRt = lpDrawItemStruct->rcItem;
textRt.right = textRt.right - nWidth - nMargin;
CString text;
GetWindowText(text);
UINT textDrawState = DST_TEXT;
if ( lpDrawItemStruct->itemState & ODS_DISABLED )
textDrawState |= DSS_DISABLED;
dc.DrawState(CPoint(textRt.left, textRt.top), textRt.Size(), text, textDrawState, TRUE, 0, (CBrush*)NULL);
CRect rt = lpDrawItemStruct->rcItem; // initial rect is for entire button
rt.left = rt.right - nWidth; // set left margin
LONG center = ( rt.bottom + rt.top ) / 2;
rt.top = center - nWidth/2;
rt.bottom = center + nWidth/2;
UINT checkDrawState = DFCS_BUTTONCHECK;
if ( lpDrawItemStruct->itemState & ODS_DISABLED )
checkDrawState |= DFCS_INACTIVE;
if ( lpDrawItemStruct->itemState & ODS_CHECKED )
checkDrawState |= DFCS_CHECKED;
else if ( GetCheck() == BST_INDETERMINATE ) {
_VMESSAGE("Indeterminate; custom draw.");
CBitmap indet_check = CBitmap();
indet_check.LoadBitmap(IDB_INDET_CHECK);
CPoint pt = CPoint(rt.left + nMargin, rt.top + nMargin);
CSize sz = CSize(8, 8);
dc.DrawState(pt, sz, &indet_check, DST_BITMAP|DSS_NORMAL);
}
dc.DrawFrameControl(rt, DFC_BUTTON, checkDrawState);
}
In OnInitDialog() you need to call InvalidateRect() after changing the window style otherwise it doesn't know it needs to be redrawn. It's also a good idea to call UpdateWindow() after changing window styles. Some information is usually cached by the common controls and won't acknowledge the change until UpdateWindow() has been called.
In DrawItem() you are responsible for rendering all states of the control. You should not call CButton::DrawItem() as it does nothing. Try something like the following:
void CTriButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
CBitmap indet_check
_DMESSAGE("Drawing TriButton"); // I never see this message
int checkState = GetCheck();
if ( checkState == BST_CHECKED )
{
indet_check.LoadBitmap(IDB_INDET_CHECK);
}
else if ( checkState == BST_UNCHECKED )
{
indet_check.LoadBitmap(IDB_INDET_UNCHECKED);
}
else if ( checkState == BST_INDETERMINATE )
{
indet_check.LoadBitmap(IDB_INDET_INDETERMINATE);
}
// ... rest of your drawing code here ...
// don't forget to draw focus and push states too ;)
}
Addendum:
I can't believe I missed this first time around but your call to SubclassDlgItem is probably not having the desired effect. This call causes messages intended for the button to be processed by the controls parent window first. Because the default implementation of DrawItem in CWnd (the superclass of CDialog) does nothing the message never gets passed to the control.
Replace this with the following snippet and everything should be ok:
HWND hWndButton;
GetDlgItem(IDC_HEAD, &hWndButton);
CBipedHead.SubclassWindow(hWndButton);
Two side notes here:
It's usually not a good idea to use the same naming convention for both classes and class members. It makes for a confusing read.
I'm guessing you are always compiling and running in release mode. If you are - don't. This prevents assertions from being thrown and letting you know something is wrong.
Not the answer, but an answer: this custom CCheckBox I found more-or-less enables what I want. It doesn't, by default, allow 3 states, but I fixed that up with some of my own tweaks. I'm not 100% sure it works out of the box (I've had some issues, that don't seem to be due to my edits, but I can't be sure), but it was the solution I've used. I'm not going to call this the answer, though, in case someone can spy what was wrong with my code and wants to illuminate me.

MFC - Printing - Changing page orientation from a custom pagesetup dialog

I am developing a custom print dialog and page setup using MFC and VS2008 for my Win32 program. Since the code is legacy, I can't take much advantage from MFC view/doc architecture. As a result, I wrote a printing code completely from scratch.
I setup CPrintInfo, instantiate my custom print dialog box and hook this dialog box to the CPrintInfo I just created. When my custom print dialog is up, I have a radio button to let a user toggles the page orientation. For some reasons, I couldn't modify the current DEVMODE at the run-time. As a result, every page I print will end up as a portrait.
Even if I manually set pDevMode->dmOrientation to DMORIENT_LANDSCAPE from the event handler of the custom print dialog, the printing result is still ended up as portrait. I am really not sure why this is happening and how to modify the DevMode after the print dialog is up.
Thank you in advance for any help.
Here is the code I have:
void PrintSomething(CWnd* currentWnd) {
// Create CPrintInfo
CPrintInfo* pPrintInfo = new CPrintInfo;
SetupPrintInfo(pPrintInfo); // simply setup some member variables of CPrintInfo
// Create a custom print dialog
CustomPrintDlg* pCustomPrtDlg = new CustomPrintDlg(FALSE, PD_ALLPAGES | PD_USEDEVMODECOPIES | PD_NOPAGENUMS
| PD_HIDEPRINTTOFILE | PD_NOSELECTION, pPrintInfo, currentWnd);
SetupPrintDialog(pPrintInfo,pCustomPrtDlg);
if ( AfxGetApp()->DoPrintDialog(pCustomPrtDlg) == IDOK ) {
... // proceed a print loop
}
}
Code for setting up the custom print dialog:
void SetupPrintDialog(CPrintInfo* pPrintInfo,CustomPrintDlg* pCustomPrtDlg) {
delete pInfo->m_pPD;
pInfo->m_pPD = pCustomPrtDlg;
pInfo->m_pPD->m_pd.hInstance = AfxGetInstanceHandle();
pInfo->m_pPD->m_pd.lpPrintTemplateName = MAKEINTRESOURCE(IDD_CUSTOM_PRTDLG);
// Set the Flags of the PRINTDLG structure as shown, else the
// changes will have no effect.
pInfo>m_pPD->m_pd.Flags |= PD_ENABLEPRINTTEMPLATE;
// Set the page range.
pInfo>m_pPD->m_pd.nMinPage = 1; // one based page numbers.
pInfo>m_pPD->m_pd.nMaxPage = 0xffff; // how many pages is unknown.
}
When a user toggles the radio button to Landscape, this function will be invoked:
void CustomPrintDlg::OnLandscapeChecked() {
// set the current Devmode to landscape
LPDEVMODE pDevMode = GetDevMode();
GlobalUnlock(pDevMode);
pDevMode->dmOrientation = DMORIENT_LANDSCAPE;
}
A pseucode for the custom print dialog class:
class CustomPrintDlg: public CPrintDialog {
... // just override some methods from CPrintDialog
};
Thanks again,
Unagi
I figured out the solution:
All I need is to call GlobalLock to obtain a pointer to the Devmode before changing the current DevMode.
void CustomPrintDlg::OnLandscapeChecked()
{
// set the current Devmode to landscape
LPDEVMODE pDevMode = GetDevMode();
GlobalLock(pDevMode);
pDevMode->dmOrientation = DMORIENT_LANDSCAPE;
GlobalUnlock(pDevMode)
}
Thanks again for helping me.
Nowhere in your example code do you show how you're creating the DC for printing. When you call CreateDC, you must pass a pointer to a DEVMODE structure; this defines whether the printing will be portrait or landscape.