How to set control focus inside an MFC custom control - c++

Experts!
I am using a class that inherits CWnd to make the content visible using a horizontal scroll bar
The control I want to create looks like this:
However, I have some problems and leave a question
When the button receives focus, it changes to blue. If another button is pressed, the button that received the existing focus should be unfocused.
The button does not release focus as shown in the second picture.
However, the above problem occurs when implemented in Dialog, not in SDI.
I need help solving this problem.
Custom Control Create Code;
m_ScrollWnd.Create(WS_CHILD | WS_VISIBLE, CRect(0, 0, 0, 0), this, 1234);
BOOL CScrollWnd::Create(DWORD dwStyle, CRect &rect, CWnd *pParent, UINT nID)
{
dwStyle |= ((WS_HSCROLL) );
return CWnd::Create(CScrollWnd::IID, nullptr, dwStyle, rect, pParent, nID);
}
m_Button3.Create(_T("Hello3"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, CRect(0, 0, 0, 0), this, 1238);

The so called "default button handling" is done by a function named IsDialogMessage.
The easiest way to control this is to make your parent control a window derived from CDialog, or if it's a view derive from CFormView. The MFC will handle all this for you in the appropriate PreTranslateMessage handler.
If you want to do this by your own you might insert your own PreTranslateMessage handler and use IsDialogMessage. The CWnd class also has a predefined implementation named CWnd::PreTranslateInput.
So this might be sufficient:
BOOL CYourParentClass::PreTranslateMessage(MSG* pMsg)
{
// allow standard processing
if (__super::PreTranslateMessage(pMsg))
return TRUE;
return PreTranslateInput(pMsg);
}
Using CFormView / CDialog is the better way from my point of view, because also other "problematic things about dialogs" are solved in it. Including loosing and getting focus and activation...

Official document from MSDN: Dialog Box Keyboard Interface
BTW, xMRi explains it very well.

Related

Can't show/hide buttons in the main window of my C++ Win32 app [duplicate]

This question already has answers here:
Access a variable from a different switch case (from WM_CREATE to WM_CTLCOLORSTATIC in the WinApi)
(2 answers)
Closed last month.
I have created a basic button in case: WM_CREATE in the windows procedure with the following.
/*The "new_game_button" is declared as type HWND at the
start of the windows procedure function but not initialized.*/
new_game_button = CreateWindow ( "BUTTON", "New Game",
WS_CHILD | WS_BORDER ,
50, 50, 100, 100,
hwnd, NULL, NULL, NULL);
My intent is to create an instructions and "start new game" button as the first thing in my simple tictactoe app. It will immediately show as expected if I give the parameter WS_VISIBLE.
Further in the same case:WM_CREATE if I use the lines
if (!start_Game){ //global variable default is false
ShowWindow( new_game_button, SW_SHOW);
}
The button will show as expected.
Outside of those two cases I cannot get the button to show at a later stage.
Further, if I use one of those two methods to show the button I can never get it to go away using
ShowWindow ( new_game_button, SW_HIDE);
Once the button is showing, it stays for the duration of the programs execution. Doesn't matter which case. Command/Create/Paint
I have tried using
if (start_Game){
ShowWindow( new_game_button, SW_HIDE);
UpdateWindow ( new_game_button );
//UpdateWindow ( hwnd ); tried this as well
}
inside case WM_CREATE.
I have also tried the same SW_HIDE line inside case: WM_COMMAND where a new game is generated (compiles but doesn't hide the button.)
I have tried declaring the button child window outside the WM_CREATE inside the windows procedure function. Then using WM_CREATE to show the window - works -- still WM_COMMAND will not hide the window.
I have also tried creating the button window inside of case:WM_PAINT which works to show the button but not to get rid of it. I have even tried DestroyWindow which just fails. [returns 0]
In trying to understand the behaviour of the button window - I have found that I cannot get
ShowWindow( new_game_button, SW_SHOW);
to work in the case:WM_COMMAND.
You said (in a code comment in the question).
new_game_button is declared as type HWND at the start of the windows procedure function but not initialized.
Each incoming message means a new call to your window procedure. Variables which are local to a function don't retain their value between calls unless they are marked static.
When your window procedure returned from processing WM_CREATE, you lost the value of new_game_button. When you try to use it during WM_COMMAND processing later, it is uninitialized and your program causes undefined behavior by passing it to ShowWindow.
Every comment helped me solve this which I appreciate. I am too new to give reputation sadly.
case WM_CREATE:
{
new_game_button = CreateWindow ("BUTTON", "New Game",
WS_CHILD | WS_BORDER ,
50, 50, 100, 100,
hwnd, (HMENU) 1, NULL, NULL);
if (!start_Game){
ShowWindow( new_game_button, SW_SHOW);
}
}
break;
After I had an ID for the dialog I am able to use GetDlgItem function to show or hide as I please.
new_game_button = GetDlgItem (hwnd, 1);
ShowWindow( new_game_button, SW_HIDE);

How to update the current state for window after showing/hiding controls?

I'm a beginner and today is my first day in learning to create Windows application.
I have two buttons.
#define BUTTON_SW 1
#define BUTTON_SW2 2
HWND Button1;
HWND Button2;
Button1 = CreateWindow("button", "Enter", WS_VISIBLE | WS_CHILD, 215, 10, 40, 25, hwnd, HMENU(BUTTON_SW), NULL, NULL);
Button2 = CreateWindow("button", "You'll be gone", WS_VISIBLE | WS_CHILD, 260, 10, 95, 25, hwnd, HMENU(BUTTON_SW2), NULL, NULL);
When Button1 is clicked, how can I hide Button2 or make it lose its WS_VISIBLE flag and reflect current situation correctly, like this?
LONG style = GetWindowLong(Button2,GWL_STYLE);
style = style | WS_VISIBLE; // style = style & ~WS_VISIBLE
SetWindowLong(Button2,GWL_STYLE,style);
This works very well. However, once WS_VISIBLE flag is assigned, button still stays invisible until the first mouseclick on it.
Vice versa, when I use style = style & ~WS_VISIBLE; once WS_VISIBLE flag is removed, button becomes passive (unclickable) but stays visible.
How to fix this? Tried many things that I've found online but couldn't fix it. Also please don't suggest me to buy a decent book, I don't have the money for now.
(P.S: ShowWindow function with SW_HIDE/SW_SHOW somehow doesn't work for me, perhaps I'm using it wrong. Can you help me on how I can hide this Button2 correctly? I'm trying the following command, but nothing happens.)
ShowWindow(GetDlgItem(Button2, 2), SW_HIDE);
#Edit: I've noticed that when I minimize the app and maximize it
again, the state of button updates. But how will it automatically
update the state?
This should work
ShowWindow(Button2, SW_HIDE);
or
ShowWindow(GetDlgItem(DialogHWND, BUTTON_SW2), SW_HIDE);
GetDlgItem needs HWND of the parent window (dialog) as first argument.
In order to a window to reflect changes you must ask the OS to do it.
Learn about RedrawWindow and the invalidated area.
Note that some actions, like resizing or restoring from minimized, automatically makes the OS to invalidate the region and redraw it.
Use:
RedrawWindow(Button2,NULL,NULL,RDW_INVALIDATE | RDW_INTERNALPAINT);

WS_EX_TOOLWINDOW tool windows doesn't work as expected

In our legacy code Windows extended style WS_EX_TOOLWINDOW is being used.This is basically for showing the title bar narrow.But recently in the later winodws versions the title bar is not drawn as narrow.That is WS_EX_TOOLWINDOW doesnt give a narrow title bar in the newer windows versions.Making the title bar narrow is done on a click event.Let me know if there is another way of achieving this?
I have read that we need to handle WM_NCCALCSIZE.But is there any other way of doing it?.Or if this is the only way,how can I handle it in a button click?
Code Snippet:
HWND hwnd = m_hWnd;
......
DWORD dwStylesEx = ::GetWindowLong( hwnd, GWL_EXSTYLE );
if ( bNarrowTitle == true)
{
dwStylesEx |= WS_EX_TOOLWINDOW;
}
else
{
dwStylesEx &= ~WS_EX_TOOLWINDOW;
}
...
::SetWindowLong( hwnd, GWL_EXSTYLE, dwStylesEx );
MSDN says:
Certain window data is cached, so changes you make using SetWindowLong will not take effect until you call the SetWindowPos function. Specifically, if you change any of the frame styles, you must call SetWindowPos with the SWP_FRAMECHANGED flag for the cache to be updated properly.
The default look just doesn't distinguish it in any way. Which suggests that you will just have to live with it.
It's probably been changed due to not being finger friendly if smaller!
Refer : WS_EX_TOOLWINDOW doesn't give look I want
As you said, handle WM_NCCALCSIZE may be the only way to handle the size of non-client areas.
Refer: How to set the size of the Non-client area of a Win32 window (native)

Create Button and Reference in message map

Im creating a button on my oncreate using message map.
I am unable to get a callback message from ON_BN_CLICKED when passing a reference to ICL_OK.
I don't believe its a parenting issue. The window is an CFrameWnd and parent is a CMainFrame.
Even getting all the messages and I can swtich between what I want to do as I have list boxes and input boxes to add also and edit / get response.
Thanks
Cant go into the gui main thread loop. Message map is the way I need to achieve this.
okBtn.Create(_T("Ok Button"), WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,
CRect(10, 10, BUTTON_WIDTH, HEIGHT), this, ICL_OK);
To click the button and get a response. Instead in using OnCmdMsg and getting a reference to its nID which I don't like. I want BN_CLICKED to work.
Refering to this answer
Message map macros
I can again confirm oncmdmsg works but wm_command event does not fire.
Message map macros
UPDATE: Still not working, alternative is to use ON_COMMAND_RANGE and still fires the WM_COMMAND so just have to restrict the amount of messages it handles. Hope it helps someone. If you want to generate a button the solution below might help you.
You are writing that the button is not showing in the window. There is a reason for that, and I would guess this: You define the button in a subroutine/method/function instead of defining it in its parent class.
Instead, in its parent class, whether that is the CMainFrame or some other Window, define a button like:
class CMainFrame : public CFrameWnd
{
/// bunch of stuff, including OnCreate() or OnCreateClient()
CButton m_button;
};
In the class that houses the button, assuming CMainFrame for now, create the button... ideally in OnCreate() or OnCreateClient()
call the baseclass version then your button create....
int CMainFrame::OnCreate(LPCREATESTRUCT lpcs)
{
int ret = __super::OnCreate(lpcs);
if (ret != -1) {
m_button.Create(_T("Ok Button"), WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, CRect(10, 10, BUTTON_WIDTH, HEIGHT), this, ICL_OK);
}
return ret;
}
If your constructor is in a method, then its destructor will be called at the end of the method. MFC CWnd derived windows classes usually call DestroyWindow() in their destructor and what this means is that the window is destroyed by the end of the call and that is the reason it is not visible.

How to insertItem to 2nd colum in CListCtrl

I am new to MFC & BGCControlBar.
Now I plan to use CBCGPListCtrl which is defined as:
class BCGCBPRODLLEXPORT CBCGPListCtrl : public CListCtrl
&
CBCGPListCtrl m_wndWatch;
Now in the demo code I plan to change:
int CWatchBar::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CBCGPDockingControlBar::OnCreate(lpCreateStruct) == -1)
return -1;
m_Font.CreateStockObject (DEFAULT_GUI_FONT);
CRect rectDummy;
rectDummy.SetRectEmpty ();
// Create output pane:
const DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_VSCROLL | LVS_REPORT | LVS_EDITLABELS ;
m_wndWatch.Create (dwStyle, rectDummy, this, ID_LIST_1);
m_wndWatch.SendMessage (LVM_SETEXTENDEDLISTVIEWSTYLE, 0,
LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);
m_wndWatch.InsertColumn (0, _T("Variable"), LVCFMT_LEFT, 100);
m_wndWatch.InsertColumn (1, _T("Value"), LVCFMT_LEFT, 100);
m_wndWatch.InsertItem (0, _T("m_nCount"));
m_wndWatch.SetItemText (0, 1, _T("100"));
m_wndWatch.SetFont (&m_Font);
return 0;
}
What I get is a list(as in pic), I can only edit the 1st colum and the data can not be retained. How can I edit the second column text and make the data retainable?
You need a grid control rather than a CListCtrl (or derived class). Actually, it's possible to add support for edition in other columns but it's a looooooot of work and not the kind of thing I'd recommend to a newcomer.
According to this page of their web site, they have a grid control.
There are a few things you need to do in order to make a MFC CListCtrl editable. This is a very broad overview without going into too many details:
As mentioned above it is quite a bit of work and you need to derive a class from CListCtrl, since CListCtrl by itself does not allow you to explicitly edit all of the columns.
You need a routine that will calculate the row/column number of the particular cell you clicked on, given a cursor position CPoint.
In the derived CListCtrl class you also need a method to edit the selected cell, creating and making visible a CEdit control of the appropriate size.
Create a derived CEdit control, such that it sends the LVN_ENDLABELEDIT message and self-destructs upon completion.
An example Visual Studio 2010 project implementing an editable list control is downloadable from this site:
http://www.technical-recipes.com/2014/making-a-mfc-list-control-editable/
Upon running/debugging the example, you get an example dialog project implementing an editable list control as shown: