Accessing document files from dialog class in mfc, sdi - c++

I am new to mfc, so I don't know if I will explain my problem correctly but I'll try.
So I built a puzzle game in mfc, and I want to implement high score system. When the game is over, the dialog pops up, where you put your name, and name is written in the external txt file. So, I have Dialog class, where I implement stuff about putting in your name, and sending it to a txt file, but the problem is that I can't access the info about the score, which is stored in the ProjectDoc class, so I can't link the name of the player and the score.
So the question is how to access files from ProjectDoc class from dialog class.

The solution offered by IInspectable and thomiel works great if you have one (or a few) parameter.
Another extreme would be to pass a pointer to the Document and let the Dialog pull whatever it needs out of it, but that would violate "need to know" policy.
I would suggest to define an interface (abstract class) IHighScoreProvider with required accessors, for example:
class IHighScoreProvider
{
public:
virtual int GetGameScore() = 0;
virtual std::string GetPlayerName() = 0;
};
Then derive your Document from it and implement those methods. And pass that interface pointer to your dialog.

Submit the score as parameter in the constructor of you dialog class:
CHighscoreDlg::CHighscoreDlg(int score)
{
m_score = score; // store in private class member variable
}
...
...
void CPuzzleView::EndGame()
{
CHighscoreDlg hs(GetDocument()->m_gamescore);
hs.DoModal();
}

Related

C++ Passing data to Form from outside

I'm starting my journey with C++ and i need help with passing data to my forms objects.
I wrote simple bot (dll project) which is injected into game and doing some stuff. Now i want to add GUI for it. So i added Forms to my project. All working well but i dont know how to pass data into my active form window from outside of form class.
For example. I have a function that receives data from game and i want to pass them to my datagridview. I tried something like that:
In Forms class i added a method to fill datagridview:
void sendToGridView(char* data,PacketDirection direction)
{
this->dataGridView1->Rows->Add(PrintPacket(data, direction));
}
In my function (outside of Form class) i try to call this method:
MainForm mf;
mf.sendToGridView(lpMsg, Recv);
but it doesent workBig THX for any tips, hints and sugestions.
I temporary resolved this issue by creating class
ref class FormCaller
{
public:
static MainForm^ form;
};
And on the Form side public getters and setters
example of calling from functions:
FormCaller::form->sendToGridView(packet, Send);

Qt C++; How to address a certain textfield, depending on user input

I'm having issues with formulating the question but this is what I want to do with my application.
A user can select one or multiple image-files (.ppm), and they are displayed in some sort of legend, with their filename underneath. The information of these images is stored in a structure. (This structure contains the image path, name, and other info).
Now I want to give the user the chance to change the name of the selected images, and uses this name in the rest of the application. So I would have to change the name in the structure.
I could do this by adding textfields in the legend, where users can type the desired name, but how can I get the input from this textfield if I don't know which one is alterred?
If the user selects 6 images, I need 6 new textfields in the legend, but how can I address the correct one?
struct[2].name = input2.getText();
I also thought about doing it with some sort of wizard, with 6 pages where the names can be changed, but I don't know how I can adress the correct textfield.
Any help would be welcome, thanks!!
If you want to allow users to rename multiple files at one time, you may want to create a wizard. In the wizard you could display each picture they selected (one at a time) and allow them to rename each picture (one at a time). Otherwise it will be confusing to the user and harder for you to manage.
When generating the wizard, I would use the information structure to associate the picture with the textfield.
Qt, signals and slots are your friend here.
When you setup the textfields for the name, assuming you use something like a QLineEdit object, connect to a relevant signal, such as editingFinished(). Make the connection to the slot of the Object that stores the structure. The receiving slot then updates the appropriate information.
So, assuming your struct is in an object derived from QObject, you can do something like this: -
struct DataStruct // the struct storing the underlying data
{
QString name;
QLineEdit* linkedEditWidget; // widget for user to change text
};
class MainObject : public QObject
{
Q_OBJECT // required for signals and slots
public slots:
void UpdateText();
private:
const int NUM_STRUCTS = 10; // initialisation in C++ 11
DataStruct myStructs[NUM_STRUCTS]; // a number of structs
};
When you initialize the array of structs and the LineEdit widgets, store a pointer to the matching LineEdit widget in each myStruct and connect the widgets' editingFinished signals to the MainObject updateText() slot. It would be a good idea to use weak smart pointers here, but I'll use a standard pointer, to keep things simple.
When you receive notification that the text has changed, you'll need to match up the caller with the LineEdit* in the struct. Note that QObject::sender() will return the pointer to the object that sent the message: -
void MainObject::UpdateText()
{
QObject* theSendingWidget = sender();
for(int i=0; i<NUM_STRUCTS; ++i) // assuming NUM_STRUCTS is already defined
{
if(myStructs[i].linkedEditWidget == theSendingWidget)
{
// update the name in the data struct
myStructs[i].name = (static_cast<QLineEdit*>(theSendingWidget))->text();
return; // our work is done.
}
}
}
Finally, you'd probably make life easier for yourself by storing the data in Qt model objects, rather than using a plain struct. I suggest reading up on Model / View programming and the MVC design pattern

Passing application objects into lower level classes

I wasn't really sure how to search for this question.
I'm doing an embedded system design with the following scenario.
I have a main application class that needs to create a bunch of hardware interfaces such as a keypad, display, communication ports, etc... a whole slew of stuff
Now I have all these objets in the main application that I can use which is great
The application class contains a few sub classes that it can go into and stay for a while. One example is a menu class that it enters and runs inside that class until the menu is closed
I need the menu class to also interact with a lot of a hardware objects that were created at the application level
What is the best way to go about this without using global variables? Is there a good solution to this problem?
I could pass each object into the menu class, but I don't want to create a constructor with 20 arguments. My current solution is to put all the objects into a structure and pass that structure into the sub-class constructor. That way they also have access.
The part that bugs me about this approach is that I have to define the structure outside of the application which I don't really like. Something just keeps telling me it's not the best solution.
Open to any suggestions.
Presumably, there is ONE keypad - thus only one "Keypad Interface Object", right? Similarly with Display [ok, there may be two displays, but still].
So my suggestion would be to have a registration and a "container" that holds the registered interfaces something like this:
class KeyPad
{
public:
int getKeyPressed();
};
class Display
{
public:
OutputText(std::string msg);
};
... bunch of other stuff ...
class HardwareRegistry
{
priviate:
Keypad *keypad;
Display *display;
static HardwareRegistry *myself;
public:
Keypad* GetKeypad() { return keypad; }
Display* GetDisplay() { return display; }
void RegisterKeypad(Keypad *akeypad) { keypad = akeypad; }
void RegisterDisplay(Display *adisplay) { display = adisplay; }
static HardwareRegistry* GetHwRegistry()
{
if (!myself) myself = new HardwareRegistry;
ASSERT(myself); // If we don't have a pointer now, panic!
return myself;
}
};
Then you just have a Singleton Pattern to provide your HardwareRegistry, and register the devices as you create them during hardware initialization.
Of course, if you support different kinds of Keypads, Displays, etc, then you would implement those with a "interface baseclass", and the registry returns the KeypadBase type, for example.

MFC :: passing data using structure

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.

How do i update a control outside of a dialog?

For example, in an MFC program, I have my main application and a 'class'. What should I do if I want to update a control (say, a listbox) that is situated on my main application from that 'class'?
heres an example that worked for me
theApp.m_pMainWnd->GetDlgItem(IDC_BUTTON6)->SetWindowTextW(L"Run Auto Test");
Your class can be designed to trigger an event which your main application can listen for. Then, a listener/event handler/delegate can be called to handle the event and update the listbox. Typically, most event formats pass a reference of the sender, in this case your 'class', as well as an object containing event arguments. These arguments can be used to pass the list of items you want to add to your listbox.
If you have the handle to dialog object in your class, then you can use GetDlgItem(ResourceID) to get list control object.
The easiest approach is to expose the listview from your application form/window to the classes that use it. You can do this either by passing the listview object (or parent window) to the class constructor, or storing it in a static variable that is accessible by the class.
For better encapsulation, you can put a method in the application that the class can call, e.g. "AddItemToListBox()". This allows the application object to remain in control of how you access the listbox. Again you can do this as a static method, or pass the main program object's 'this' pointer into the class constructor.
i.e.
class CApplication
{
CListBox m_ListBox;
public:
static void CApplication::AddItemToListBox(CString itemText)
{
// Add the item as you wish here
}
}
class CMyClass
{
afx_msg void CMyClass::OnMouseDown(...)
{
CApplication::AddItemToListBox("This is a test");
}
}