Can I use the value(numeric) in the edit box to set it as the position on a scroll bar? If yes, then how? - c++

Suppose in a dialog based application, I have a scroll bar and an edit box to display the position of the scroll bar.
Now, I want to improvise and put a value in the edit box myself and as soon as I type it, the scroll bar scrolls to that position.

you can select edit control and go to property window and make Number as TRUE.
By this user can only enter numeric value in editbox.
Use SetLimitText(); function to limit the length of character in edit control.
m_edit.SetLimitText(2); // this will accept value from 0 to 99
Call ON_EN_UPDATE this function will call every time when edit Control value changes.
Inside this function you can get the value of edit control.
CString strTxt;
m_edit.GetWindowText(strTxt);
int nIndex = _ttoi(strTxt); // you will get integer value here.
Use this integer value to set the position of scroll bar.

Related

C++ Windows Owner Drawn Main Menu -- itemID

I am attempting to create an owner-drawn main menu, in Windows. I understand setting:
menuiteminfo.ftype = MFT_OWNERDRAW
I also know about handling the WM_MEASUREITEM and WM_DRAWITEM messages.
However, how do I know which main menu item is sending the message? (so that I can fill-in the appropriate box size and text) "itemID" seems to be the only unique identifier. But, how can I associate this pointer/handle to the item in question? I can use "lParam" to determine it is a menu item. But, I can't determine which menu item. "GetMenuItemID" is useless, as it returns "-1" for all main-menu items.
Or, am I going about this all-wrong? I have been searching for answers, for weeks. Really, all I want to do is change the text color of the main menu, from black, to white or light gray, so I can use a dark background.
The itemID field of the MEASUREITEMSTRUCT and DRAWITEMSTRUCT structs tells you exactly which menu item is being measured/drawn. This is the ID that you specify when you create/modify a menu item. That ID is specified via either:
the uIDNewItem parameter of AppendMenu(), InsertMenu(), or ModifyMenu().
the item parameter of InsertMenuItem() or SetMenuItemInfo()
the wID field of the MENUITEMINFO struct that you pass to InsertMenuItem() or SetMenuItemInfo().
Use whatever IDs you want, as long as they are unique for your menus.
You can also use the itemData field of MEASUREITEMSTRUCT and DRAWITEMSTRUCT to receive any custom data you want for owner-drawn menu items, if you so desire (like, for example, a pointer to a buffer that contains a menu item's text string). This custom value can be anything you want that is meaningful for you. You set this value in the dwItemData field of the MENUITEMINFO struct that you pass to InsertMenuItem() or SetMenuItemInfo().
This is all covered in the documentation:
Using Menus: Creating Owner Drawn Menu Items
Thank you Remy. Through the items that you mentioned, and researching the documentation for each, I was able to find a buried secret. For a Main Menu item, the "itemID" in both the MEASUREITEMSTRUCT and DRAWITEMSTRUCT is the handle to the drop-down menu of that item. From that, I added this line of code to WM_CREATE, to associate the itemID with the numerical (zero-based) position:
mItemID[i] = int(GetSubMenu(hMenu, i));
'i' is the numerical position, from left to right. I can then use a comparison statement like this, in WM_MEASUREITEM and WM_DRAWITEM:
lpmis=(LPMEASUREITEMSTRUCT)lParam; if(lpmis->itemID==mItemID[i])

Changing parameters based on qt combo box

I have a combo box called x_axis_unit in qt with two options; metres and ms. When I change the options, the combo box doesn't take note of the change and stays stuck on metres after I changed the option to ms once I exit the gui. I typed in
ui->plot_type->setCurrentIndex(1);
but that doesn't set it. So what argument is needed to set the current index to its current value? Also based on the current option I'd like to run a loop that changes another parameter. So if the current text in the combo box is metres then I set a variable called axis to 0 and if it is in ms then I set the variable to 1
// Combo box code
ui->setupUi(this);
ui->x_axis_unit->addItem("metres");
ui->x_axis_unit->addItem("ms");
So how can I set the combo box to ms, it is always on metres.
You could use an enum to store the index for the combo box.
If the enum has class scope you can then change the combo box from any function in the class with "comboBox.setCurrentIndex(enum entry)" like this:
enum comboBoxSelection
{
eMetres = 0,
eMS
};
x_axis_unit = new QComboBox(parent);
x_axis_unit->insertItem(eMetres, "Metres");
x_axis_unit->insertItem(eMS, "ms");
x_axis_unit->setCurrentIndex(eMS);

MFC Spin/Edit Control

I am using an Spin Control with an Edit Control buddy. I have an OnEnChanged event as below
void MyClass::OnEnChangeSnrEdit()
{
UpdateData(TRUE);
wizard_data->wlan.min_snr = m_snr_spin.GetPos();
CheckValid();
}
CheckValid enables the next button on my dialog page if the value is within the range I want it to be. The problem I have is that if I manually delete the value from the Edit Control so it is blank then GetPos above returns 0. 0 is within the range I allow and so my Next button is enabled and the value 0 is set when there is actually no value in the Edit Control.
How do I solve this issue?
Simply check the Contents of the edit Control first. Only if it is not empty, then get the spin button Control.
But why to relay on the value of the spin Control. always use the value from the edit Control!

CEdit control MFC, placing cursor to end of string after SetWindowText

I am using VC9, I've a CEdit control whose contents are reset to default test (say - "fill-in") at the click of a button and then I call SetFocus for the CEdit control. The problem is that the cursor blinks at the start of the default text, and i want it to blink an the end of the default string.
How can this be done?
You can use CEdit::SetSel to accomplish that.
Example:
CEdit* e = (CEdit*)GetDlgItem(IDC_EDIT1);
e->SetWindowText("hello world");
e->SetFocus();
e->SetSel(0,-1); // select all text and move cursor at the end
e->SetSel(-1); // remove selection
You can use CEdit::SetSel to accomplish that:
CEdit* e = (CEdit*)GetDlgItem(IDC_EDIT1);
e->SetWindowText("hello world");
// e->SetSel(0,-1); // you don't need this line
e->SetFocus();
e->SetSel(-1);
It will place the cursor in the end of the string.
I had a strange finding but still relevant to it.
This solution did not work for me initially. Even after calling SetSel(-1) my cursor was moving to the top of the edit box.
Then I did some code reshuffle and it started working.
The learning was that if I update any other control after updating the edit control, the cursor will move to the top of the edit box. But if edit box is the last control updated, the cursor remains in the end of the edit box.
Like I had a code something like
Add text to edit & call SetSel(-1)
update static control
And the cursor would not stay in the end. But when I changed it to
update static control
Add text to edit & call SetSel(-1)
My cursor was displayed in the end of the edit box.
I had it on my mind since the day I had this finding to update the knowledge base here. Hope it helps some random soul whose cursor jumps to top of edit box even after calling the API.

"Smart" Linked Scrollbar and Edit Controls?

I hope that I can explain my problem well enough for someone to help.
Basically, I have a horizontal scrollbar (ranged 0 to 1000) and an edit control that represents the position of the scrollbar divided by 1000, so that the user can use either the scrollbar to select a range of numbers between 0 and 1 up to a 3 decimal precision (.001, .002, ..., .987, etc.), or enter their own number in the edit box. As they scroll the scrollbar, the number in the edit control changes to reflect the new scroll position. When a new number is entered, the scrollbar sets itself to a new position reflecting the number entered. Meanwhile I also perform some calculations with this number as it changes (through either the scrollbar or the edit control) and display the results in another dialog.
Here is my problem: I'm having trouble deciding which event handlers to use to produce the proper behavior when a user enters a number into the edit control.
I'm using a double value variable called fuelMargin to handle my edit control and a CScrollBar control variable called fuelScroll to handle the scrollbar.
In my HSCROLL event I set the edit control to the scroll position / 1000. No problems there; when the user scrolls the scrollbar the edit box is correctly updated.
As for the edit box, my first attempt was an ONCHANGE event:
void MarginDlg::OnEnChangeFueledit()
{
CEdit* editBox;
editBox = (CEdit*)GetDlgItem(IDC_FUELEDIT);
CString editString;
editBox->GetWindowText(editString);
if (editString.Compare(".") != 0 && editString.Compare("0.") != 0
&& editString.Compare(".0") != 0 && editString.Compare("0.0") != 0
&& editString.Compare(".00") != 0 && editString.Compare("0.00") != 0)
{
UpdateData();
UpdateData(FALSE);
if (fuelMargin > 1)
{
UpdateData();
fuelMargin = 1;
UpdateData(FALSE);
}
if (fuelMargin < 0)
{
UpdateData();
fuelMargin = 0;
UpdateData(FALSE);
}
fuelScroll.SetScrollPos(int(fuelMargin*1000));
}
}
I needed that first if statement in there to keep from doing an UpdateData() when the user is trying to type a number like .5 or .05 or .005. It does produce a few wonky behaviors, though; when the user tries to type something like .56, after the .5 an UpdateData() is performed, the number becomes 0.5, and the cursor is moved to the far left, so if they tried to type .56 they would accidentally end up typing 60.5 -- which goes to 1, since I won't let them enter numbers lower than 0 or higher than 1. If they enter 0.56, however, this behavior is avoided.
For my second attempt, I commented out my ONCHANGE event and put in an ONKILLFOCUS event instead:
void MarginDlg::OnEnKillfocusFueledit()
{
UpdateData();
UpdateData(FALSE);
if (fuelMargin > 1)
{
UpdateData();
fuelMargin = 1;
UpdateData(FALSE);
}
if (fuelMargin < 0)
{
UpdateData();
fuelMargin = 0;
UpdateData(FALSE);
}
fuelScroll.SetScrollPos(int(fuelMargin*1000));
}
So now the user can finish typing their number and all is hunky dory--as long as they click out of the edit box. The scrollbar won't move and results won't be calculated until the box loses focus.
I want the results to be calculated as the numbers in the box are being typed; I want the scrollbar to move as the numbers are being typed. But I don't want typing to be disrupted, i.e. the actual numbers in the box changed or the cursor moved in any way.
Suggestions?
Thanks!
With the first approach, it looks like you're almost there: the only really significant problem is that the repeated calls to UpdateData() mess with the cursor position as the user is typing.
Given that you're trying to have a reasonably complex interaction between the controls, what I'd suggest is not to do validation in the OnChange() at all, so that as the user is typing he can type what he wants (which is how most numeric edit controls work anyway). When the user closes the dialog the controls are on (or clicks a button that uses the data in some way) then validation should be triggered, and a suitable error shown.
Once you're free from validating in OnChange(), you can fix the "cursor moves" problem by simply not calling UpdateData() in OnChange(). Instead, just parse the number from "editString" and, if it's in the valid range, update the scrollbar. That way, the scrollbar updates as the user types, and if they type in an invalid value the scrollbar stays put, and they'll get an error when they move to whatever the next stage is. Something like this (not tested):
void MarginDlg::OnEnChangeFueledit()
{
CString editString;
GetDlgItem(IDC_FUELEDIT)->GetWindowText(editString);
double editValue;
if ((sscanf(editString,"%lf",&editValue) == 1)
{
if (editValue >= 0.0) && (editValue <= 1.0))
fuelScroll.SetScrollPos(int(editValue*1000));
}
}
The only remaining important problem to note is that, if the user types some invalid value, or a number out of the valid range, then the edit control and the scrollbar will be out of sync. The simplest way to deal with that is to just decide that the edit control is the "master" value: that is, when we want to know what the user entered, we always look at the edit control, not the scrollbar, and validate data.
As for your second approach, one possible solution might be to implement a timer message handler: in the timer handler you could say the equivalent of "if the user hasn't typed anything for a second, I'll assume they're done, and parse the number and update the scrollbar". I'm not so keen on that as a solution, though.
I'd suggest watching for the Enter key, and performing UpdateData() then as well as OnKillFocus and OnChange. The more user-friendly the better.
Next, make sure your UpdateData() routine only works in the direction you need:
If ".5" is entered in the edit control, run your UpdateData() routine when the OnChange event is raised, but make sure to update your scrollbar only. Don't worry about updating the edit control to "0.5" until OnKillFocus is raised. Any updates in the reverse direction (to the edit control) will mess with your cursor. If your edit control is somehow bound to this double variable and auto updates when the var changes, consider leaving the double and your edit control seperate from each other until the OnKillFocus event is raised.
The same concept applies in the other direction as well. When the user scrolls, don't mess with the scrollbar. Just update the edit control and leave it at that.
I should add that XAML's data-binding features really help in situations like this, if you know how to use them properly. It's unfortunate for us native-type developers that it's so difficult to implement similar functionality using only event handlers.