i have a native win32 c++ application which has a checkbox in it. I want to replace the checkbox and create ON/OFF toggle button with 2 states (just like the checkbox). I've added the BS_OWNERDRAW style to the checkbox and drawn it to the window in WM_DRAWITEM. The problem is that when I click on the checkbox I get a WM_COMMAND message (just like without the BS_OWNERDRAW) but the CHECKED state doesn't change automaticly. Do I have to implement this functionality or am I missing something?
The code that handles clicking on the checkbox:
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
switch (wmId)
{
case IDC_CHECKBOX:
if(wmEvent == BN_CLICKED)
{
dwPos = SendMessage(checkBox, BM_GETCHECK, 0, 0);
if(dwPos == BST_CHECKED )
{
// do some stuff
} else if(dwPos == BST_UNCHECKED) {
// do some stuff
}
}
The problem is that every time i click on the checkbox BM_GETCHECK returns BST_UNCHECKED. If i remove the BS_OWNERDRAW it works fine.
Code that creates the button/checkbox:
checkBox = CreateWindowEx(
0,
WC_BUTTON,
szBuffer,
WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX | BS_OWNERDRAW,
BUTTON_ON_OFF_X, BUTTON_ON_OFF_Y,
BUTTON_ON_OFF_WIDTH, BUTTON_ON_OFF_HEIGHT,
hWnd,
(HMENU)IDC_CHECKBOX,
hInst,
NULL
);
Ordinarily, you would set BS_AUTOCHECKBOX to have the checkbox check/uncheck automatically in response to user input. However, according to the docs, you cannot combine other styles (e.g., BS_AUTOCHECKBOX) when using BS_OWNERDRAW.
http://msdn.microsoft.com/en-us/library/windows/desktop/bb775951%28v=vs.85%29.aspx
Yes. You will need to translate from your WM_COMMAND and toggle the internal check state with something like CheckDlgButton.
Related
I'm learning mfc, activex controls and containers. I'm doing a assignment on containers(Dialog).I have created a dialog, when I do right click, there are system menu items like Minimize, Maximize, Move, Size. All these items appeared by selecting true in dialog properties. I have added another item "Always on top" which will be appear on top. When the user click on Always on top I provided a message box which will say "Do you want enable?" I gave yes or no for that, but I have to avoid this message box and need to add a checkbox beside the Always on top item. So that whenever user wants the dialog to appear on top they can use the checkbox.
I have tried in one possible way by adding a bitmap image of checkmark but somehow it's not working and I have less time. If anyone has any idea how I can add this checkbox please let me know.
This is the code where I have appended the item
BOOL CDiagDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
CMenu * pSystemMenu = GetSystemMenu(FALSE);
pSystemMenu->AppendMenu(MF_ENABLED, IDM_SYSCOMMAND_CUSTOM,_T("Always on top"));
return TRUE; // return TRUE unless you set the focus to a control
}
void CDiagDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if (nID == IDM_SYSCOMMAND_CUSTOM)
{
AfxMessageBox(
_T("Enable Always on top"), MB_YESNO
);
switch (iResponse) {
case IDYES:
SetWindowPos(&CWnd::wndTopMost, 0, 0, 0, 0, SWP_NOSIZE);
break;
case IDNO:
SetWindowPos(&CWnd::wndNoTopMost, 0, 0, 0, 0, SWP_NOSIZE);
break;
}
}
else
{
CDialog::OnSysCommand(nID, lParam);
}
}
With this call
SystemParametersInfo(SPI_SETCLIENTAREAANIMATION, 0, (LPVOID)FALSE, 0);
I disable the animation of buttons in my Win32 C++ project (no MFC or anything else) that has Visual Styles Common Controls 6.0.0.0 enabled and correctly initialized by calling InitCommonControlsEx function. Is there an alternative method to do this? I am asking because I don't want to disable the animation for the whole system but ONLY for my application. The buttons I create are Custom Drawn (not Owner Drawn).
I create a button like this in the WM_CREATE message (hwndbutton is defined before as static so that I can share it between all WM messages):
hwndbutton = CreateWindowEx(0, L"BUTTON", L"example", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, x, y, width, height, hwnd, (HMENU)button_id, GetModuleHandle(NULL), NULL);
and I draw it
...
case WM_NOTIFY:
{
LPNMHDR item = (LPNMHDR)lParam;
if (item->idFrom == button_id && item->code == NM_CUSTOMDRAW)
{
LPNMCUSTOMDRAW item_draw = (LPNMCUSTOMDRAW)item;
if (item_draw->uItemState & CDIS_HOT)
{
SetDCBrushColor(item_draw->hdc, RGB(180, 180, 180));
SelectObject(item_draw->hdc, GetStockObject(DC_BRUSH));
}
else
{
SetDCBrushColor(item_draw->hdc, RGB(255, 255, 255));
SelectObject(item_draw->hdc, GetStockObject(DC_BRUSH));
}
SetDCPenColor(item_draw->hdc, RGB(0, 0, 0));
SelectObject(item_draw->hdc, GetStockObject(DC_PEN));
RoundRect(item_draw->hdc, item_draw->rc.left, item_draw->rc.top, item_draw->rc.right, item_draw->rc.bottom, 0, 0);
return CDRF_DODEFAULT; // Return would be CDRF_SKIPDEFAULT but I want to keep the text "example" drawn
}
break;
...
By "button animation", I mean for example the fading effect that takes place in the button color when you move the cursor over a button and then leave it: I would like it to be colorA when normale state or colorB when mouse is over and not colorA when normal and fade_until_you_reach_colorB when mouse is over.
Thanks
EDIT: I add two gifs
The first is what I want (and I obtain with a previous call to SystemParametersInfo) and the second is the animation I would like to avoid
What I want
What I DON'T want
Theme for individual windows and controls can be disabled as follows:
SetWindowTheme(hbutton, L" ", L" ");
Animation should already be disabled because you are using custom draw. This method will also disable mouse-hover effect.
Normally when you disable a button's theme it may look weird with old 3-D borders on newer systems. You can add BS_FLAT to button's style.
I have a problem using MESSAGE_MAP &/or PreTranslateMessage. This may be a design issue but I'm not sure. The main issue is MESSAGE_MAP code not being called & not sure how to do same via PreTranslateMessage. ie as follows:
//MyCDialogEx : public CDialogEx
class MyCDialogEx::Init()
{
CFlatSplitterWnd m_cSplitter; //http://www.codersource.net/2010/01/29/mfc-splitter-window/
m_pFrame = new CFlatFrameWnd;
m_pFrame->Create(strMyClass, L"", WS_CHILD, rect, this);
m_pFrame->ShowWindow(SW_SHOW);
m_cSplitter.CreateStatic(m_pFrame, 1, 2);
m_cSplitter.ModifyStyleEx(WS_EX_CLIENTEDGE, 0, SWP_NOSIZE | SWP_NOACTIVATE);
m_cSplitter.CreateView(0, 0, RUNTIME_CLASS(CHolderView), CSize(100, 100), &ccc);
CHolderView* pView = (CHolderView*)m_cSplitter.GetPane(0, 0);
ASSERT_VALID(pView);
pView->setWnd(&m_TreeCtrl);
pView->setOwner(this, IDC_TREECTRL);
const DWORD dwStyle = LBS_NOTIFY | WS_CHILD | WS_VISIBLE | TVS_HASBUTTONS | TVS_HASLINES
| TVS_LINESATROOT | TVS_CHECKBOXES | TVS_SHOWSELALWAYS | WS_BORDER | WS_HSCROLL | WS_TABSTOP;
m_TreeCtrl.Create(dwStyle, CRect(0, 0, 1, 1), pView, IDC_TREECTRL);
}
BEGIN_MESSAGE_MAP(MyCDialogEx, CDialogEx)
ON_NOTIFY_REFLECT(WM_ONMYCLICK, OnClickTreectrl) //this & following not called
ON_NOTIFY(NM_CLICK, IDC_TREECTRL, OnClickTreectrl)
ON_NOTIFY(TVN_ITEMCHANGED, IDC_TREECTRL, OnItemchangedTreectrl)
ON_NOTIFY(TVN_SELCHANGED, IDC_TREECTRL, OnSelchangedTreectrl)
ON_NOTIFY(TVN_KEYDOWN, IDC_TREECTRL, OnKeydownTreectrl)
END_MESSAGE_MAP()
BOOL MyCDialogEx::PreTranslateMessage(MSG* pMsg)
{
if (GetFocus() && GetFocus()->GetDlgCtrlID() == IDC_TREECTRL)
{
//what/how goes in here to catch NM_CLICK, TVN_ITEMCHANGED etc??
if (pMsg->message == WM_LBUTTONDOWN)
{
switch (LOWORD(pMsg->wParam))
{
case NM_CLICK:
break;
}
}
if (pMsg->message == WM_KEYDOWN)
TRACE(L"WM_KEYDOWN\n");
if (pMsg->message == WM_KEYUP)
TRACE(L"WM_KEYUP\n");
}
return MyCDialogEx::PreTranslateMessage(pMsg);
}
void MyCDialogEx::OnClickTreectrl(NMHDR *pNMHDR, LRESULT *pResult) //not called
{
TRACE(L"tree click\n");
*pResult = 0;
}
MESSAGE_MAP works if I house these in CHolderView class MESSAGE_MAP, but I rather not as it's just a container class & will possibly be used elsewhere in my project.
What I'd really like to do is use MESSAGE_MAP to minimize coding via PreTranslateMessage (& if it's possible to redirect to MESSAGE_MAP, how?). If I must resort to PreTranslateMessage or other, then how do I use this so I can catch the relevant NM_CLICK, TVN_ITEMCHANGED for tree control etc.
Thank you.
EDIT: oh & the following don't help, not relevant or don't sufficiently explain:
How to get Click Event of Treeview(CTreeCtrl) in MFC created at runtime?
How to redirect MFC messages to another object?
How can identify Mouse Click event in PreTranslateMessage?
The problem is that the tree view will send all its notifications to the parent window. And the parent windows is the CHolderWindow.
Messages are not routed like WM_COMMAND messages. So handler for WM_COMMAND messages may reside anywhere in the notification path.
But regular window control notifications are always handled in the direct parent of the window. In MFC you can redirect such notfications to the child window control itself. Using ON_..._REFLECT.
A trick can be: Set a pointer to a window to the holder window, that should receive all messages. Than accept all WM_COMMAND and all WM_NOTIFY messages in the holder window and resend them to the new window.
PreTranslateMessage is another thing. The target window always receives a call first. Than all parents will get a chance until somebody in the chain of PreTranslateMessage calls returns TRUE.
I have a RichEdit control in a dialog box. The RichEdit control displays RTF text. EM_AUTOURLDETECT causes the RichEdit control to properly format and recognize the hyperlink. When the mouse hovers over the link, the pointer changes to a hand, but the browser doesn't launch once the link is clicked.
Am I missing some kind of event handler code?
case WM_INITDIALOG:
{
// Create Richedit
HWND hwndRE = CreateWindowA("RichEdit20A", "", WS_CHILD | WS_BORDER | WS_VSCROLL | ES_READONLY | ES_MULTILINE, 10, 10, 480, 220, hDlgWnd, 0, hInst, 0);
SendMessage(hwndRE ,EM_AUTOURLDETECT,(WPARAM)TRUE,(LPARAM)0);
//SendMessage(hwndRE ,EM_SETEVENTMASK, 1, ENM_LINK | ENM_CHANGE);
ShowWindow(hwndRE, SW_SHOWNORMAL);
SETTEXTEX SetTextEx;
char* aboutdata = "{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang1033{\\fonttbl{\\f0\\fnil\\fcharset0 Verdana;}}\\viewkind4\\uc1\\pard\\qc\\b\\f0\\fs20 www.whateverdomain.com} ");
SendMessage(hwndRE, EM_SETTEXTEX,(WPARAM)&SetTextEx, (LPARAM)(LPCTSTR)aboutdata);
return TRUE;
}
You can try something like this:
case WM_NOTIFY:
switch (((LPNMHDR)lParam)->code)
{
case EN_LINK:
ENLINK * enLinkInfo = (ENLINK *)lParam;
if (enLinkInfo->msg == WM_LBUTTONUP)
{
// code which gets clicked URL using enLinkInfo->chrg and saves it in
// "urlString"
ShellExecute(NULL, "open", urlString, NULL, NULL, SW_SHOWNORMAL);
}
break;
.... // More cases on WM_NOTIFY switch.
}
break;
Basically, when the WM_NOTIFY code is EN_LINK, you get the clicked URL and launch it using ShellExecute.
Have a look at EN_LINK:
http://msdn.microsoft.com/en-us/library/bb787970(VS.85).aspx
I am creating my textbox with these options. I can Copy / Cut / Paste / Undo, but when I hit Select All it doesn't select all. I can right click and click Select All but CTRL + A doesn't do anything. Why?
wnd = CreateWindow("EDIT", 0,
WS_CHILD | WS_VISIBLE | ES_MULTILINE | WS_HSCROLL | WS_VSCROLL | ES_AUTOHSCROLL | ES_AUTOVSCROLL,
x, y, w, h,
parentWnd,
NULL, NULL, NULL);
Ctrl+A is not a built-in accelerator like Ctrl+C and Ctrl+V. This is why you see WM_CUT, WM_PASTE and WM_COPY messages defined, but there is no WM_SELECTALL.
You have to implement this functionality yourself. I did in my MFC app like this:
static BOOL IsEdit( CWnd *pWnd )
{
if ( ! pWnd ) return FALSE ;
HWND hWnd = pWnd->GetSafeHwnd();
if (hWnd == NULL)
return FALSE;
TCHAR szClassName[6];
return ::GetClassName(hWnd, szClassName, 6) &&
_tcsicmp(szClassName, _T("Edit")) == 0;
}
BOOL LogWindowDlg::PreTranslateMessage(MSG* pMsg)
{
if(pMsg->message==WM_KEYDOWN)
{
if ( pMsg->wParam=='A' && GetKeyState(VK_CONTROL)<0 )
{
// User pressed Ctrl-A. Let's select-all
CWnd * wnd = GetFocus() ;
if ( wnd && IsEdit(wnd) )
((CEdit *)wnd)->SetSel(0,-1) ;
}
}
return CDialog::PreTranslateMessage(pMsg);
}
Note, I stole IsEdit from this page: http://support.microsoft.com/kb/145616
I point that out partly because I want to give credit, and partly because I think the IsEdit function (comparing classname strings) is dorky and I want to give blame.
You could simply use EM_SETSEL message to the textbox,
According to MSDN ,
If the start is 0 and the end is –1, all the text in the edit control is selected. If the start is –1, any current selection is deselected.
so,
SendMessage(hwndEdit,EM_SETSEL,0,-1);
Will work fine.
I tend to use MFC (forgive me) instead of Win32 so I cannot answer this definitively, but I noticed this comment added to a page on an MS site concerning talking with an Edit control (a simple editor within the Edit control):
The edit control uses WM_CHAR for
accepting characters, not WM_KEYDOWN
etc. You must Translate() your
messages or you ironically won't be
able to edit the text in the edit
control.
I don't know if this applies to BoltBait's response, but I suspect it does.
(I found this at http://msdn.microsoft.com/en-us/library/bb775462(VS.85).aspx)
You need to capture that keystroke and do the select all yourself.
Here is some C# code for use with a RichTextBox:
protected override void OnKeyDown(KeyEventArgs e)
{
// Ctrl-A does a Select All in the editor window
if (e.Control && (e.KeyCode == Keys.A))
{
this.SelectAll();
e.Handled = true;
}
}
Sorry, I don't have Win32 code for you.
The strange thing is that Ctrl+A DOES work (as select all), if you do NOT specify ES_MULTILINE
But that doesn't help if you need multiline
The MSDN documentation for ES_MULTILINE doesn't appear to say anything about this.
Could it be that something else is stealing Ctrl+A? Use Spy++ to verify that it reaches your edit control.
Why not add an accelerator for Ctrl+a to SelectAll?