I created a simple MFC ribbon app using the App Wizard. Then, I removed all the controls in the ribbon and added a simple button, and two edit boxes, and added event handlers for each.
The event handler for the button is a simple message loop as followed :
void CRibbon2Doc::OnButton(){
MSG msg;
while (1){
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
And the message handlers for the two Edit Boxes are also simple as followed:
void CRibbon2Doc::OnEdit1(){
OutputDebugString(_T("Box1"));
}
void CRibbon2Doc::OnEdit2(){
OutputDebugString(_T("Box2"));
}
Here is my problem :
Case : Button not clicked, i.e. my message loop not running
In this case, when I click on an Edit Box, I immediately see the blinking cursor that lets me write inside the Edit box. No problem here.
Case : Button clicked, i.e. my message loop is running
In this case, when I click an Edit Box, I do not see a blinking cursor that will let me write inside the edit box. I need to double click for the blinking cursor to show up. This is a problem, I would like to avoid making the users double click inside a box just to activate it.
Can you please tell me what could be the reason, and how to make it such that I can obtain a blinking cursor inside the edit boxes on a single click in the case where my message loop is running in the background.
I am basically struggling with a real life problem, and this is a simplified version of the problem, and a lot is on the line, please help.
Related
I have an application in which users, upon logging in, are prompted with a modal dialog where they must choose the facility they wish to work out of. At this stage, the application looks like this:
The modal dialog is shown by calling this method:
bool __fastcall ShowFacChoiceForm()
{
TFacChoiceForm *Form = new TFacChoiceForm( Application );
bool Result = ( Form->ShowModal() == mrOk );
delete Form;
return Result;
}
In this case, TFacChoiceForm inherits from TForm so the ShowFacChoiceForm() function is calling the standard TForm.ShowModal method documented here.
The issue I am running into is that if my application loses focus, it cannot become the active window again unless the modal dialog itself is clicked. To better illustrate this, I will present the following scenario:
Lets say its Friday afternoon and I decide to goof off a bit and read some web comics. With my application open, I open up another window on top of it, like so:
Then, out of nowhere my boss comes in for a performance review, and I attempt to refocus my application by clicking somewhere on the main form. For example, at the position of this red X in the next image.
In the above image, I have clicked at the location of the red X. Now, both the form containing the web comic, and my application are inactive. Thus, my application does not come to the front of the screen.
However, if I am able to click somewhere on the modal dialog, like the red X in the following image...
...then my application comes to the front like one would expect.
To solve this, I have looked at using something like SetForegroundWindow from the Windows API, but I have not been able to find a way to trigger the event, since my main form does not fire events while I have a modal dialog open.
My question is, how can I make sure that if the user clicks anywhere on my application that it is brought to the front? Is there a property I can edit in my form to do this?
If you set modalresult to mrcancel in the ondeactivate of the modal dialog then the main form will get focus when its clicked. You can then check if the user is logged in the mousedown event of the main form and if not, show the modal dialog again.
I'm working on an application to detect a pop-up dialog and then
automatically dismiss it. I'm writing this as a C++/Win32 app. The
dialog box is generated by IE 7 and I can detect the window, but
several methods to get the OK button to "click" have failed.
Doing searches for other people's solutions, sending these messages to
the button handle seems to have worked in a lot of situations:
PostMessage( handle, WM_LBUTTONDOWN, 0, 0 );
PostMessage( handle, WM_LBUTTONUP, 0, 0 );
PostMessage( handle, BM_SETSTATE, 1, 0 );
It has no effect on the button state in my tests though.
I can send tab characters to the main window and see that the OK
button gets focus, but then sending return characters does nothing.
To learn more about this I used Spy++ to get information about the
window hierarchy and what messages are delievered when I manually
click the OK button.
Looking at the message log and reading about WM_MOUSEACTIVATE seamed
to offer a solution. The log info shows that 0002166C was the button
window. So in my code I tried this:
GetClassNameA( handle, str, str_size );
if( strcmp( str, "Internet Explorer_Server" ) != 0 )
return TRUE; // Not the window we're interested in.
// Send a message to activate the button window and have it process a mouse click.
PostMessage( handle, WM_MOUSEACTIVATE, (WPARAM) dialog_handle, MAKELPARAM( HTCLIENT, WM_LBUTTONDOWN );
Based on the window hierarchy and message log, I think the window with
the class name "Internet Explorer_Server" is the button. Maybe I'm
wrong, because it does seem like an odd class name for a button...
Below is a link to the window hierarchy image, message log when I
manually click the OK button. Last is the code that's executed on a 1
second timer ticket, looking for the window.
Any insight and help is appreciated!
Image of the window hierarchy, source, window messages, and test dialog source are available here:
https://sites.google.com/site/matthewmillersmiscellanea/Home/
Ideally, you should create a DLL which exports a Global CBT Window Hook. This would allow you to get early notification when a dialog is going to be created. This would avoid the need to drain resources by constantly polling.
Once you've detected that a dialog is about to be created, you have two options:
1) Prevent the dialog creation.
I don't recommend this, it causes all sorts of problems with code that was fully expecting a valid HWND to be returned by CreateDialog();
2) Asynchronously control the dialog.
We achieved this by using PostMessage with a Registered user message and picking it up by hooking the WNDPROC. When you get this message, then you have to decide how to kill the dialog that you're in.
There are multiple ways to exit the dialog:
a) Simulate pressing OK, Cancel, Abort, No buttons using WM_COMMAND(BN_CLICKED) (as Chris comments). You can use GetDlgItem(), look for the WindowText and make your choice. However, this doesn't work for non-US-English. There may be some distance in leveraging the Accessibility API here though.
b) Simulate closing the dialog with PostMessage(WM_CLOSE, m_hWnd). This doesn't always work as expected - some dialogs have no [X] close button and their client code is expecting a specific button to be pressed instead.
c) Simulate user input using the SendInput() API. This worked around dialogs that had anti-popup-killer code in them :)
Our final solution was a rule+heuristic-based approach that had a configuration file which we could tweak when the app/IE dialogs changed their ID's, class names or parent class names.
To close continually a specific popup given that you know the window class name and window caption
#define UNICODE
#include <windows.h>
#pragma comment(lib, "user32")
int main (int nn, char ** aa)
{
while (true) {
HWND iHandle = FindWindow (L"theWindowClassName", L"theWindowCaption");
if (iHandle > 0) SendMessage(iHandle, WM_SYSCOMMAND, SC_CLOSE, 0);
Sleep (200); // check 5 times per second
}
return 0;
}
if one is not known or too generic (e.g. "Dialog") you can omit it by passing a null
HWND iHandle = FindWindow (L"theWindowClassName", 0);
or
HWND iHandle = FindWindow (0, L"theWindowCaption");
of course this will close all windows with the given names.
If I click anywhere on the dialog window, like in the "background", or on a Static Text, the function OnLButtonDown() is fired. But if I click a ListBox/EditBox/Combo/Calendar/Checkbox etc is not fired.
I thought that because these have control variables atached to it, and the Static Text don't. But adding a new Listbox to my Dialog and testing, I see that it doesn't fire either, so now I am confused...
I added OnLButtonDown() with the Class Wizard, it appears in:
BEGIN_MESSAGE_MAP(CMFCTesting2Dlg, CDialogEx)
ON_WM_SYSCOMMAND()
// other handlers, etc
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
END_MESSAGE_MAP()
My function:
void CMFCTesting2Dlg::OnLButtonDown(UINT nFlags, CPoint point)
{
AfxMessageBox(CString("BUTTON DOWN"));
CDialogEx::OnLButtonDown(nFlags, point);
}
I tried calling CDialogEx:: ... before AfxMessageBox... but same result.
The CListBox item, has the Notify option set to True, as I seen some advices in other posts.
I suspect that the WM notification message is captured somehow by the ListBox, and not sent "forward" to my CMFCTesting2Dlg, but I understood that this should happen with the Notify option set to True, on the ListBox, no? (well, obviously, not...)
Sorry, I am new to dealing with WM in MFC.
BTW, I use Visual Studio 2010 Ultimate, and this is a Visual C++ - MFC- MFC Application - Dialog Based project.
How can I capture this mouse down event if clicked on a listbox / combo / etc?
On the LONG STORY, I am actually trying to accomplish this issue:
I have two listboxes (lets say), and I want to scroll them synchronously, when user scrolls one of them, others must scroll the same (or update in the next moment). And I thought of using on mouse down to track the position of every Listbox (with the GetTopIndex), and on mouse up, to GetTopIndex again and compare with the previous ones. If a change was made, then a listbox was scrolled and then update all listboxes with SetTopIndex. The unfriendly solution for the user, but simpler for me, would be clicking a button that does this verification / update, but its not elegant at all, and it can only set them at the same level, but can't determine which one was scrolled last time. This automatically scrolling of the listboxes should be made just for displaying, it is not important the selections in the listboxes. I tried using the Message Type in the Add Event Handler for the Listbox, but none that are displayed work for my problem, KillFocus and SetFocus, are not fired if the scroll-bar is dragged, only if an item in the listbox is clicked... and I didn't succeed on the others message type either, from the Add Event Handler.
Once a window handles a message, it stops being sent to the other windows beneath it. A static window doesn't handle a mouse down, so it goes to the dialog. The other controls all handle it in some fashion (setting focus at least) so it never gets to the dialog.
You can override the OnLButtonDown handler in each of the controls to do something else once they've finished their default handling in the base class. You might also get to see the message in the PreTranslateMessage method of the dialog.
As far as getting the List Controls to sync scrolling goes, your best bet would be to intercept WM_VSCROLL by subclassing CListCtrl or perhaps by PreTranslateMessage, and then calling SetScrollInfo on the other list. If the number of items in the lists are the same, it should be fairly simple.
I have a windows gui built in Microsoft Visual C++ and when the user performs a certain set of actions the keyboard tabbing to move from widget to widget stops working.
Simply put, there are two list boxes with an add and a remove buttons. Selecting a row in listbox #1 and pressing the add button removes the object from list box #1 and moves it to list box #2. The problem I am seeing is that the keyboard tabbing functionality goes away since the tab focus was on the add button which become desensitized when the add callback is completed (since no row in list box #1 is selected currently).
I want to be able to re-set the tab focus to listbox #1 (but not the selection of a particular row). Any ways to do this? I believe I am running as a standard modal dialog.
If I understand correctly, you just want to set the focus back to one of the listboxes. Since this is in a dialog, instead of calling SetFocus, The Old New Thing recommends you send a message to the listbox's hWnd to do this:
void SetDialogFocus(HWND hdlg, HWND hwndControl)
{
SendMessage(hdlg, WM_NEXTDLGCTL, (WPARAM)hwndControl, TRUE);
}
i have a button that is a rectangle how would i put words in it i want to make so ican click the word and it starts the progrma i know ShellExecute the style is BS_GROUPBOX
If you have more than one program you want to start, you need a button per program you want to start.
To start you external progrma, in the button parent window, you need to process the WM_COMMAND message with the BN_CLICKED notification.
To set the text of the button, you need to send WM_SETTEXT message to the button with the text you want shown.
Btw, BS_GROUPBOX is used for creating the rectangle around radio buttons. This style is not going to work for your scenario.
If you want an alternative to using multiple Button controls, you can use a Toolbar. In fact, it seems to me that a toolbar would be a better control for you. You can read more about creating a toolbar.