The DDX technology was created for linking resources with class members (for example). In my solution I need to make the connection between myCCtreeCtrl (instant of CCtreeCtrl) does not living in resources with class member CCtreeCtrl.
Now I have CTreeCtrl in resouces and silmple doDataExchange:
#define IDC_TREE_LAYER0 2000
#define IDC_TREE_LAYER1 2001
#define IDC_TREE_LAYER2 2002
// ============================================================================
void ForcesGUI::doDataExchange( int id0, int id1, int id2, CDataExchange* pDX )
// ============================================================================
{
DDX_Control(pDX, id0, m_tree[0].data);
DDX_Control(pDX, id1, m_tree[1].data);
DDX_Control(pDX, id2, m_tree[2].data);
}
but in future it will be necessary to delete CCtreeCtrl from resources and make instance.
You'll ask me why do you need deleting from resources?
The answer is: In project I have 3 CCtreeCtrls each of them live on his own bar. There is no different betwen them. That is why I want to use 1 bar class with 1 tree on it instead of redundancy. After I'll create 3 instance of bar and here appears problem with DDX wich does not work here.
Have you any ideas how can I replace basic DDX? May be it will be WinAPI or something else. In any case thanks for help.
If the control isn't generated automatically from a dialog resource, you'll have to create it with the Create method. You'll want to do this in OnInitDialog or whatever equivalent is in your parent window. By creating the window with Create it will automatically be connected to the object you created it from - no need for DDX_Control.
Related
I use the same ID's in Menus and Dialog.
I create a modeless or modal CMyDialog within my CView class.
Then I handle CMyDialog Buttons Click in my CView derived class.
(No need to write any code in CDialog, it just forward the commands to CMyView).
That works usually.
ON_COMMAND(IDC_HOME, &CMyView::OnHome)
void CMyView::OnHome()
{
..
}
But what I have discovered is:
If the resource ID is e.g
#define IDC_HOME 1060 // Fail
but
#define IDC_HOME 32796 // Works
I have read TN021: Command and Message Routing but I don't find or see a limitation?
Where is this documented?
I have a solution and it has two projects in it. When I got the code they told one project handles the visual part and the other has the logic part. Now I added one button to the window. To do that i edited the project which handles the visual part. I am very new to this but creating and adding buttons is fairly straightforward in visual studio 2010. Now the problem is I want to detect if the button is pressed from the other project. I am sure that the projects are sharing some data, but I am not being able to capture it. For now I am changing a value in a file and reading the same data from the other project to check if the button is pressed. But I think there is a better way to do it. Can anyone help?
I don't think the two projects are sharing automatically. You will have to define the interface that the two projects communicates. For instance, in your solution above the "a value in a file" is the "interface" you have defined. What sounds like you are trying to achieve is to separate the controller (logic part) and view (visual part) separately, which seems to indicate that your project is using MVC model.
I would suggest defining an abstract class (interface) that defines the interaction you want between the two projects. All they have to share is a single header file.
For example:
// Solution A (Controller - logic part)
// MyUIHandler.h
class IMyUIHandler //You can also use microsoft's interface keyword for something similar.
{
public:
HRESULT onButtonPressed() = 0; // Note that you can also add parameters to onButtonPressed.
};
HRESULT getMyUIHandler(IMyUIHandler **ppHandler);
Then implement this interface:
// Solustion A (Controller - logic part)
// MyUIHandler.cpp
#include "MyUIHandler.h"
class CMyUIHandler : public IMyUIHandler
{
private:
// Add your private parameter here for anything you need
public:
HRESULT onButtonPressed();
}
HRESULT getMyUIHandler(IMyUIHandler **ppHandler)
{
// There are many ways to handle it here:
// 1. Define a singleton object CMyUIHandler in your project A. Just return a pointer
// to that object here. This way the client never releases the memory for this
// object.
// 2. Create an instance of this object and have the client release it. The client
// would be responsible for releasing the memory when it's done with the object.
// 3. Create an instance of this object and have a class/method in Solution A release
// the memory.
// 4. Reference count the object, for example, make IUnknown the parent class of
// IMyUIHandler, and implement the IUnknown interace (which is boiler plate code).
// Since I don't know your project it's hard for me to pick the most suitable one.
...
*ppHandler = myNewHandler;
...
return S_OK;
}
CMyUIHandler can simply be your existing class that already handles some of the logic.
In solution B you should will call getMyUIHandler in some initialize function, for example the controller of the UI class, save that as your member. Then "Button clicked" event handler that VS creates for you.
// Solution B (View - visual part)
// MyUIView.h
class MyUIView
{
protected:
IMyUIHandler *m_pHandler;
}
// MyUIView.cpp
CMyUIView::CMyUIView(...)
{
...
hr = getMyUIHandler(&m_pHandler);
// error handler, etc...
...
}
// In the function that is created for you when button is clicked (I'm not sure if I get the signature right below.
void OnClick(EventArgs^ e)
{
...
hr = m_pHandler->onButtonPressed();
...
}
Then you can pass any parameter you define for the function onButtonPressed as soon as the button is clicked.
So I have this MFC dialog program I am working with. The dialogs are written but now I am having difficulty passing data around from dialog to dialog. I have the following structure _dlgDataHandler set up in a class derived from CWinApp and have have created a "new" statement for a pointer to this type.
//.......SRK.h file
class CSRK_App : public CWinApp
{
public:
CFSB_App();
// added the following data structure for data passing withing the program
typedef struct _dlgDataHandler {
char RepetitionRadio[24];
// another member
// yet another member and so on as necessary
} *dlgDataHandlerPtr;
// extern dlgDataHandlerPtr dlgDataHandler;
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CSRK_App)
public:
virtual BOOL InitInstance();
//}}AFX_VIRTUAL
// Implementation
//{{AFX_MSG(CSRK_App)
// NOTE - the ClassWizard will add and remove member functions here.
// DO NOT EDIT what you see in these blocks of generated code !
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
//....... SRK.cpp A pointer to a new dataHandler created in this block about 2/3 the way down
// CSRK_App initialization
BOOL CSRK_App::InitInstance()
{
AfxEnableControlContainer();
// Standard initialization
// If you are not using these features and wish to reduce the size
// of your final executable, you should remove from the following
// the specific initialization routines you do not need.
//SetRegistryKey(_T("Local AppWizard-Generated Aplications"));
#ifdef _AFXDLL
Enable3dControls(); // Call this when using MFC in a shared DLL
#else
Enable3dControlsStatic(); // Call this when linking to MFC statically
#endif
//CSRK_Dlg dlg;
CDialogMain dlg("SRK - Beta"); // added 12/27 **
m_pMainWnd = &dlg;
//const char* m_pszHelpFilePath = NULL;
//free((void*)m_pszHelpFilePath);
//m_pszHelpFilePath=_tcsdup(_T("c:\SRKHelp.rtf"));
// the following line added to allocate memory for the structure
dlgDataHandlerPtr dlgDataHandler = new _dlgDataHandler;
dlg.SetWizardMode(); // added 12/27 **
int nResponse = dlg.DoModal();
if (nResponse == IDOK)
{
// TODO: Place code here to handle when the dialog is
// dismissed with OK
}
else if (nResponse == IDCANCEL)
{
// TODO: Place code here to handle when the dialog is
// dismissed with Cancel
}
// Since the dialog has been closed, return FALSE so that we exit the
// application, rather than start the application's message pump.
return FALSE;
}
In the dialog .cpp files, there are five, I need to be able to get data from the AFX variables "m_" and load them into this dataHandler Structure (or another one like it) so that they can be used in other dialogs and parts of the program, specifically my actual code when all the dialog data collection is done. Someone said to use AfxGetApp() so that I could have a handle on the current instance but I do not understand what they are talking about. And yes I have read about it in many forums, I just don't get it. I further realize this is probably not the best way to do it. I am trying to learn MFC/OOP with what time I have available, but for now, I am just trying to get a handle on the basic process as I can tune it later once I understand how to collect and pass simple data around.
I further don't understand how calling AfxGetApp() will help me get a handle on the members of CSRK_App. It inherited CWinApps public members but AfxGetapp() can't see what CSRK_App has... can it?
First, to explain the AfxGetApp advice you have received. There is some extra hand-waving using 'new' and a pointer, but this is basically using a global variable for the structure that holds your data. This is not the best way to do what you are trying to do. There are many pitfalls.
AfxGetApp() is an MFC call that returns a pointer to your main App class derived from CWinApp.
If you want to use that returned pointer, you need to cast it as a CSRK_App* pointer with:
CSRK_App* pApp = static_cast <CSRK_App*> ( AfxGetApp());
Then you can use pApp->dlgDataHandlerPtr->... to access the variables you need.
Now, for the pitfalls. Someone else may chime in with a reason why the 'new' and the pointer are helpful, but I do not see any advantage to this approach as compared to just having a local variable dlgDataHandler inside your CSRK_App class. That would simplify the code.
The next issue is that all your data is public in a struct. Any dialog class that can call AfxGetApp can read or write any data in that struct. You have no way to control access.
Also, all of your dialog classes must now include SRK_App.h so they know the structure, and have access to all other variables in that App class.
A cleaner, object-oriented approach would be to declare the struct (class) for the data in a separate .h file that could be included in the dialog classes. Then, you would pass a pointer/reference to this data into the constructor of the dialog classes. The dialog class would have no need to know anything about the App class.
For an even higher level of segregation, the dialog classes can be written so they only get a copy of the dlgDataHandler class passed in before calling .DoModal(), and then after the DoModal call returns with IDOK, the App class can have control over which data from the dialog gets updated into the dlgDataHandler class. The advantage of this approach is that it insures that no matter how the dialog class is programed, the user can always "Cancel" the dialog without modifying any data.
I have a VS 2005 C++ MFC project that contains several CDialog based windows. The program communicates with a custom piece of hardware and displays different readings on the different windows. The data is read from the hardware using a public static member function named ReadHardWare() of a class named CTools. ReadHardWare() places the data read from the hardware in an array with global scope and each window has the ability to read from this array. On each window I have an indicator that lights up showing that a read from hardware operation is in progress. This indicator is a National Instruments
Measurement Studio CNiButton class control. CTools has a public static member variable of the CNiButton type named m_read_in_progress_status that I use to identify if a read operation is in progress (m_read_in_progress_status.Value == 1) or not (m_read_in_progress_status.Value == 0). My goal is to have all the read indicators on all the opened windows show a read is in or not in progress at the same time. I regularly use DoDataExchange to connect variables with controls but always on a one-to-one basis. In this case I want several controls to connect with a single variable and to automatically update with that variable.
I seem to have two problems:
1) It seems that I am only able to have one control connect with the variable at the same time. Apparently the only control that the variable shares data with is the first one instantiated (i.e. first window opened)
2) If I send a read command from the second window opened, not only does the read indicator on the second window still not show the read status but neither does the read indicator on the first anymore. The only time any of the read indicators work is when I perform a read command from the first window opened. The first window does not seem to want to update its controls when the second window is sending the read command.
So my questions are:
1) How can I allow two controls on two different windows to share the same member variable and update immediately when that member variable's value is changed?
2) How can I make the ReadHardWare() member function (or some other event) force the first window to update its controls even though it is not the window actively calling that function?
In the current case the first window is the parent of the second. However this will not always be the case.
Below is an excerpt of my code.
//Globalvariables.cpp
NI::CNiButton CTools::m_read_in_progress_status;
//Tools.h
class CTools
{
public:
static ReadHardWare();
public:
static NI::CNiButton m_read_in_progress_status;
}
//Tools.cpp
CTools::ReadHardWare()
{
//Declare and initialize variables and other setup code is here
m_read_in_progress_status.Value == 1 //Set read in progress flag high
//Read operations here
m_read_in_progress_status.Value == 0 //Reset read in progress flag low
}
//FirstWindow.cpp
#include "Tools.h"
#include "SecondWindow.h"
void CFirstWindow::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
DDX_Control(pDX, IDC_First_Window_Read_in_Progress_Indicator, CTools::m_read_in_progress_status);
}
//SecondWindow.cpp
#include "Tools.h"
#include "FirstWindow.h"
void CSecondWindow::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
DDX_Control(pDX, IDC_Second_Window_Read_in_Progress_Indicator, CTools::m_read_in_progress_status);
}
DDX_Control establishes an association between control identifier in dialog and particular instance of CWnd based object. I am not sure it's a good idea is to share the same object representing a button for two windows. I suggest to sligthly modify the design. You should create a timer for pooling read operation state. If state is changed you will update the button.
class CTools
{
public:
static void ReadHardWare();
public:
static int m_read_in_progress_status;
}
class CFirstWindow: CDialog
{
public:
void OnTimer(UINT nIDEvent)
{
if(m_read_in_progress_status != CTools::m_read_in_progress_status)
{
m_read_in_progress_status = CTools::m_read_in_progress_status;
m_button.SetCheck(m_read_in_progress_status);
}
}
private:
int m_read_in_progress_status; // Cached status
NI::CNiButton m_button;
};
Imagine I have a CDialog which creates controls dynamically when the user clicks a button. It could be like this:
// We don't know which is the first id for the new buttons until runtime (!)
MyDialog::MyDialog(/*whatever parameters needed*/, first_id)
: next_id_(first_id)
{ /*...*/ }
BOOL MyDialog::OnSomeButtonClicked()
{
CButton* new_button = new CButton;
new_button->Create("Caption", WS_CHILD | WS_VISIBLE, this->new_button_rect_,
this, this->next_id_++);
}
Then my question would be: How could I handle messages from this button? Is it possible to use the MFC message map facility?
The solution should work in both vs6 and vs2005.
Thank you!
These are the solutions I've found so far in order of relevance:
Use ON_COMMAND_RANGE if you can define the range of the control IDs you want to handle.
Overload CWnd::PreTranslateMessage() and do whatever stuff you want with the messages received. NOTE: When dealing with buttons, take into account that the BN_CLICKED event is NOT sent to PreTranslateMessage but directly sent to the window procedure.
Overload CWnd::WindowProc() and do whatever stuff you want with the messages received. NOTE that when dealing with buttons this is the ONLY WAY I've found to handle the BN_CLICKED event.
Interesting links:
Please help with PreTranslateMessage and user defined messages handling.
TN006: Message Maps
I hope this helps... thank you all for your contributions.
Eventhough you dont know the exact values of the id, if you know the possible range of IDs then the following macro can be used.
BEGIN_MESSAGE_MAP(MyDialog, CDialog)
...
...
ON_COMMAND_RANGE(1000, 5000, OnButtonDynamic)
END_MESSAGE_MAP()
void MyDialog::OnButtonDynamic(UINT nID)
{
}
This will work for ids in the range 1000 - 5000.
I'm a few years late to this party, but the solution to this is to assign the same control id to each button (no need to 'reserve' id's in resource.h, and no artificial restrictions on the amount of controls that can be created), to save the window handle and to use GetCurrentMessage() in the handler for that button:
// resource.h
#define IDC_DYNAMIC_BUTTON 123
// In message map
ON_BN_CLICKED(IDC_DYNAMIC_BUTTON, OnDynamicButtonClicked)
// Store the window handles when creating them in a member:
std::map<HWND, SomeStruct> m_Buttons;
... fill this map when creating the buttons, presumably in OnInitDialog()
// Actual handler
void MyDialog::OnDynamicButtonClicked()
{
const MSG* message = GetCurrentMessage();
if (m_Buttons.find((HWND)message->lParam) != m_Buttons.end()) {
// Do something with m_Buttons[(HWND)message->lParam]
}
}
I believe this article explains it pretty well and has source code. I have not tried this so I can't guarantee it works, but in the time I have thought it might help.
Article
You can find details (+ a lot more) on modeless dialogs there.
insert the entry of ID of the handler in Resouce.h
Then insert the entry in the message map of the handler like ON_BN_CLICKED(IDC_BTNCREATE, OnBnClickedrunCreated)
or you can directly use the integer ID like ON_BN_CLICKED(1200, OnBnClickedrunCreated). If you use 2nd version then there is
no need to insert entry in resource.h. Give defination and declaration of the handler in .h and .cpp file. you will get your answer.
Use this way: ON_CONTROL_RANGE(wNotifyCode, id1, id2, memberFxn ).
for example:
ON_CONTROL_RANGE(EN_UPDATE, IDC_EDIT_START, IDC_EDIT_END, OnEnUpdateEditParams)