Visual Studio MFC change text in Edit Control while typing/dynamically - visual-c++

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

Related

Changes to the contents of a control variable linked to a static text box doesn't reflect in the dialog

I have a CString variable which is linked to a static text box inside one of my dialogs, lets call it controlVariable. When I click the START button inside this dialog a couple of things happen. First I update the contents of the controlVariable (to say something like "initialization begun"). I do UpdateData(FALSE) and then run an initialization of another class (which starts some threads). This initialization takes some time, so this is why the contents of the static text box need to reflect that while its running. But the changes aren't reflected until the OnBnClickedStart() function finishes. I'm having trouble having the changes to this controlVariable reflect in the dialog.
What I've tried:
UpdateData(FALSE) after changing the controlVariable using basic CString append functions (e.g. CString A = str1 + str2;) and changing the control variable using .format() (e.g. controlVariable.format(_T("some text")); )
Running OnPaint() after changing the controlVariable contents
I went into debug mode and the program runs into the BEGIN_MESSAGE_MAP section of the dialog class and just loops there until I step out of it. The contents of the static text box linked to my controlVariable aren't updated until I step out of BEGIN_MESSAGE_MAP. So the contents of my static text box don't even update at the end of my OnBnClickedStart() funciton.
Example Code:
CMyClass someClass;
CString controlVariable; // linked to some static text in the SomeDlgClass
void SomeDlgClass::OnBnClickedStart()
{
controlVariable = CString("System initialized\r\n"); // Also tried
UpdateData(FALSE); // Also tried OnPaint()
someClass.initialize(); // I would like the static text box to update before I run this
}
So when I'm running this, my main dialog seems like it's "frozen" - I can't move the window around or click any of the buttons. Suggestions?
Thanks.

Running into issue creating shortcut on desktop

I've just created a custom dialog with a checkbox asking if the user wants to create a desktop shortcut. I used to always include a shortcut I'm not using the AskText() function as I plan on adding more pieces to this page later and want to simplify these few options to this one page.
I get an item on my desktop when I run, but it's not what I expect. The target seems to be pointing to a location on the desktop itself and not the actual executable. Also, this shortcut does not delete on uninstall (I'm assuming this needs to be handled separately anyway) and the shortcut needs admin rights to be manually deleted (which I don't want, for obvious reasons).
Below is my InstallScript code. It is in a custom action that was inserted after InstallFiles.
function MyFunction(hMSI)
STRING szProgramFolder, szItemName, szCommandLine, szWorkingDir;
STRING szShortCutKey, szProgram, szParam, szIconPath;
NUMBER nIcon, nResult;
begin
szProgramFolder = FOLDER_DESKTOP;
szItemName = "myProgram";
szProgram = INSTALLDIR + "myProgram.exe" ;
LongPathToQuote (szProgram, TRUE);
szCommandLine = szProgram;
szWorkingDir = INSTALLDIR;
szIconPath = "";
nIcon = 0;
szShortCutKey = "";
nResult = AddFolderIcon (szProgramFolder, szItemName, szCommandLine,szWorkingDir,
szIconPath, nIcon, szShortCutKey, REPLACE);
end;
I'm not quite sure where I'm going wrong here, although my knowledge of InstallShield (let alone InstallScript) is very limited.
As it turned out, this is a deferred custom action, hence the INSTALLDIR variable is not initialized (nor any other Windows Installer built-in variables). Change it to an Immediate-type custom action (and relocate it to an appropriate location in the execution sequence) and it should work.
To fix the shortcut's parameters, start by ensuring they are correct. Debug your function to verify you are actually passing what you want to. As commented, INSTALLDIR may not be available directly to an InstallScript custom action. A simple way to "debug" would be to add calls like MessageBox(szCommandLine, 0); to key points in your code. If you find you are passing something like C:\Program Files\Company\ProductmyProgram.exe, consider using the ^ operator to concatenate your paths: szProgram = INSTALLDIR ^ "myProgram.exe";.
To uninstall the shortcut, you have to understand that custom actions in MSI projects are not automatically reversed. So use a different approach. Either explicitly code up its removal during uninstall in another action, switch to pure InstallScript where logging will reverse your actions, or go with a proper MSI-based approach. For the last of those, define the shortcut in its own component, and give the component a condition that correlates to a property you set in your UI (or via AskText for now), or skip the condition and just use feature selection by putting the component in a child feature. Then Windows Installer will track and remove the shortcut for you.

paraview RequestData called once

I have created a paraview filter in C++. The problem is when I press apply button the filter works and show me the result but if I try it again (after any change in properties input), the RequestData function is not called anymore. This problem never appear when I used Python programmable filter. Any idea?
Make sure you're calling this->Modified() in the method that gets called after the property is changed e.g.
void SetMyValue(double value)
{
...
this->Modified();
}
You probably want to check that the value or some other state of your filter is changed which could potentially change the output of the filter before calling this->Modified(). Otherwise the filter may unnecessarily update and produce the exact same result. You can look at vtkSetGet.h for macros that do that (look at #define vtkSetMacro(name,type) ).

Unity - How to write a "Behaviour" or script for entire scene (in C#)?

I am starting to learn Unity.
As I understand, We can write scripts(behaviors) in the form of C# files and apply them to each objects on the scene.
But how to write a script for the entire scene? I know this is a obvious question - there has to be a script for the entire scene so that all my objects "behave" in a synchronized way and it's gotta be pretty basic, but preliminary Google searches has not borne much fruit.
Can someone give me a quick guide?
Taking your "boxes" example comment I would do the following:
Create an empty gameobject, let's call it BoxesController...
Attach below BoxesController.cs script to it
In the editor inspector reference all boxes
BoxesController.cs
public class BoxesController: MonoBehaviour
{
public Transform box1, box2, box3;
void Update() {
// change boxes position
}
}
Now imagine you will need to have > 30 boxes in current scene... You will have a lot of work to reference each box. So you could change your script if you add a Tag to all boxes. Let's say you create a new tag inside Unity Tag Manager called "Box" and give it to all boxes.
You now can change BoxesController.cs script to the above and you will not have to reference all boxes in the Editor Inspector because they will be searched and referenced inside Start method.
BoxesController.cs
public class BoxesController: MonoBehaviour
{
public GameObject[] boxes;
void Start()
{
boxes = GameObject.FindGameObjectsWithTag("Box");
}
void Update() {
// change boxes position
foreach (GameObject go in boxes)
{
//get box name
string box_name = go.Name;
// get box transform property
Transform t = go.transform;
}
}
}
Please note that GameObject.FindGameObjectsWithTag is a heavy operation and that's why I did it in the Start method and saved the result to reuse it in Update method calls.
what you can do is create an empty GameObject and add a script to it and use one of the techniques described in the link to get access to the 3 boxes you want to move.
http://docs.unity3d.com/412/Documentation/ScriptReference/index.Accessing_Other_Game_Objects.html
In this case you probably want to use "1. Through inspector assignable references." which just means create a public Transform variable in the script, save, then in the Inspector drag the box in the slot that appeared in the script-component
edit: for further reading i'd suggest googling the term "Game Manager" in combination with "Singelton" and "Unity" :)

CEdit::ModifyStyle(), dosallow 0 when es_number is set inside CDialog::OnInitDialog

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);
}
}

Resources