How to collect data and pass it around - c++

I should find another interest because this one is taking the life out of me quickly. Seems like a lot of people are confused about the intricacies of MFC code, including me. I have an MFC Dialog Box application that creates several dialogs that you navigate to using the typical back or next function. Along the way you collect data via radio group buttons, list boxes and various other controls. For the most part I understand how to get a handle on the data by using the m_ variables provided by the AFX maps throughout the code for each distinct dialog. At the end - and sometimes during - the data collection/selection process gathered by dialogs, I need to do things with what has been collected. I may need to take the data from one dialog and modify the next based on the previous. It seems like when you move through the dialogs the data from the last is lost unless you save it somehow. I know that there are dozens of ways to do this and I have toyed with several of them, from object passing, to creating new classes, new structures, global variables, pointers, whatever.... My concern is, I need a data structure of some sort to stay up and active in memory long enough for my user code to do something with it. That is the problem I think, I don't know in MFC how to deal with this. I have currently decided to go with a struct called dlg_DataHandler (to house collected data from each dialog) with a few test members in a .h file. It has been typedef'd as a pointer. I am creating a variable of this type and setting it = new dlg_DataHandler, but the data isn't getting passed around like I want from dialog to dialog. One thing that I wonder about is, I don't know exactly where to place the "new" statement for creating the variable. Its as if data is not flowing to and from the structure as it should. Anyway here is some of the code:
// file1.h
typedef struct dlg_DataHandler {
int var;
char* String;
int RepetitionRadio; // radio button data
constructor here
} *dlgDataHandler;
extern dlgDataHandler DlgData;
//*****************
// file2.cpp
dlg_DataHandler DlgData = new dlg_DataHandler; // not located anywhere in peticular just in the code since I DON'T KNOW where to put it. DlgData->member gets loaded in the dialog .cpp files to try collect data, but it doesnt seem to be passing data across the different windows.

Put the variable in your main application class (the one derived from CWinApp) and call new in InitInstance(). You can then use AfxGetApp() to gain access to the application instance, and so your variable, from anywhere else in the code.

Related

How to programmatically print without prompting for filename in MFC and CView using Print-To-PDF printer?

I have a large graphics program using C++, MFC, and C++6.0.
I need it to print to PDFs without prompting the user for printer settings and file name.
I use CView::OnPrint() to print using Microsoft Print-to-PDF and it works fine except for the user prompts.
I've seen how to bypass those prompts with a PrintDocument object in C# but how can I do that when using CView::OnPrint() in MFC? Surely there must be a way?
My project is much too big to consider re-writing in C#, and I've tried moving forward to Visual studio 2005/2010/2019 etc. without success as changes in default data structure packing and converting existing data files is fraught with problems so solution has to be an addition to existing MFC C++6.0 if at all possible.
Can anybody help?
I haven't used VC++ 6 in quite a while now, so I'm going from rather distant memories, but the general idea is fairly simple.
Full Approach
Your view has a DoPreparePrinting member function. By default, this creates a CPrintDialog object, then invokes the CPrintDialog's DoModal to show the print settings dialog. Eventually (but not in DoPreparePrinting, if memory serves) that CPrinterDialog's CreatePrinterDC will be called to (obviously enough) create a DC for the printer using the settings the user entered in the dialog.
To bypass the dialog, you can override DoPreparePrinting. That receives a pointer to a CPrintDialog. Since you don't want to show a print dialog, you obviously won't invoke its DoModal member. Instead, you'll fill in its DEVMODE and DEVNAMES structures for the printer and any settings you want. Then when CreatePrinterDC gets called, it'll use what you filled in without displaying the dialog.
My personal advice would be to do a run using the dialog under the debugger, then after the CPrintDialog's DoModal has returned, look through the DEVNAMES structure it returned. You may not need it, but I found the DEVNAMES structure a little confusing the first time I had to set it up on my own. The DEVMODE is bigger and arguably more complex, but I've usually just modified a few bits and pieces, and left most of it with default values.
Simplified Approach
If you just want to use the system's default print settings, there's a simpler approach: you can override OnPreparePrinting. This receives a pInfo parameter, which is a pointer to a CPrintInfo. That has an m_bDirect member, which you can set to true to do "direct" printing, which just uses the default settings without using a printer dialog. I don't remember for sure when m_bDirect was added though. If it's missing, there's a "trick" to get the same effect: the default implementation of DoPreparePrinting doesn't display a print dialog for a print preview, so you override OnPreparePrinting to set m_bPreview to true, invoke DoPreparePrinting, then set m_bPreview back to false.

Is it possible to create a dynamic room by passing in variables?

I am attempting to create a framework where I can have multiple events all use the same room.
For example, the player triggers an event and the event builds the room with the passed in variables.
I am having trouble making the room dynamic. I want the room and the objects in the room be reusable for every event. This includes the buttons as well.
Is this possible to do?; OR
Do I have to create separate rooms for each unique event I wish to create?
The game is mostly menu based (like the game "Long Live The Queen") if that helps.
To answer simply, yes it is possible.
There are a lot of cases where I have been able to fit a lot of stuff into a single room in Game Maker. Here are a few ways to achieve this "dynamic" game creation:
Files and Scripts. You can use a single room to hold a variable number of levels by storing walls, floors, player positions, events, etc inside of a file. You can make a script that takes the filename (your "passed in" variable) and then let it simply create all of the instances inside the level for you in that room. You can also have a function that cleans up the room to prepare for another level to load. The side effect though is that your uniqueness is limited to what information can be stored in those files. You can store menu options and text dialog too if you wish.
"Unique" Objects. Game Maker is an IDE. There is nothing stopping you from making new objects in the editor for a unique case and then adding a handler in another object to create it on demand. You have to manage switching between them though.
Make a "manager" object. It can handle all of the events of something happening in-game (and in that room, for that matter). Plus also it can be used by objects to store non-global variables before being destroyed. For instance, if a character dies, it can set a variable in a manager object to "true", which would trigger a boss to appear.
In terms of manipulating object events dynamically though, unless you are running something like Game Maker 8, that is no longer possible. I say this because prior to GameMaker:Studio, object, sprites and others can be created dynamically in game via functions like "object_add()". Of course, these are obsolete and can no longer be used. Nevertheless, there are always ways around it.

Adding an object to a vector

this is my first question on this website, but I will try to cover everything that is needed. Apologies if I forgot something. I encountered the problem using QT Creator, but I suppose it would be the same using Visual Studio, or just C++ in general.
I've got a couple of classes: Mainwindow, Track and AddForm. Mainwindow is what it is called. The main form. Track is a custom class based on QObject which contains just a single QString variable (just for now, since I am still experimenting with QT). And AddForm is a class for another form that can be created by clicking a button in my MainWindow form. That form only contains a single line-edit to fill the string and a button that says "Add". Whenever that button is pressed the text from the line-edit will be put into the QString variable from the Track-class. That QString variable is called "artist".
Apart from assigning the text from the line-edit to the variable "artist" for the Track-object, the form will also emit a signal that sends that entire object. A slot within my mainwindow will react to that signal and collect the Track-object. So far so good.
Here is my question. Within my mainwindow-header I have created a private QVector named trackVector, which I can then call within my mainwindow.cpp. What I want to do is append / push_back the QVector with that Track-object. Sort of like this:
trackVector.push_back(trackObject);
I get the following error message when building the application:
click here for a screenshot
Now ofcourse with an integer or any other variable this is very straightforward. You would just do something like this I suppose:
QVector<int> myVector;
myVector.push_back(3);
I think that whenever you append a QVector (or a standard non-QT vector) you need to do so with the constructor of that class. But how can I make a constructor in which you can just put an already existing object?
Please explain with as much simple words as possible since I am no native English speaker :) Thanks a lot in advance!
You've posted insufficient code (so your post is liable to be closed as off topic -- a classical beginners error on SO), but I guess the appropriate solution here is to use some auto pointer type. If your TrackVector is to keep ownership of the Track objects, then the best solution is have std::unique_ptr<Track> elements:
std::vector<std::unique_ptr<Track>> TrackVector;
// filled like
TrackVector.emplace_back(new Track(args));
If, on the other hand ownership lies somewhere else, you may either use std::shared_ptr or even raw pointers (provided your layout guarantees that the pointed to Track objects' lifetime exceeds that of the TrackVector).

WinAPI - how to organize lots of HWND objects?

As I push forward my first winapi UI, I find myself creating large, uncomfortable stacks of HWND variables in my WinMain file:
HWND foo;
HWND bar;
HWND baz;
HWND etc;
int WINAPI WinMain(...) {}
Of course, these variables are used in the functions in the rest of the file - the message loop, for example - so they must be accessible.
For my relatively small UI, I'll have something like 30 HWNDs piled up so they're in a visible scope. This makes me very suspicious that I'm doing it wrong.
Is this what should be happening, or is there a more practical way to organize this?
You have a few solutions, depending what your program is.
You can put all those handles in one or many containers like std::vector.
You can map them like chris suggests.
If your program gets big, you might want to organize them into logical units. For example, if 15 of those windows are for one half of your logic and the other 15 for another half (say controls inside tabs) then you might want to group those controls in some way (file, class, whatever is the most logical fit).
You only need one HWND in your main program, and that's for a main window.
The API doesn't require a single main window, but that's most common. And even when from a user point of view the application offers several apparently independent windows, it's a good idea to have a main window in the program (it can be invisible, but provide grouping).
The other windows are then either children of the main window (within it), or windows "owned" by the main window. In general. And in particular for a first ever Windows program. :-) So you don't need separate variables for these windows. Whenever a window should react to something, that's a message to the window, which means a call of one your functions with the relevant window handle as argument.
Every child window can have a unique integer ID, and that's one way to keep track of them.
But as you get ahead you will want to associate state with each window, and the easiest way to do that is to use the Windows "subclassing" API to associate a pointer with each window. Then you can route window procedure calls to a method on an associated C++ object. Where different messages can be routed further to different message handling methods, each with access to window's state (it's just this C++ object).

In MFC program, how to pass data between different dialog?

In web development, when we want to pass something between different pages, we might use the Session to save the data. But in MFC, what can we use to store these things?
Thanks!
Typical MFC Applications will have a Document-View-Frame architecture. Data is stored in the Document object, and accessed globally. You can access it anywhere via AfxGetMainWnd().
AfxGetApp() will also get you a pointer to your main application, which is another good spot to store data if you're not using a Document View architecture. If there is a lot of data, you can construct a class to hold the data, then add an instance as a member variable to the CWinApp in your project.
Another option, which I don't recommend but I have seen, is to have the dialogs themselves as member variables in the CWinApp, and then each dialog can reference the other. Basically, the user clicks 'ok', but then the dialog disappears, but is not deleted. This means all the data they entered is still accessable via the dialog variable.
There are a ton of ways to share data between dialogs. You may need to be more specific about your needs.
Store it in a global variable.
Store it in thread local storage (TLS).
Have one Dialog send a window message via SendMessage() or PostMessage().
Things get more complicated from there.