CEdit::ModifyStyle(), dosallow 0 when es_number is set inside CDialog::OnInitDialog - visual-c++

I have an edit control which should only take integers betweeen 1 and 99.To achieve this, i used, modifystyle() and limittext().Is there a way to restrict 0 from being entered?

You do not have to control values limit it using your code.
It is easier if you subclass (add variable) edit control using wizard, you can choose UINT type and set minimum and maximum value here.
Also do nto forget to set style to ES_NUMBER (setting Number to True in edit control Properties).

If you absolutely need that, you must derive a class from CEdit and process the input accordingly. Rendering the baloon that says "Unacceptable Character" may be bit tricky to give online-error. The class would be useful only if you are planning to use such class (edit-control) at multiple places, preferably with different ranges.

This is completely different problem from than one in your original post.
Make sure that your spin control follows immediately edit control in the Z-order (tab order).
In the resource set spinner style to: UDS_AUTOBUDDY UDS_SETBUDDYINT, UDS_ALIGNRIGHT,.
This will causse spinner to: choose edit control as buddy, set integer in edit box, place itself inside edit control to the right edge.
To do that, in the properties for the spinner set: "Auto Buddy" True, "Set Buddy Integer" True and "Alingment" to Right Align.
You do nto have to set minimum and maximum for the edit control, handle it now in the command handler for EN_CHANGE notification.
Place this code in the handler.
void CYourDlg::OnEnChangeEditNum()
{
int iValue = GetDlgItemInt(IDC_EDIT1);
if(iValue < 1 || iValue > 99)
{
m_Edit.ShowBalloonTip(_T("Number Out of Range"), _T("Value must fall between 1 and 99."), TTI_INFO_LARGE);
}
}

Related

Visual Studio MFC change text in Edit Control while typing/dynamically

I am trying to set up a MFC C++ App in Visual Studio 2019 such that modifies the user's text as they are typing.
Current layout is 2 radio buttons,
ID= rdbOn (set to Group = True, with Value int variable m_isOn = 1)
ID= rdbOff, m_isOn value would be = 0
and 1 Edit Control,
ID= txtInputBox, with Value CString variable m_inputString
Currently, for testing I can see how it would work for a button on click, it would take something like the following and just SetDlgItemText of the result. But that would be after they have typed, not WHILE they are typing.
void Onsomebtnclick()
{
//convert CString to String of m_inputString
//do some string manipulation
//convert back to CString
//SetDlgItemText(txtInputBox, result)
}
Update:
got EN_CHANGE to work
I was able to get EN_CHANGE working with the flag suggestion from user #GoGoWorx. However, now I just have a slight problem that the cursor is back to the beginning of the edit control txtInput.
I'm reading about using a CEdit::SetSel but don't know how to use that directly in my code. I tried
CEdit control MFC, placing cursor to end of string after SetWindowText
someDlg::someFunction()
{
//some logic stuff to get a result string
SetDlgItemText(txtInputBox, result);
//need it to set the cursor to the end
//I tried these, but it didn't recognize (expression must have class type?)
//txtInputBox.SetSel(0, -1);
//txtInputBox.SetSel(-1);
}
It sounds like you need to use the ON_EN_CHANGE message-map notification (called after the control has been updated due to typing or pasting for example)
BEGIN_MESSAGE_MAP(CMyDialog, CDialog)
ON_EN_CHANGE(IDC_EDIT_CONTROL, &CMyDialog::OnEnChangeEditControl)
END_MESSAGE_MAP()
void CMyDialog::OnEnChangeEditControl()
{
// Copy or call your Onsomebtnclick() here
}
I'm not sure what you're using for the numeric identifier for the edit control, since these are typically upper case defines - replace IDC_EDIT_CONTROL above with your define (possibly txtInputBox, but again, these are normally upper case, so I'm not sure).
Also change CMyDialog for the name of your dialog class too.
Note that we're using the ON_EN_CHANGE message-map handler here instead of the ON_EN_UPDATE, since the ON_EN_CHANGE message is sent after the control has been updated, whereas ON_EN_UPDATE is called just before it's updated.
The message-map handlers are described in the Remarks section of the CEdit control documentation: https://learn.microsoft.com/en-us/cpp/mfc/reference/cedit-class?view=msvc-160
Regarding your concern about modifying things as the user types - this should be fine, since every change (keystroke or paste from clipboard, etc.) should trigger this handler to be called, where you can change whatever you need. Just be sure that when you're updating the control, you don't trigger the ON_EN_CHANGE again and end up in a recursive 'change' loop.
You might be able to do this with some sort of flag to indicate you're the one updating the control, as opposed to the user, however it's probably better to subclass the CEdit control to do what you're wanting. There are a few examples out there of how to do this (it's not as difficult as it might sound), for example:
https://www.codeproject.com/Articles/27376/Avoiding-EN-CHANGE-notifications

Setting the main icon of a CTaskDialog as a Question?

I have this CTaskDialog that I am working on:
The code is as follows:
CTaskDialog dlg(_T("How would you like to download the data?"),
_T("Download Schedule Information"),
_T("Meeting Schedule Assistant"), TDCBF_OK_BUTTON | TDCBF_CANCEL_BUTTON);
dlg.SetMainIcon(TD_INFORMATION_ICON);
dlg.SetFooterIcon(TD_INFORMATION_ICON);
dlg.SetFooterText(_T("All assignments for the selected weeks will be reset."));
dlg.AddRadioButton(44444, _T("Download data for all weeks"));
dlg.AddRadioButton(44445, _T("Download data for selected week"));
dlg.AddRadioButton(44446, _T("Download data for selected week and all additional weeks"));
// Set Width in dialog units (40% screen width)
int iPixelWidth = (::GetSystemMetrics(SM_CXSCREEN) / 100) * 40;
int iDialogUnitsWidth = MulDiv(iPixelWidth, 4, LOWORD(GetDialogBaseUnits()));
dlg.SetDialogWidth(iDialogUnitsWidth);
if(dlg.DoModal() == IDOK)
{
auto iSelection = dlg.GetSelectedRadioButtonID();
}
Is it possible to set the main icon as a question? I can only see these defines in the source:
#define TD_WARNING_ICON MAKEINTRESOURCEW(-1)
#define TD_ERROR_ICON MAKEINTRESOURCEW(-2)
#define TD_INFORMATION_ICON MAKEINTRESOURCEW(-3)
#define TD_SHIELD_ICON MAKEINTRESOURCEW(-4)
The SetMainIcon member function is what you're looking for. Like most functions that deal with Win32 resources, it has two overloads:
void SetMainIcon(
HICON hMainIcon
);
void SetMainIcon(
LPCWSTR lpszMainIcon
);
The first takes a handle to an icon resource (HICON), while the second takes a string identifying a resource from which an icon resource can be loaded.
If you want to set the task dialog to display your application's icon, then you can simply pass in the appropriate HICON. You can also use a custom icon loaded from your application's resources.
I'm not entirely sure, but I think what you're asking is how to use a question-mark icon. Note first that the use of such icons in message boxes has been deprecated since Windows 95, and Microsoft strongly discourages their use. It is recommended that you only use them to denote entry points to online help. Quoting from the Standard Icons section of the official Win32 style guide:
Question mark icons
Use the question mark icon only for Help entry points. For more information, see the Help entry point guidelines.
Don't use the question mark icon to ask questions. Again, use the question mark icon only for Help entry points. There is no need to ask questions using the question mark icon anyway it's sufficient to present a main instruction as a question.
Don't routinely replace question mark icons with warning icons. Replace a question mark icon with a warning icon only if the question has significant consequences. Otherwise, use no icon.
So, this is why there's no standard question mark icon defined. These TD_*_ICON defines are straight from the Win32 headers for the Task Dialog (they're the same ones you'd use with the TASKDIALOGCONFIG structure), not part of the MFC wrapper class.
If you absolutely must use this icon, the workaround is as follows:
const HICON hiconQuestion = AfxGetApp()->LoadStandardIcon(IDI_QUESTION);
dlg.SetMainIcon(hiconQuestion);
(Note that the same HICON could be passed to the CTaskDialog's SetFooterIcon member function.)

How can I simulate hand rays on HoloLens 1?

I'm setting a new project which is intended to deploy to both HoloLens 1 and 2, and I'd like to use hand rays in both, or at least be able to simulate them on HoloLens 1 in preparation for HoloLens 2.
As far as I have got is:
Customizing the InputSimulationService to be gesture only (so I can test in editor)
Adding the GGVHand Controller Type to DefaultControllerPointer Options in the MRTK/Pointers section.
This gets it to show up and respond to clicks both in editor and device, but it does not use the hand coordinates and instead raycasts forward from 0,0,0, which suggests that the GGV Hand Controller is providing a GripPosition (of course with no rotation due to HL1) but not providing a Pointer Pose.
I imagine the cleanest way to do this would be to add a pointer pose to the GGV Hand controller, or add (estimated) rotation to the GripPosition and use this as the Pose Action in the ShellHandRayPointer. I can't immediately see where to customize/insert this in the MRTK.
Alternatively, I could customize the DefaultControllerPointer prefab but I am hesitant to do so as the MRTK seems to still be undergoing frequent changes and this would likely lead to upgrade headaches.
You could create a custom pointer that would set the pointer's rotation to be inferred based on the hand position, and then like you suggested use Grip Pose instead of Pointer Pose for the Pose Action.
The code of your custom pointer would look something like this:
// Note you could extend ShellHandRayPointer if you wanted the beam bending,
// however configuring that pointer requires careful setup of asset.
public class HL1HandRay : LinePointer
{
public override Quaternion Rotation
{
get
{
// Set rotation to be line from head to head, rotated a bit
float sign = Controller.ControllerHandedness == Handedness.Right ? -1f : 1f;
return Quaternion.Euler(0, sign * 35, 0) * Quaternion.LookRotation(Position - CameraCache.Main.transform.position, Vector3.up);
}
}
// We cannot use the base IsInteractionEnabled
// Because HL1 hands are always set to have their "IsInPointing pose" field as false
// You may want to do more thorough checks here, following BaseControllerPointer implementation
public override bool IsInteractionEnabled => IsFocusLocked || IsTracked;
}
Then create a new pointer prefab and configure your pointer profile to use the new pointer prefab. Creating your own prefab instead of modifying MRTK prefabs has advantage of ensuring that MRTK updates will not overwrite your prefabs.
Here's some captures of the simple pointer prefab I made to test this with relevant changes highlighted:
And then the components I used:

Why must you call SelectObject before calling GetTextExtendPoint32

I understand that for GetTextExtendPoint32 to work correctly, it needs to know the correct font. However, I'm confused as to why SelectObject needs to be called. Example I wanted to calc the length of the text for a check box.
Works:
Size sizeChkBox;
CString csChkBox;
m_ChxBox.GetWindowText(csChkBox);
CDC* dc = m_ChkBox.GetDC();
HFONT hfontChK = (HFONT)GetWindowFont(m_ChkBox.GetSafeHwnd());
SelectObject(*dc, hfontChK);
GetTextExtentPoint32(*dc, csChkBox, strlen(csChkBox), &sizeChkBox);
Doesn't Work:
Size sizeChkBox;
CString csChkBox;
m_ChxBox.GetWindowText(csChkBox);
CDC* dc = m_ChkBox.GetDC();
GetTextExtentPoint32(*dc, csChkBox, strlen(csChkBox), &sizeChkBox);
I guess my question really is why doesn't dc have the correct font already since its "made from the checkbox"?
GetDC(HWND) creates an HDC with all default settings, set up for drawing on a given window. It doesn't actually interrogate the window for its properties: in particular, it doesn't send WM_GETFONT to it.
Realize that WM_SETFONT and WM_GETFONT work only by convention. Nothing says that a window must handle these messages, or use the font provided in its WM_PAINT implementation. Standard controls tend to do this, as a common courtesy, but this is by no means a universal requirement.

How to create control at runtime using app.config?

I would like to create simple objects at runtime (textbox, label, etc) and add them to a Grid in my WPF application. My problem is that I need to define these in the app.config file. I am reading in the config data by using the “ConfigurationManager.GetSection” method. Shown below is an example of the XML that defines two textboxes. The Key values are always defined as Labels so the following defines two labels called “ID:” and “Name:” and two associated TextBoxes
<HardwareControls>
<add key="ID:" value="System.Windows.Controls.TextBox"/>
<add key="Name:" value="System.Windows.Controls.TextBox"/>
</HardwareControls>
At the moment I use the following code to create a TextBox object but need to modify it so that the control types are defined by the config data and not hardcoded. Can anyone help in how I would go about doing this based on me knowing the control type as defined by a string?
TextBox tb1 = new TextBox();
tb1.Width = 100;
tb1.SetValue(Grid.ColumnProperty, 1);
tb1.SetValue(Grid.RowProperty, i);
I can also see a situation where I may want to define additional values such as the textbox width in the config file. Is there a better solution to store this in the app.config as it looks like the “GetSection” method only supports a key/value pair (I may be rog in that assumption as I haven’t read too much about this yet).
You can use Activator.CreateInstance
Example:
string typeName = "System.Windows.Controls.TextBox";
Type type = Type.GetType(typeName);
object control = Activator.CreateInstance(type); // control is your TextBox
You can use Reflection to create a type from a string name - e.g.
http://en.csharp-online.net/CSharp_FAQ:_How_create_an_instance_of_a_type_using_only_its_name
or
How can I pass an argument to a C# plug-in being loaded through Assembly.CreateInstance?

Resources