Language: C++
Development Environment: Microsoft Visual C++
Libraries Used: MFC
Background: So I've created an application that is basically a large preference dialog where the user can configure a number of pages, each with a bunch of different settings. When the user is finished, he/she has three options for saving the preferences (as XML): Save Current [page], Save These, and Save All.
I'm working with the Save These function right now. When the user chooses this option, a dialog appears with check boxes for each page, allowing them to choose which pages they wish to output. Once they choose the directory into which they wish the files to be saved, the magic happens and the XML files are written.
Problem: I have a function (UpdatePageData) that will detect which page is being displayed and update the current page's data by calling UpdateData. I have put in a break point to watch to make sure the variables are being filled with the user's inputted values, and everything is dandy and working correctly. However, when the program jumps from the checkbox dialog (where I call UpdatePageData) to the classes for the pages I'm saving, suddenly all of the values are wrong.
Below I've included some code that will help you guys understand the program flow.
NOTE: In SaveThese, I am currently just working on saving a single page...I will have it update all pages selected once I figure out the problem I'm having.
Location: Main Dialog
void CSAPrefsDialog::OnSaveThese()
{
int msgboxID = ::MessageBox(
NULL,
(LPCSTR)"Are you sure you want to save?",
(LPCSTR)"Save These",
MB_ICONQUESTION | MB_OKCANCEL
);
switch (msgboxID)
{
case IDCANCEL:
break;
case IDOK:
UpdatePageData();
CSaveThese m_sT;
m_sT.DoModal();
break;
}
}
Location: Main Dialog
void CSAPrefsDialog::UpdatePageData()
{
if ((m_iCurPage >= 0) && (m_iCurPage < m_pages.GetSize()))
{
pageStruct *pPS = (pageStruct *)m_pages.GetAt(m_iCurPage);
if (pPS)
{
ASSERT(pPS->pDlg);
if (pPS->pDlg)
{
if (!pPS->pDlg->UpdateData()) // THIS WORKS. THE DATA IS UPDATED.
{
AfxMessageBox("Did not update data.");
}
}
}
}
}
Location: SaveThese Class
void CSaveThese::OnBnClickedOk()
{
// TODO: Add your control notification handler code here
UpdateData(TRUE); // figures out which boxes are checked for saving
CDirDialog dir;
CSAPrefsDialog prefsDialog;
if(dir.DoBrowse())
{
prefsDialog.m_strDirectorySavePath = dir.m_strPath;
}
// [ other if-statements like the one below to check the check boxes ]
}
if(m_bST_FS)
{
FSC_Main m_FS;
m_FS.Save(prefsDialog.m_strDirectorySavePath);
}
OnOK();
}
Location: FSC_Main Class
void FSC_Main::Save(CString dirPath)
{
if(Validate())
{
dirPath += "\\FS_Config.xml";
FILE *fp = fopen(dirPath, "w+");
WriteXML(fp);
fclose(fp);
}
}
By the time it gets to WriteXML, the values have either reverted back to their initialized values (empty strings and -1 for all combo boxes), or have strange values (empty for strings, and large numbers for combo boxes).
I imagine I just have something in the wrong place. I'm just not sure why this is happening, and it's really the biggest hurdle between me and really getting this project rolling.
Jon, Very hard to understand your code. What i understood is you have a member variable m_pages in CSAPrefsDialog dialog class which you are updating by calling UpdateData. And then you are creating a local variable CSaveThese m_sT and calling DoModal. Do you expect CSaveThese class should hold the values of m_Pages?
Related
I have an application (Manager) used to send commands to another application (Instructor) through sockets. From the first application I will have configure some data which is useful to invoke and run the second application. Same time im getting reports from the second application to first application.
Let me explain my question, I have the set of exercises which has to be run in second application. Either I can invoke it from First app or from the second app by invoking the exercise dialog. Once I invoked, I can get the report. For that I have one button in my first app.
Here whats happening,before the exercise dialog get invoked,when i press this button, it shows error.
So, I just want to know whether that dialog is opened or not.
I use GetSafeHwnd(), but once the object created for that dialog class, these handle get some value even the dialog is not open.
Here I pasted the code, once I get the button press 'GenXL' command from first app.
extern CPerfScore *oPerfScore;
void CMainFrame::ProcessPendingRead(void)
{
int nRead;
CString strBuf;
CString sCmd;
nRead = m_pCltSocket->Receive( &m_pRecPacket, sizeof(Packet));
if(nRead > 0)
{
// read the message
sCmd = m_pRecPacket.sMessage;
AfxMessageBox(sCmd);
if (sCmd.CompareNoCase("CLOSE") == 0)
{
OnClose();
}
if (sCmd.CompareNoCase("GENXL") == 0)
{
if(oPerfScore->GetSafeHwnd() == 0)
{
oPerfScore->SendMessage(WM_COMMAND, IDC_GENERATE_EXCEL);
}
else
{
AfxMessageBox("Exercise dialog not open");
}
}
}
}
A handle will be valid even if the window isn't currently being shown, as long as it has been created. I think you're looking for the API call IsWindowVisible(). I believe MFC wraps this as a member.
I have added a CMFCOutlookBar control to a dialog. This outlookbar contains some 12 trees.
As per following link https://msdn.microsoft.com/en-us/library/bb983453.aspx
we can set active tab (in my case tree control) of our wish.
but it doesn't seems to work.
as per above link this function returns non zero value on success. Indeed it is returning 1 when i used it to set tree of my choice. but visually it's not changed.
can someone help me?
Problem solved.
CMFCOutlookBarTabCtrl::SetActiveTab() only works after window has been displayed.
I guess this is because CMFCOutlookBar stores it's previous state to registory and reloads on next run. And this overrides changes made by SetActiveTab(), if we use it before displaying of window.
I had the same problem, and you are correct that on load the tab gets set to the last session value - actually it seems to get set several times during the load process - some of them seem to correspond to each time a tab is added, and then the last time it is called seems to be the tab from the previous session.
The solution is to set the value once the window is ready to be shown. This can be done by overriding the OnShowWindow callback on the view which contains the tab bar.
In my case the tab bar is added in a view called MainFrame, which has a member variable CMFCOutlookBarTabCtrl* m_pOutlookBar; which is initialised in the OnCreate callback.
I can then correctly set the tab by overriding OnShowWindow to contain the following:
void MainFrame::OnShowWindow(BOOL bShow, UINT nStatus)
{
CFrameWndEx::OnShowWindow(bShow, nStatus);
if ((m_pOutlookBar != NULL) && bShow) {
//When the tab bar is shown, select the correctview
for (int tabIdx = 0; tabIdx < m_pOutlookBar->GetTabsNum(); tabIdx++) {
CString requiredLabel;
CString thisLabel;
requiredLabel.LoadString(IDS_OF_TAB); //The ID of the tab wanted
m_pOutlookBar->GetTabLabel(tabIdx,thisLabel);
if (requiredLabel.Compare(thisLabel) == 0) {
//If the tab label matches the one required
m_pOutlookBar->SetActiveTab(tabIdx); //set it as the active one.
break; //done.
}
}
}
}
I am a new comer in MFC programming. I have already wrote a program, and I want to display the program in a graphical interface. So I use MFC dialog to realize it, but it does not work when runs.
Once the OK button is clicked :
void CTest1Dlg::OnBnClickedOk()
{
UpdateData();
FILE *stream;
freopen_s( &stream, "out_file.ps", "w", stdout ); // reopen stream as .ps
if (mode == 1) //main() in my code
{
ActiveAuthoring();
}
else if (mode == 0)
{
XYAuthoring();
}
else
{
ActiveAuthoring();
}
cout<<"showpage"<<endl;
UpdateData(FALSE);
OnOK();
}
My code is in converter.cpp, so first I change converter.cpp to converter.h and include it in Test1Dlg.cpp. And then when the OK button click run the main() in my code.
However, I discover that it seems the parameter does not transfer from the graphical interface to my code, although I relevant the edit control box to every parameter. So the dialog does not work. Could some one help me?
EDIT
The eight edit control boxes are the parameters I used in my coverter.cpp.
My code is aim to use eight parameters to generate some strings, these strings are saved in a file named as out_file which format is .ps.
There are two basic ways you get data from dialog controls to "your code"... if you're using the Visual Studio dialog editor and adding the controls there, it will generate code inside of virtual void DoDataExchange(CDataExchange* pDX) for you to move data to and from your controls when the dialog gets initialized and terminates. You'll have a line like DDX_Text(pDX, IDC_DIGITS, m_Digits); that the IDE adds that does the exchange. You can also just set and get the data directly if you wanted, e.g. GetDlgItem( IDC_DIGITS )->GetWindowText( m_Digits );
Hello everybody reading this. Thanks in advance for your time.
One thing before question: I DO NOT use neither MFC nor Windows Forms, just WinApi in C++.
Well, I am making a polynomial calculator in Visual C++. I added a Dialog to it, which was created in resources (.rc file) using drag'n'drop method. I suppose there would be no such a problem if i created my Dialog with CreateWindowEx (but I don't want to).
My Dialog has a few of Edit Controls. Everything is fine except that when the Dialog is launched, one of Edit controls takes focus to be ready to take keyboard input.
I have included management of EN_KILLFOCUS (Edit sends it to parent when loses focus due to selecting another control).
Here I read from control to wstring (string of wide characters - _UNICODE is defined), use some kind of parser to verify this wstring and remove bad characters, and then put correct string into the same edit control. It works fine, but here is the source of my problem:
When there was no input, parser returns string "0" (not the NULL, string is just set to "0"), as if control had focus and then lost it even before I clicked anything in Dialog.
Due to that, and something else (this is what I have to figure out), at the Dialog launch parser puts this string "0" to edit.
I want to make my edit not be able to take input from keyboard until i click one of the Edits (including this one).
If it is not possible, I want to clear the whole text at the beginning of dialog (being able to take input is not a problem, I just want to prevent parser from entering string "0" at the beginning)
My code:
In DlgProc I have:
//up here is switch to manage all controls
case MyEditID: // here is ID of one of my edits from resources
switch (HIWORD(wParam))
{
case EN_KILLFOCUS: // edit lost focus - another control selected
if (LOWORD(wParam)==MyEditID) //necessary to determine if
// one of allowed Edits sent this message
// because I have also other Edits
{
GetDlgItemText(hPanel, LOWORD(wParam), MyTempWcharArray, 100);
MyTempString.assign(MyTempWcharArray);
w1 = polynomial(MyTempWcharArray); // parser takes the string
// and removes bad chars in constructor
// polynomial is my class - you don't have to care of it
// w1 is declared before as object of polynomial class
MyTempString = w1.ConversionToString();
SetDlgItemText(hDialog, LOWORD(wParam), sw1);
}
break;
}
break;
does it matter what integer number is set to Edit's ID?
I know SetFocus(), and WM_SETFOCUS message. In this case I just can't get this working.
If i haven't included something important to make you see my point please let me know. I'm sorry I'm just a newbie in WinAPI world.
EDIT:
For those with a similar problem: Do not do this:
I made an workaround with global variable ProcessKillFocus set to false indicating that instructions in message management should not be processed, except that at the end (just before break;) I am changing it to true, so next time and later it will be processed:
case EN_KILLFOCUS:
if (ProcessKillFocus && LOWORD(wParam)==MyEditID)
{
// first time global ProcessKillFocus is false so all this is skipped
// 2nd time and later do all the stuff
}
ProcessKillFocus = true;
break;
Huge thanx to Sheyros Adikari for making my question easy to understand!!!
Huge thanx to patriiice for simple answer on a huge messing question!!!
ANSWER:
BTW: patriiice, I tried this:
case WM_INITDIALOG:
SetFocus(GetDlgItem(hDialog, Desired_Control_ID));
return (INT_PTR)FALSE;
break;
IT JUST WORKS!!!
You have to return FALSE to WM_INITDIALOG message and set the correct focus by yourself.
When I hover over this 'X' button the tip says "Close" and it behaves somewhat erratically closing one or several files that are not modified and prompting to save one or more files that are modified.
Sometimes it takes several clicks of the 'X' to clean up all the files. It would nice if this 'X' button behaved like the File Exit menu item.
I struggled with this for a while. I remeber overriding didn't work for whatever reason. In the end i just placed some code in the apps destructor to handle file saving etc. Not ideal, but im happy with it.
You can throw up a dialog like this:
int nResult = AfxMessageBox("Save changes to Current Job?", MB_YESNO);
if (nResult == IDYES)
{
m_bClosing = true;
OnFileSave();
}