I'm building my first c++ project using classes (trying to get more experience) and now I'm stuck. I need to determine which button was pressed from my calculator application. The way I have my project set up is:
Windows.cpp
// Windows.cpp
#include <Windows.h>
#include <wchar.h>
#include "Resource.h"
#include "Application.h"
int WINAPI wWinMain(...)
{
// after register class and create/show/update window ( winMain() )
Application App(hwnd);
App.Go();
// Main message loop, etc.
MSG msg;
ZeroMemory(&msg,sizeof(msg));
while(msg.message != WM_QUIT)
{
if(PeekMessage(&msg,NULL,0,0,PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return 0;
}
Application.h
#pragma once
#include "Calculator.h"
class Application
{
public:
Application(HWND hwnd);
~Application();
void Go();
private:
void Run();
private:
Calculator calc;
};
Application.cpp:
// Application.cpp
#include "Application.h"
Application::Application(HWND hwnd)
: calc(hwnd)
{}
Application::~Application()
{}
void Application::Go()
{
calc.Initiate(); // This function shows all my button controls for my calculator
Run();
}
void Application::Run()
{
// This is where i want to determine which button was pressed(if any)
if(buttonONEwasPRESSED) { /* do stuff */ } // etc
}
I thought about adding a function to Calculator class to determine if a button was pressed, but I'm not sure how to access wm_command, or if theres another way. Then I could just call calc.IsButtonPressed().
You are stuck because you want to know which button was pressed. That reminds me some console programs dealing with user input.
That's not how to go with GUI. What you should do is code what to do when a button is pressed. That's event drived programming.
With standard Win32 application, the "event" for pushbutton press is WM_COMMAND.
For mapping a HWND to a C++ class with easy mapping between a WM_MESSAGE_X and an OnMessageX member function, see for example https://stackoverflow.com/a/20356046/1374704
Related
I created a basic project on the TouchGFX Designer and wrote a function in my own cpp file using touchgfx library. I want that when the button is clicked ,the function is called to ScreenView.cpp or ScreenViewBase.cpp from my own cpp file and change the color of the box.
This is my cpp file.
#include <touchgfx/Color.hpp>
#include <touchgfx/widgets/Box.hpp>
#include <gui/screen1_screen/Screen1View.hpp>
#include <gui/screen1_screen/Screen1Presenter.hpp>
#include <touchgfx/widgets/Box.hpp>
ChangeColor::ChangeColor()
{
Screen1View::box1;
box1.setColor(touchgfx::Color::getColorFrom24BitRGB(51, 168, 35));
box1.invalidate();
}
This is the Screen1View.cpp where I want to call my function.
#include<gui/ChangeColor.hpp>
#include <touchgfx/Color.hpp>
Screen1View::Screen1View():
buttonCallback(this, &Screen1View::buttonCallbackHandler)
{
}
void Screen1View::setupScreen()
{
Screen1ViewBase::setupScreen();
button1.setAction(buttonCallback);
}
void Screen1View::tearDownScreen()
{
Screen1ViewBase::tearDownScreen();
}
void Screen1View::buttonCallbackHandler(const touchgfx::AbstractButton& src)
{
if (&src == &button1)
{
//Interaction1
//When button1 clicked execute C++ code
//Execute C++ code
//ChangeColor();
ChangeColor();
}
}
and this is the Screen1BaseView.hpp where the box is declared
#define SCREEN1VIEWBASE_HPP
#include <gui/common/FrontendApplication.hpp>
#include <mvp/View.hpp>
#include <gui/screen1_screen/Screen1Presenter.hpp>
#include <touchgfx/widgets/Box.hpp>
#include <touchgfx/widgets/Button.hpp>
class Screen1ViewBase : public touchgfx::View<Screen1Presenter>
{
public:
Screen1ViewBase();
virtual ~Screen1ViewBase() {}
virtual void setupScreen();
protected:
FrontendApplication& application() {
return *static_cast<FrontendApplication*>(touchgfx::Application::getInstance());
}
/*
* Member Declarations
*/
touchgfx::Box __background;
touchgfx::Box box1;
touchgfx::Button button1;
private:
};
I can't access the box. Is there way to do it?
TouchGFX uses MPV architecture, i.e. Model-Presenter-View. The point is Model and View can not access each other.
In your case, your cpp file play role as a model, so it's not allowed to access element in View. That's the reason why you can't access. You need a Presenter to handle the connection.
I want to know when the user has clicked in a CListBox, but outside of any item. I was hoping to get some notification in the containing dialog so I can process the point to determine if it is inside an item via mylistbox.ItemFromPoint(flags,outside). But clicks within the listbox don't seem to result in such events. What event should I be looking for in the parent dialog, and what needs to be set up to enable it? I really don't care if it is a click or just mousedown.
My purpose for this is to deselect all items if the user clicks outside of any item, with mylistbox.SetCurSel(-1).
Addendum: This is the full code for the class implemented as suggested by #mercurydime.
(Header)
#ifndef INCLUDE_CMYLISTBOX_H
#define INCLUDE_CMYLISTBOX_H
class CMyListBox : public CListBox
{
public:
CMyListBox();
void allow_deselect( bool allow = true );
protected:
bool m_allow_deselect;
afx_msg void OnLButtonDown( UINT flags, CPoint point );
DECLARE_MESSAGE_MAP()
};
#endif // INCLUDE_CMYLISTBOX_H
(Body)
#include "stdafx.h"
#include "CMyListBox.h"
CMyListBox::CMyListBox()
: CListBox(), m_allow_deselect( false )
{
}
void CMyListBox::allow_deselect( bool allow )
{
m_allow_deselect = allow;
}
BEGIN_MESSAGE_MAP( CMyListBox, CListBox )
ON_WM_LBUTTONDOWN()
END_MESSAGE_MAP()
void CMyListBox::OnLButtonDown( UINT flags, CPoint point )
{
if( m_allow_deselect )
{
BOOL outside( TRUE );
ItemFromPoint( point, outside );
if( outside )
SetCurSel( -1 );
}
CListBox::OnLButtonDown( flags, point );
}
Use the Class Wizard to create a class derived from CListBox:
Ctrl+Shift+X
Click the down arrow on the Add Class button
Select the MFC Class menu item
Make sure the base class is set to CListBox
Add a message handler for WM_LBUTTONDOWN
Ctrl+Shift+X
Click the Messages tab
Double-click WM_LBUTTONDOWN
Add your ItemFromPoint code inside the handler
void CMyListBox::OnLButtonDown(UINT nFlags, CPoint point)
{
BOOL bOutside = TRUE;
UINT uItem = ItemFromPoint(point, bOutside);
if (bOutside)
{
// do whatever
}
CListBox::OnLButtonDown(nFlags, point);
}
I am updating some old software that does not work on Win7 or later. so, I am rebuilding some MFC libraries that are using latest win32 updates.
Now I have two issues:
MessageBox appears behind the CFrameWnd so it can't be accessed sending the application to halt.
Open dialog box (whether is based on CFileDialog or IFileDilog) does not get refreshed when changing the file type.
However, both problems are solved if the CFrameWnd is hidden. or, in case of MessageBox, you will not need to hide the window if you write: PostMessage(0x118); which in fact I don't know why.
There must be something I am missing Here.
I also Have another problem when using the OpenFileDialog class that inherits from the IFileDialog. is when closing this dialog without picking up a file, the application Crashes.
//--targetver.h
#pragma once
#include <sdkddkver.h>
//--stdafx.h:
#ifndef CS_EXTRALEAN
#define CS_EXTRALEAN
#endif
#pragma once
#include "targetver.h"
#include<afxwin.h>
#include<afxext.h>
#include<afxcmn.h>
//--stdafx.cpp
#include "stdafx.h"
//--CMainWnd.h
#pragma once
class CMainWnd : public CFrameWnd
{
public:
CMainWnd();
~CMainWnd();
afx_msg void OnPaint();
afx_msg void OnLButtonDown(UINT, CPoint);
DECLARE_MESSAGE_MAP()
};
//--CMainWnd.cpp
#include "stdafx.h"
#include"CMainWnd.h"
BEGIN_MESSAGE_MAP(CMainWnd, CFrameWnd)
ON_WM_PAINT()
ON_WM_LBUTTONDOWN()
END_MESSAGE_MAP()
CMainWnd::CMainWnd()
: CFrameWnd()
{
CString class_name = AfxRegisterWndClass(
CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS,
AfxGetApp()->LoadStandardCursor(IDC_ARROW),
(HBRUSH)::GetStockObject(BLACK_BRUSH),
AfxGetApp()->LoadStandardIcon(IDI_ASTERISK));
HRESULT hResult = this->Create(
class_name,
L"This is CMainWnd",
WS_OVERLAPPEDWINDOW,
this->rectDefault,
NULL,
NULL,
0,
NULL);
}
CMainWnd::~CMainWnd() { }
void CMainWnd::OnPaint()
{ }
void CMainWnd::OnLButtonDown(UINT, CPoint)
{
MessageBox(L"HELLO MFC", L"MFC", MB_OK);
}
//--CAppWnd.h
#pragma once
class CAppWnd : public CWinApp
{
public:
CAppWnd();
~CAppWnd();
BOOL InitInstance();
DECLARE_MESSAGE_MAP()
};
//--CAppWnd.cpp
#include "stdafx.h"
#include "CAppWnd.h"
#include "CMainWnd.h"
BEGIN_MESSAGE_MAP(CAppWnd, CWinApp)
END_MESSAGE_MAP()
CAppWnd::CAppWnd()
:CWinApp()
{ }
CAppWnd::~CAppWnd()
{ }
BOOL CAppWnd::InitInstance()
{
this->m_pMainWnd = new CMainWnd;
this->m_pMainWnd->ShowWindow(m_nCmdShow);
return CWinApp::InitInstance();
}
CAppWnd The_App;
There was a simple problem. You override OnPaint but didn't call the default procedure. OnPaint handles to WM_PAINT message, it doesn't forgive this error.
void CMainWnd::OnPaint()
{
CFrameWnd::OnPaint(); //<= this was missing
//custom paint...
//CClientDC dc(this);
//dc.TextOut(0, 0, L"test");
//dc is automatically released...
}
Or you can use CPaintDC which is a wrapper for BeginPaint/EndPaint API
void CMainWnd::OnPaint()
{
CPaintDC dc(this);
//custom paint...
//dc.TextOut(0, 0, L"test");
//dc is automatically released...
}
If you don't do any painting in this frame window then remove the whole CMainWnd::OnPaint() function and the correspoonding ON_WM_PAINT message.
Above change should fix your error. I would rewrite the rest of the code so it calls the default override first. Example:
#include "stdafx.h"
#include "resource.h"
class CMainWnd : public CFrameWnd
{
public:
CMainWnd();
~CMainWnd();
afx_msg void OnPaint();
afx_msg void OnLButtonDown(UINT, CPoint);
DECLARE_MESSAGE_MAP()
};
BEGIN_MESSAGE_MAP(CMainWnd, CFrameWnd)
ON_WM_PAINT()
ON_WM_LBUTTONDOWN()
END_MESSAGE_MAP()
CMainWnd::CMainWnd() : CFrameWnd() {}
CMainWnd::~CMainWnd() {}
void CMainWnd::OnPaint()
{
CFrameWnd::OnPaint();
}
void CMainWnd::OnLButtonDown(UINT f, CPoint pt)
{
CFrameWnd::OnLButtonDown(f, pt);
CFileDialog dlg(TRUE, 0, 0, 0,
L"All files|*.*|"
L"Text files|*.txt;*.txt||" , this);
if (dlg.DoModal() == IDOK)
MessageBox(dlg.GetPathName(), L"MFC", MB_OK);
}
class CAppWnd : public CWinApp
{
public:
BOOL InitInstance();
};
BOOL CAppWnd::InitInstance()
{
CWinApp::InitInstance();
CMainWnd *frame = new CMainWnd;
CString class_name = AfxRegisterWndClass(
CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS,
AfxGetApp()->LoadStandardCursor(IDC_ARROW),
(HBRUSH)::GetStockObject(BLACK_BRUSH),
AfxGetApp()->LoadStandardIcon(IDI_ASTERISK));
frame->Create(class_name, L"This is CMainWnd",
WS_OVERLAPPEDWINDOW, CFrameWnd::rectDefault, NULL, NULL, 0, NULL);
frame->ShowWindow(m_nCmdShow);
m_pMainWnd = frame;
return TRUE;
}
CAppWnd The_App;
Note that you can call up static members directly, for example CFrameWnd::rectDefault, it doesn't cause an error either way but it makes the code more clear.
I tried to make a simple MFC GUI application with C++, but it seems to have problem at generating the main window(dialog?). When I'm trying to compile the code, following message shows :
Unhandled exception at 0x00E7A9DC in GUI_Employee_0501.exe:
0xC0000005: Access violation reading location 0xFEFEFF66.
and the break point stops inside winmain.cpp, at pThread->m_pMainWnd->DestroyWindow();. The value of pThread->m_pMainWnd is NULL, which I suspect as the cause of the problem.
Can you specify what is the problem here? I have a sample code and that is very similar to mine but that works, so I truly have no idea what is happening!
#include <afxwin.h>
#include "resource.h"
#include <iostream>
using namespace std;
#pragma comment(linker, "/entry:WinMainCRTStartup /subsystem:console")
CEdit *pFNAME;
CEdit *pLNAME;
CEdit *pSALARY;
CEdit *pDDAY;
CEdit *pMMONTH;
CEdit *pYYEAR;
CComboBox *pGENDER;
CButton *pADD;
CButton *pDELETE;
CButton *pSAVE;
CButton *pLOAD;
class ENTRY_FORM : public CDialog
{
public:
ENTRY_FORM(CWnd* pParent = NULL) : CDialog(ENTRY_FORM::IDD, pParent) { }
enum { IDD = dialog_main };
protected:
virtual void DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); }
virtual BOOL OnInitDialog()
{
CDialog::OnInitDialog();
SetUpInterfacePointers();
return true;
}
void SetUpInterfacePointers(){ ... does its own thing ... }
public:
afx_msg void add() { PRESS_ADD(); }
void PRESS_ADD() { ... does its own thing ... }
DECLARE_MESSAGE_MAP()
};
class Program : public CWinApp
{
public:
Program(){ }
public:
virtual BOOL InitInstance()
{
CWinApp::InitInstance();
cout << "CWinAPP:initInstance" << endl;
ENTRY_FORM dlg;
m_pMainWnd = &dlg;
cout << "mpMainWnd" << endl;
INT_PTR nResponse = dlg.DoModal();
return FALSE;
}
};
//
BEGIN_MESSAGE_MAP(ENTRY_FORM, CDialog)
ON_COMMAND(button_add, add)
END_MESSAGE_MAP()
//
Program theApp;
Change in InitInstance():
return FALSE;
to
return TRUE;
This is because CWinApp::InitInstance should return FALSE only in case of failure, and TRUE if all initialization went OK. In case of failure, AfxWinMain will try to destroy window pointed by m_pMainWnd, which is not possible (it causes Undefined Behaviour) because you assign to m_pMainWnd a local object (which is destroyed once InitInstance ends).
[edit]
S.B Bae - to investigate it further and find a root cause, you will need to debug place where m_pMainWnd should be set to NULL once your dialog ends. This should be in CWnd::OnNcDestroy() in wincore.cpp. There is a line pThread->m_pMainWnd = NULL; which apparently is not being executed in your application.
Late to the party, but I saw the exact problem when creating an MFC Dialog application. I found I had accidentally changed the application dialog Style (in Properties) from 'Popup' to 'Child'. Toggling this can consistently toggle this error. 'Overlapped' seems to work just as well as 'Popup'.
https://learn.microsoft.com/en-us/cpp/mfc/reference/styles-used-by-mfc?view=vs-2019#window-styles
I am try to create very simple c++ MFC project. Since it is very simple one I need to create it form scratch.
my code so far is shown below. But now I need to add picture control and thus my Intent use CImage class. But to use CImage class I need to add altimage.h header to my project. But When I do so it gives a error that cannot open source file altimage.h. So
How can I overcome this problem.
How to add the file I needed when I creating the MFC projects form the scratch.
please help me solvethis.
thanks
#include <afxwin.h> //MFC core and standard components
//#include <altimage>
#include "resource.h" //main symbols
//-----------------------------------------------------------------------------------------
//Globals
//CEdit * TEST;
CEdit * RECOG_CHARS;
CButton * BTN_CONVERT;
CButton * BTN_QUIT;
CStatic * IMG_IMAGE;
class HWCR_FORM : public CDialog
{
public:
HWCR_FORM(CWnd* pParent = NULL) : CDialog(HWCR_FORM::IDD, pParent)
{ }
// Dialog Data, name of dialog form
enum{ IDD = ID_MAIN_INTERFACE };
protected:
virtual void DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); }
//Called right after constructor. Initialize things here.
virtual BOOL OnInitDialog()
{
CDialog::OnInitDialog();
RECOG_CHARS = (CEdit *)GetDlgItem(CE_ID_TEXT);
BTN_CONVERT = (CButton *)GetDlgItem(CB_ID_START);
BTN_QUIT = (CButton *)GetDlgItem(CB_ID_QUIT);
IMG_IMAGE = (CStatic *)GetDlgItem(CS_ID_IMAGE);
HBITMAP image = (HBITMAP)LoadImage(NULL,L"C:\\Users\\Kasun\\Desktop\\image.bmp",IMAGE_BITMAP,150,120,LR_LOADFROMFILE);
IMG_IMAGE->SetBitmap(image);
RECOG_CHARS->SetWindowTextW(L"Hi there");
return true;
}
public:
DECLARE_MESSAGE_MAP()
};
//-----------------------------------------------------------------------------------------
class HWCR : public CWinApp
{
public:
HWCR() { }
public:
virtual BOOL InitInstance()
{
CWinApp::InitInstance();
SetRegistryKey(_T("Hills Of Darkness"));
HWCR_FORM dlg;
m_pMainWnd = &dlg;
INT_PTR nResponse = dlg.DoModal();
return FALSE;
} //close function
};
//-----------------------------------------------------------------------------------------
//Need a Message Map Macro for both CDialog and CWinApp
BEGIN_MESSAGE_MAP(HWCR_FORM, CDialog)
END_MESSAGE_MAP()
//-----------------------------------------------------------------------------------------
HWCR theApp;
First at all, in order to use CImage, you need to include header file
#include <atlimage.h>
instead of
#include <altimage>
Secondly, be sure that this file's directory is included into MSVC paths...
Normally it should be included as this header file is part of MFC / Win32 SDK....check the directories in VS properties.
Z.