First let me say that I've been searching for a solution for couple of days now...
I'm trying to get selected item for ListBox. This is my code:
CListBox * pList1 = (CListBox *)GetDlgItem(IDC_LIST1);
CString ItemSelected;
// Get the name of the item selected in the Sample Tables list box
// and store it in the CString variable declared above
pList1->GetText(pList1->GetCurSel(), ItemSelected);
MessageBox(ItemSelected, "TEST", MB_OK);
Now when i try this i get an error message saying "The Parameter is incorect"
Your code looks OK except error handling. Also MessageBox parameters look incorrect. The first parameter should be of type HWND. I believe that this is the root cause of your problems. Use MFC standard AfxMessageBox instead:
CListBox * pList1 = (CListBox *)GetDlgItem(IDC_LIST1);
int nSel = pList1->GetCurSel();
if (nSel != LB_ERR)
{
CString ItemSelected;
pList1->GetText(nSel, ItemSelected);
AfxMessageBox(ItemSelected);
}
If the CListBox is in single selection mode, the CListBox::GetCurSel will return the selected index.
If the CListBox is in multi-selection mode, you should use CListBox::GetSelItems which will return a list of indices.
You cannot mix'n'match the functions.
And always check return codes (as others already wrote).
If You already have a data member MyList(of classCListBox) :
int nSel = MyList.GetCurSel();
CString ItemSelected;
if (nSel != LB_ERR)
{
MyList.GetText(nSel, ItemSelected);
}
CWnd class has a MessageBox function which does not need a HWND parameter. But yes, AfxMessageBox is a little bit more easier to use and can be called anywhere in the MFC code without having a CWnd-derived object. And a beside note: if call a WinAPI function inside MFC code (not needed here, but possible in other cases) it's good to prepend it with scope resolution operator in order to avoid any confusion, mistake and/or name conflict (e.g. ::MessageBox...).
One possible cause for "invalid parameter" error in OP code is that it uses an ANSI string literal ("TEST") in a UNICODE build configuration. This case, must use an UNICODE string literal (L"TEST") or a little bit better, use _T macro (_T("TEST")) that makes it possible to build in both ANSI and UNICODE configurations.
Related
Thank you for the answers and comments. I chose the answer I chose because it allowed me to continue to use CEdit with just a couple of minor changes to the code. However, the solution considering CMFCMaskedEdit also seemed to work as well when tested. If you choose to use that solution make sure you apply the correct functions for the object such as SetValidChars etc upon initialisation ! :) Thank you again everyone
I am using Visual Studio Professional 2017 C++ with MFC
I have a CEdit object in my MFC project which also has an EDITTEXT control in my .rc file.
The CEdit object will be edited by the user who will type a keyword, and I will do something with that keyword, that is, find files that contain that keyword.
Naturally, due to my task, I cannot allow the following char s: \ / : * ? " < > | , since these chars are not allowed to be in a file or folder name.
What can I do to prevent a user from entering these characters into the CEditBox. Realistically, the only chars I will need are: A-Z, a-z, 0-9, and _.
Another specification: no regex please ! Ideally the answer will use a Control (I looked here) or function (I looked here) I may have overlooked.
If there is no solution, I will fall back to this:
I will check whether any of these chars are in the text the user entered. If no, awesome, nothing to worry about ! If yes, then I will return an error :)
Thank you in advance ! :D
I can think of two possible solutions to your question. The 1st solution posted just below is the easiest to implement because it does not require subclassing the control.
1st Solution - Control Notification
Edit controls send the EN_UPDATE notification, just before the (updated) text is about to be displayed. You can capture this event easily: open the Resource Editor, go to the dialog, select the edit conrol and in the Properties Editor go to Control Events page and Add the EN_UPDATE handler. The editor will add the handler to the message-map and generate the function:
BEGIN_MESSAGE_MAP(CMyDialog, CDialogEx)
.
.
ON_EN_UPDATE(IDC_EDIT_FNAME, &(CMyDialog::OnEnUpdateEditFname)
END_MESSAGE_MAP()
In the generated function add the following code:
void CMyDialog::OnEnUpdateEditFname()
{
CString s;
GetDlgItemText(IDC_EDIT_FNAME, s); // Get the control's text - may contain illegal characters
// First illegal character position
int nFIChar = -1;
// Loop until all illegal chars are removed - will also work for a paste operation w/ multiple illegal chars
while (LPCTSTR p = _tcspbrk(s, _T("\\/:*?\"<>|")))
{
if (nFIChar<0) nFIChar = p-s; // Store 1st illegal char position
s.Remove(*p); // Remove illegal char(s)
}
if (nFIChar>=0) // At least one illegal char found
{ // Replace the control's text and display a balloon
CEdit *pEdit = (CEdit*)GetDlgItem(IDC_EDIT_FNAME);
pEdit->SetWindowText(s); // SetWindowText() will reset the caret position!
pEdit->SetSel(nFIChar, nFIChar); // Set caret to the 1st illegal character removed
MessageBeep(-1);
pEdit->ShowBalloonTip(NULL, _T("A file name can't contain any of the following characters:\n\t\\ / : * ? \" < > | "));
}
}
This will remove the illegal characters and will display a balloon tip, like when entering an illegal character while trying to rename a file in File Explorer. It's tested and works.
Alternative Solution - Subclassing
Another solution is possible, employing a subclassed control class:
Define a CEdit-derived class.
Add a handler for the WM_CHAR message.
In the WM_CHAR handler, if an illegal character is about to be entered, beep and display the balloon, but do NOT call the default, otherwise call it.
So the code could be:
BEGIN_MESSAGE_MAP(CFilenameEdit, CEdit)
ON_WM_CHAR()
END_MESSAGE_MAP()
void CFilenameEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
if (_tcschr(_T("\\/:*?\"<>|"), nChar))
{
MessageBeep(-1);
ShowBalloonTip(NULL, _T("A file name can't contain any of the following characters:\n\t\\ / : * ? \" < > | "));
}
else CEdit::OnChar(nChar, nRepCnt, nFlags);
}
You may want to add a handler for the WM_PASTE message too.
Then you have to use it in your dialog, just use the Class Wizard to add a member variable of the derived edit class, associated with the edit control. It can be easily reused in another project.
EDIT:
The 1st solution (capturing the EN_UPDATE notification) is easier to implement (although there's more code in this sample - the 2nd one doesn't currently handle the paste operations) because it does not require defining a new subclass. It's what a developer would choose to handle a special requirement, quickly implementing it for the project.
The 2nd solution defines a new subclass. It can be reused in another project - I tend to favor reusable code - but it needs to be completed (handle paste operations as well) and then maintained. And in order to be more useful it should preferably be enhanced, for example make it more general, like add an option for fully-qualified path/file names (they may contain \, : or ") or better yet allow the developer to define the set of invalid characters - in this case the message displayed should also be defined by the developer*, as the new class could be used in more cases, not just for filenames or paths. So this would require more work initially, and it's finally a matter of choice (a bigger "upfront investment", with potential future benefits).
* The 2nd line of the message, containing the invalid character list should be constructed programmatically, by the class's code
Note: The _tcspbrk() and _tcschr() (THCAR.H versions of strpbrk() and strchr()) are CRT functions. One could alternatively use the StrPBrk() or StrCSpn() and StrChr() functions from Shlwapi - many useful utility functions there btw.
I suggest you switch to using the CMFCMaskedEdit class instead of CEdit. It supports exactly the behavior you are after.
I use CreateWindowEx which expands to CreateWindowExA. That function uses LPCSTR types. I would like to pass as a second argument MSFTEDIT_CLASS (from Richedit.h):
#define MSFTEDIT_CLASS L"RICHEDIT50W"
The following casting doesn't work:
(LPCSTR)MSFTEDIT_CLASS
CreateWindowEx returns NULL. It works when I pass the second argument this way:
"RICHEDIT50W"
but I don't want to copy a string from the header. How to fix that ?
There is only a single, viable solution here: Call CreateWindowExW, either directly or by defining the UNICODE preprocessor symbol and have the generic-text mapping CreateWindowEx expand to CreateWindowExW.
The window you are creating is a Unicode window, always. The character set used for communicating with a window is set at class registration time. The window class named "RICHEDIT50W" is registered using RegisterClassExW by the system. You don't have control over this.
Since you are eventually going to have to talk to the window using messages, you will need to use the Unicode variants of the message handling functions (GetMessageW, DispatchMessageW, etc.). You cannot use the ANSI versions, unless you are happy with an application, that sometimes doesn't fail.
I have the following wxDialog parent window:
I have created that parent window by the following code:
settingsFrm settingsWindow(this, "Settings");
settingsWindow.ShowModal();
I have tried to use FindWindowByName to get the value of the first text ctrl as follow:
wxLogMessage(dynamic_cast<wxTextCtrl*>(settingsWindow->FindWindowByName("keywords_txt"))->GetValue());
But unfortunately, it doesn't work and gives me a runtime error.
I don't know if that method suitable to do what I want.
How to get the value/other of a control through its parent window?
From your comments, it seems like you expect the function to find the control from the name of the variable in your code which is not how it works and would be pretty much impossible.
FindWindowByName() uses the window name (and, as a fallback, label, but this is irrelevant here because text controls don't have labels anyhow), so for it to work you need to set the window name when creating the control, using the corresponding parameter of its ctor. This is very rarely useful in C++ code, however, as it's simpler to just store a pointer to the control in some variable and use this instead.
FindWindowByName() can often be useful when creating controls from XRC, however. If you do this, then you should specify names for your controls in XRC and pass the same name to this function.
How did you create the TextCtrl instance? You should have something like wxTextCtrl m_textCtrl1 = new wxTextCtrl(/// arguments); Accessing the value should be very easy, as wxString text = m_textCtrl1->GetValue(); You definitely don't need FindWindowByName just for what you are trying to do here.
As mentioned in the title, I am currently using VS 2010 C++ , MFC application for my project. Currently new to programming.
I am currently asked to create an edit box to accept names, full names, e.g "Lee Roy Long". I have looked through many other websites but I am confused with which method should I use to do it.
Is there any examples or a guide to how to go about this?
EDIT: I have another question aside from this solved one [ Cannot Post new questions due to the "restrictions"], I am currently using the same edit box to add new names as strings into the SQLite database. I am currently having some trouble converting CString to string
vector<int> userSerialNumber;
vector<string> userName;
vector<int> userID;
vector<int> userTrainingImagesNo;
Program starts here:
CString str,text;
CString Lone = _T("MEEP"); // This one converts it succesffuly...
string ss((CStringA(Lone)));/Only works for declared CStrings?
CEdit* editBox = (CEdit*)GetDlgItem(IDC_EDIT1);
editBox->GetWindowText(str);
Adding the user's input from above into the program below.
userSerialNumber.push_back(newserialnumber);
userID.push_back(newserialnumber);
userName.push_back(ss);
userTrainingImagesNo.push_back(Img);
I have referred to many websites on how to convert CStrings to strings, but none of them worked, including this one.
As I debug the program, the conversion between CString and string did not work as I get "" for string, which causes the database to update a blank "".
CString str = "name";//Name CString gotten from EditBox
std::string newname = ""; //After typing many conversion methods, results ""
Is there something that I did not notice regarding this ?
You can filter the keystrokes going into the edit control by deriving a class from CEdit and handling the WM_CHAR message in your derived class. To accept a key pass it along to CEdit::OnChar, to reject a key simply return without calling the CEdit function.
To connect the edit control to your code you use a standard MFC subclassing technique. Right-click on the control and create a control member variable (a CEdit) in the parent window. Then edit to change the variable from a CEdit to a CYourDerivedCEdit.
There is a tutorial about this and a sample project at http://www.flounder.com/validating_edit_control.htm
As an alternative to trapping each character, you can handle the CWnd::OnKillFocus event for the edit box and interrogate the value once. Validating can be done by using CString::SpanExcluding with numbers and any other character that should not be in the resulting string. For example,
CString stringEnteredByUser = _T("Lee Roy Long");
CString validatedString = stringEnteredByUser.SpanExcluding("0123456789");
if (stringEnteredByUser != validatedString)
AfxMessageBox(_T("Invalid string"), MB_OK);
The 'stringEnteredByUser' variable should contain the string entered by the user. In this example, using SpanExcluding will tell you if they've entered a number. The returned string from the call (validatedString) will not match the string the user typed (stringEnteredByUser) if they've entered a character that is invalid (ie. the character is within the list provided to the SpanExluding call).
If the validatoin fails, simply force the focus back to the edit box.
I'm assuming you know some basic event coding.
Use the Textbox.textchanged event.
Also research ASCII and its conversion (asc function.)
If you need any more help, comment below.
Good luck!
Having a problem here with creating a child window with c++ and win32 api.
If i check the getLastError function its returning "87" but i dont know what that means.
For what i know my code does not contain errors, can someone take a look at my code and help me figure out whats wrong with it.
(This is in the WinProc WM_CREATE section.)
HWND hChildWindow = CreateWindowEx(WS_EX_CLIENTEDGE,0,NULL,WS_OVERLAPPEDWINDOW|WS_VISIBLE,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,hwnd,0,GetModuleHandle(0),NULL);
if(!hChildWindow)
{
char text[256];
int errormsg = (int)GetLastError();
sprintf(text,"Error# %i",errormsg);
MessageBox(0,text,"Error",MB_OK|MB_ICONEXCLAMATION);
return false;
}
87 = Invalid Parameter - be aware that you can use FormatMessage to get a string message from an error code.
The 2nd parameter to CreateWindowEx is a window class (either string or ATOM). Obviously NULL is not a valid value.
P.S.
For what i know my code does not
contain errors...
Beware of such a loud phrases. When something doesn't work everything should be checked carefully. Otherwise you may just accuse something/someone without any good for solving the problem. Check everything vs standard/documentation/specifications/etc. before you make any judgement.
A quick look through the System Error Codes reference indicates ERROR_INVALID_PARAMETER. You're most likely passing in an invalid combination of styles/flags to your window.