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);
}
}
Related
I've played with PostMessage just clicking different tabs which seemed to work. But I'm trying to automate some button clicks and when running this function it highlights the button as if I was hovering over it but doesn't click.
I thought somehow the button changing of colour made the boolean false so I added the exception of the buttons colour whilst it's hovered. Made no difference, and I do not wish to use SetCursorPos & simulate a mouseclick using SendInput. I wish to understand the problem/issue I'm having as to why it's not clicking.
void click(const std::vector<uint_16>& x, const uint_16& y)
{
for(uint_8 i = 0; i < 5; i++)
{
if(content::MyClass().firstMatch(GetPixel(hdc, x[i], y)))
{
PostMessage(hwnd, WM_LBUTTONDOWN, 0, MAKELPARAM(x[i], y));
return;
}
}
if(content::MyClass().secondMatch(GetPixel(hdc, x[4], y)))
{
PostMessage(hwnd, WM_LBUTTONDOWN, 0, MAKELPARAM(x[4], y));
}
}
The solution you are using is unreliable because you are short-circuiting the input system on the window and not specifically targeting which button you are trying to press.
As for the reason your code is not currently working, you only send a WM_LBUTTONDOWN message to the window. Since most buttons work off a combination of WM_LBUTTONDOWN and WM_LBUTTONUP your program isn't causing the buttons click method to activate.
Adding PostMessage(hwnd, WM_LBUTTONUP, 0, MAKELPARAM(x[i], y)); after the mouse down will cause the button click to register.
In future as a more reliable solution that will specifically target a button on the window and click it you may want to look at the BM_CLICK PostMessage argument. Using this instead of trying to emulate a mouse click is more correct because windows will trigger events that may otherwise be forgotten when using the mouse down and mouse up post commands.
An example:
int retVal = 0;
HANDLE hwndDialog;
HANDLE hwndButton;
/* First, see if the dialog box (titled "Inactivity Warning" ) is currently open. */
hwndDialog = FindWindow( 0, "Inactivity Warning" );
if ( hwndDialog == 0 ) return;
/* Now get a handle to the "Resume" button in the dialog. */
hwndButton = FindWindowEx( hwndDialog, 0, 0, "Resume" );
/* After making sure that the dialog box is the active window, click "Resume". */
retval = SetActiveWindow( hwndDialog );
/* converted from SendMessage. */
retval = PostMessage( hwndButton, BM_CLICK, 0, 0 );
Source found Here, Converted from VB by me.
For some further reading on the input system Here is a good article.
A Blog Post by Raymond Chen goes into a bit of detail about these commands and their caveats as well.
I have a window with a listview which I would like to right click an entry in the listview and have certain options displayed in a context menu. I cant find any examples for C++. The similar question is here but this is for listbox and i cant make it work in my program
So far I could not find any examples for c++ online. I could make it work for WM_LBUTTONDOWN on my main window but not on listview. Anyway, this is my code which i cant make it work:
case WM_CONTEXTMENU:
if ((HWND)wParam == hWndListView) {
POINT cursor;
GetCursorPos(&cursor);
TrackPopupMenu((HMENU)GetSubMenu(LoadMenu(hInst, MAKEINTRESOURCE(IDR_CONTEXT)), 0), TPM_LEFTALIGN | TPM_RIGHTBUTTON, cursor.x, cursor.y, 0, hWnd, NULL);
}
break;
Any advise? Thanks
Answer:
case WM_NOTIFY:
// When right button clicked on mouse
if ((((LPNMHDR)lParam)->hwndFrom) == hWndListView)
{
switch (((LPNMHDR)lParam)->code)
{
case NM_RCLICK:
{
POINT cursor; // Getting the cursor position
GetCursorPos(&cursor);
// Creating the po-up menu list
TrackPopupMenu((HMENU)GetSubMenu(LoadMenu(hInst, MAKEINTRESOURCE(IDR_CONTEXT)), 0), TPM_LEFTALIGN | TPM_RIGHTBUTTON, cursor.x, cursor.y, 0, hWnd, NULL);
}
break;
}
break;
}
break;
This works under WndProc
INTRODUCTION AND RELEVANT INFORMATION:
I have made an application that needs to change the look of a cursor into hand when mouse hovers above the static control, but resets it to a normal cursor otherwise.
My initial application was in full screen mode, but recently terms have changed and it must have a resizable window.
This means that my handler for WM_SETCURSOR must be rewritten to reflect newly introduced changes.
Cursors are loaded in WM_CREATE, and I have defined class cursor, like this:
// cursors
case WM_CREATE:
hCursorHand = LoadCursor( NULL, IDC_HAND );
hCursorArrow = LoadCursor( NULL, IDC_ARROW );
// other stuff
In my class:
WNDCLASSEX wc;
// ...
wc.hCursor = hCursorArrow;
//...
This is my old WM_CURSOR handler ( code is simplified for clarity purposes ):
case WM_SETCURSOR:
if( (HWND)wParam == GetDlgItem( hwnd, 4000 ) )
SetCursor(hCursorHand);
else
SetCursor(hCursorArrow);
return TRUE;
If cursor hovers above static control, then my handler changes it to hand, else sets it to default cursor ( arrow ).
Bellow is the picture I have sketched in Paint that displays the desired look of the cursor when it hovers above static control, it is on the client area, and when user resizes window.
If additional code snippets are required, ask and I will edit my post, but for now, they are omitted to keep the post short and concise.
I work on Windows XP, using MS Visual Studio C++ and pure Win32 API.
MY EFFORTS TO SOLVE PROBLEM:
Bellow are the code snippets that I have tried, but they all failed:
First snippet:
case WM_SETCURSOR:
if( (HWND)wParam == GetDlgItem( hwnd, 4000 ) )
{
SetCursor(hCursorHand);
return TRUE;
}
else
return DefWindowProc( hWnd, msg, lParam, wParam );
Second Snippet:
case WM_SETCURSOR:
if( (HWND)wParam == GetDlgItem( hwnd, 4000 ) )
{
SetCursor(hCursorHand);
return TRUE;
}
break; // based on MSDN example
Third snippet:
case WM_SETCURSOR:
if( (HWND)wParam == GetDlgItem( hwnd, 4000 ) )
{
SetCursor(hCursorHand);
return TRUE;
}
else
return FALSE;
These set cursor to hand no matter where it is.
If I leave my WM_SETCURSOR handler unchanged, the only problem I get is that instead of sizing arrows, I get regular arrow ( as the cursor’s look ) when I hover over the border, but window can be sized.
If I comment out my WM_SETCURSOR handler, sizing arrows and cursor arrow appear properly, but cursor doesn’t change into hand when hovers above static control ( which is logical, since there is no WM_SETCURSOR handler to change it ).
I have browsed through SO archive, looked on MSDN, CodeProject , DaniWeb, Cprogramming and CodeGuru, but had no success.
Looking through those, I have found an example where people compare low word of the lParam against hit test code.
Looking through MSDN I have found link for hit test values ( http://msdn.microsoft.com/en-us/library/windows/desktop/ms645618%28v=vs.85%29.aspx ) and I have found link for cursor types (http://msdn.microsoft.com/en-us/library/windows/desktop/ms648391%28v=vs.85%29.aspx ).
Currently I am reading them, because I think that I will have to load additional cursor resources, take several comparisons of hit test values, and then use those resources to set cursor look accordingly.
QUESTION:
I really would like my WM_SETCURSOR handler to look like this:
case WM_SETCURSOR:
if( (HWND)wParam == GetDlgItem( hwnd, 4000 ) )
{
SetCursor(hCursorHand);
return TRUE;
}
else
// reset cursor's look to default
so I ask the community to instruct me on how to do this.
If this isn’t possible, then I will consider using multiple if statements to check the hit test code, and set cursor’s look accordingly.
Of course, if there is better solution for my problem, please suggest it, I will consider it as well.
Thank you.
Regards.
In general, if you handle the WM_SETCURSOR message you must either
Call SetCursor() to set the cursor, and return TRUE, or
If the message came from a child window, return FALSE for default processing, or
If the message is from your own window, pass the message through to DefWindowProc()
I think the last two points aren't made quite clear by the MSDN docs.
The window under the mouse pointer gets the first WM_SETCURSOR message. If it handles it and returns at that point, nothing else happens. If however it calls DefWindowProc(), then DWP forwards the message to the window's parent to handle. If the parent chooses not to handle it, it can return FALSE and the DefWindowProc processing will continue.
But this only applies if the message came from a previous call to DWP. If the message originated with the window itself, rather than a child, returning TRUE or FALSE without setting the cursor means the cursor won't be set at all.
Another thing: although your question didn't specify, I'm assuming from your use of GetDlgItem() that your top-level window is a dialog. If that's true, you can't just return TRUE or FALSE for a message - you need to return the value using SetWindowLongPtr() and store the return value in DWLP_MSGRESULT. Returning FALSE from a dialog procedure indicates that you didn't handle the message at all - this is equivalent to passing a message through to DefWindowProc().
So I think the proper handling for your situation is, in your top-level window:
case WM_SETCURSOR:
if( (HWND)wParam == GetDlgItem( hwnd, 4000 ) )
{
SetCursor(hCursorHand);
SetWindowLongPtr(hwnd, DWLP_MSGRESULT, TRUE);
return TRUE;
}
return FALSE;
If your top-level window isn't in fact a dialog, you would do this:
case WM_SETCURSOR:
if( (HWND)wParam == GetDlgItem( hwnd, 4000 ) )
{
SetCursor(hCursorHand);
return TRUE;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
Here's my first example, if cursor go to menubar, cursor changes to cursor hand:
HCURSOR cursorHand = LoadCursor(NULL, IDC_HAND);
case WM_SETCURSOR:
if(LOWORD(lParam) == HTMENU)
{
SetCursor(cursorHand);
}
break;
Here's my second example, if cursor goes to button, cursor changes to cursorHand:
HCURSOR cursorHand = LoadCursor(NULL, IDC_HAND);
case WM_SETCURSOR:
if(LOWORD(lParam) == buttonId)//declare you
{
SetCursor(cursorHand);
}
break;
Warning:menubar and button is not created! Create you and please, check my answer example.
The question as I understand it is, given a parent window with one more more child windows (one of which is a static control) how do you set the cursor to the hand when the cursor is over the static control, and the arrow when the cursor is over the client area of the parent window, and let default processing take place when the cursor is over a non-client area of the parent window.
To check things out, I wrote a simple program with a top-level window with a static control as a child window. My first attempt was the following:
1) Set the class cursor of the top-level window to LoadCursor(NULL, IDC_ARROW). This allows the default processing to set the cursor to the arrow when appropriate.
2) Keep track of the position of the mouse cursor by handling the WM_MOUSEMOVE message by calling my HandleWMMouseMove function as follows:
case WM_MOUSEMOVE:
HandleWMMouseMove(lParam);
break;
//ptCurrMousePos is a global variable of type POINT
static void HandleWMMouseMove(LPARAM mousepos)
{
ptCurrMousePos.x = (int)(short)(LOWORD(mousepos));
ptCurrMousePos.y = (int)(short)(HIWORD(mousepos));
}
3) and then all I had to do was handle the WM_SETCURSOR message by calling my HandleWMSetCursor function as follows:
case WM_SETCURSOR:
if (HandleWMSetCursor())
return TRUE;
break;
//hwndFrame is a handle to the top-level window.
//hwndStatic is a handle to the static control.
static BOOL HandleWMSetCursor(void)
{
if (ChildWindowFromPoint(hwndFrame, ptCurrMousePos)==hwndStatic) {
SetCursor(hCursorHand);
return TRUE;
}
return FALSE;
}
this worked fine but I couldn't understand how the code posted in the question was working even partially. So I asked the questioner whether the child window was really a static control. The answer was yes but it was created with the SS_NOTIFY style. So I created my child window with this style and my code stopped working, but the code posted with the question started to work. With the help of the Spy++ program distributed with Visual Studio I learned the following.
Static controls are normally transparent (not in the visual sense, but meaning that even when the mouse is over the transparent window, Windows will consider the mouse to be over the window underneath the transparent window).
When you create a static control with SS_NOTIFY the control is no longer transparent (i.e. it starts to receive an process mouse messages (like WM_MOUSEMOVE), so my code stopped working because it never received WM_MOUSE messages when the cursor was over the static control. On the other hand the code in the question did not work when the static control was created without SS_NOTIFY because without this style the static control was transparent, which meant that the WARAM in the WM_SETCURSOR message was never equal to the static control (in other words Windows never considered the mouse to be over the static control because it was transparent).
It is possible to combine the two approaches by changing the WM_SETCURSOR handler function to the following:
//hwndFrame is a handle to the top-level window.
//hwndStatic is a handle to the static control.
static BOOL HandleWMSetCursor(WPARAM wParam)
{
if (((HWND)wParam == hwndStatic) || (ChildWindowFromPoint(hwndFrame, ptCurrMousePos)==hwndStatic)) {
SetCursor(hCursorHand);
return TRUE;
}
return FALSE;
}
So I'm using Visual C++, and I have created a draggable, borderless window. Anyway, there is a toolbar along the top, and i want to be able to drag the window by that toolbar. I still want the toolbar to be functional, but i have no earthly idea how to be able to drag the window by it. This is my current window (see the toolbar on the top):
And this is my current code to make it draggable:
case WM_NCHITTEST: {
LRESULT hit = DefWindowProc(hWnd, message, wParam, lParam);
if(hit == HTCLIENT) hit = HTCAPTION;
return hit;
}
break;
You are on the right track with hooking WM_NCHITTEST. Now, you need to make change what constitutes a client hit versus a caption hit. If I understand your code right now, anywhere you click within the client area of the window (everything but the border) will allow you to drag the window elsewhere. This will make interacting with your application very difficult. Instead, you should be returning HTCAPTION only after you have determined that the hit was within the menubar area. Specifically, the area of the menubar that does not hold the File/Edit/Help buttons.
case WM_NCHITTEST: {
LRESULT hit = DefWindowProc(hWnd, message, wParam, lParam);
if (hit == HTCLIENT) { // The hit was somewhere in the client area. Don't know where yet.
// Perform your test for whether the hit was in the region you would like to intercept as a move and set hit only when it is.
// You will have to pay particular attention to whether the user is actually clicking on File/Edit/Help and take care not to intercept this case.
// hit = HTCAPTION;
}
return hit;
break;
}
Some things to keep in mind here:
This can be very confusing to a user that wants to minimize, close, or move your application. Menubars do not convey to the user that you can move the window by dragging them.
If you are concerned with vertical pixels you may consider doing what other applications on Windows are starting to do -- moving the menubar functionality to a single button that is drawn in the titlebar. (See recent versions of Firefox/Opera or Windows explorer in Windows 8 for some idea to move things to the titlebar.
In one of my applications I also wanted to make the window what I call "client area draggable". Unfortunately the mentioned solution (replacing HTCLIENT with HTCAPTION)
does have a serious flaws:
Double-clicking in the client area now shows the same behaviour as
double-clicking the caption (i.e. minimizing/maximizing the window)!
To solve this I did the following in my message handler (excerpt):
case WM_MOUSEMOVE:
// Move window if we are dragging it
if (mIsDragging) // variable: bool mIsDragging;
{
POINT mousePos = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
mIsDragging = (ClientToScreen(hWnd, &mousePos) &&
SetWindowPos(hWnd,
NULL,
mDragOrigin.left + mousePos.x - mDragPos.x,
mDragOrigin.top + mousePos.y - mDragPos.y,
0,
0,
SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE));
}
break;
case WM_LBUTTONDOWN:
// Check if we are dragging and safe current cursor position in case
if (wParam == MK_LBUTTON)
{
POINT mousePos = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
if (ClientToScreen(hWnd, &mousePos) &&
DragDetect(hWnd, mousePos))
{
// Check if the cursor is pointing to your new caption here!!!!
mIsDragging = true;
mDragPos = mousePos;
GetWindowRect(hWnd, &mDragOrigin);
SetCapture(hWnd);
}
}
break;
// Remove this case when ESC key handling not necessary
case WM_KEYDOWN:
// Restore original window position if ESC is pressed and dragging active
if (!mIsDragging || wParam != VK_ESCAPE)
{
break;
}
// ESC key AND dragging... we restore original position of window
// and fall through to WM_LBUTTONUP as if mouse button was released
// (i.o.w. NO break;)
SetWindowPos(hWnd, NULL, mDragOrigin.left, mDragOrigin.top, 0, 0,
SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
case WM_LBUTTONUP:
ReleaseCapture();
break;
case WM_CAPTURECHANGED:
mIsDragging = false;
break;
The (pseudo) code omits the return values (default: 0) and variable definitions but
should make the procedure clear anyway!? (If not drop me a line and I'll add more
or all code).
ps: I just found another comprehensive description which also explains the differences
of these two solutions: http://tinyurl.com/bqtyt3q
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.