1-indexed Model in QCombobox - c++

I have a 1-indexed (readonly-)model and want to use it for a combobox.
I parse the data (comes from a file-parser) and have for example:
1: Variable Number 1 and that will be my first item, next
2: Variable Number 2 and so on.
When I click on an item the currentIndex()-method from QCombobox will give me a 0-indexed int, so my problem is:
I don't want to write everytime I parse a file +1 respectively -1 when writing back to the file (although the model is readonly, I can alter the data in the file). (I have nearly 30 UIs where I need the model, and for every UI I have to parse other data)
I currently use something like:
virtual int currentIndex() const { return QComboBox::currentIndex() + 1; }
virtual void setCurrentIndex(int index) { QComboBox::setCurrentIndex(index-1); }
I know that this is not ideal, because (set-)currentIndex is not virtual. But to avoid +/-1 I used this for now.
Does anybode have a good suggestion for this problem?

If you have a custom model you could add a role that returns the "real" index value.
If you just use strings to fill the combobox, you could use the setItemData() and itemData() methods to associated your reference value.
E.g.
comboBox->addItem("Number 1", 1);
and
int refValue = comboBox->itemData(comboIndex).toInt();
The associated data can be anything that can be stored in a QVariant.

Related

using one Qcombobox to set value to several labels, C++

im trying to set the value from a combobox to multiple Qlabels, the idea is to populate the QcomboBox with all the values, then according to the number, (ejem 15.6) the corresponding label should change the problem is, theres too many of them to simply use a switch of something similar, but all the names of the labels are similar, HumSec_val156 corresponds to 15.6 the main idea was to use
Silo* silo = new Silo;
QString number = widget.QComboBox->currentText();
QString nameOfLabel = "HumSec_val";
nameOfLabel.append(QString::number(number));
silo->findchild<QLabel*>(nameOfLabel)->setText(valuefromCombobox);
but everytime it simply return an empty string, i did try using somthing simplier like
widget.nameOfLabel->setText(valuefromComboBox);
but nameOfLabel its just a qstring so i can mix it with the code generated from designer. Any idea what can i do? do i need to create something like a scoped enum or similar?
below i add a picture of what im doing
If I would do something like this, I would probably create a QHash<QString, QLabel*> and use that as a cache to find the matching QLabel for each name.
Declaration:
QHash<QString, QLabel*> m_hash
Storing value:
m_hash[labelName] = labelPtr;
Reading value:
QLabel* labelPtr = m_hash.value(labelName, nullptr);
if (labelPtr)
{
// Access label
}
When you remove a label remember to remove it from the hash as well:
const QString key = m_hash.key(labelPtr);
m_hash.remove(key);

Add empty option to List Validator

I'm trying to add the option to my users that, on a List Validator, to allow select any of the options or a blank option. Spreadjs has the IgnoreBlanks setting, which I use, so when the user uses the delete key or the backspace and deletes the cell it validates correctly.
However, I would love to use the same functionality as in Excel, which allows blank options in the list validator, in part of the list.
I've tried to target the <select> element that holds the list and programmatically add the empty element, however, it crashes after the user selects the empty option.
I've also tried to add different escaped characters to the list. If I select a character that represents an empty string or a tab, it won't add a new option to the list. If I use any strange character, or even the null character \0 you get a new option to select, but the content is that typical rectangle you see when your font doesn't have the character you're trying to display.
I've also tested using a regular ListValidator like in the example pages, not our custom functionality and doesn't work either.
https://www.grapecity.com/demos/spread/JS/TutorialSample/#/demos/basicDataValidator
I have also tried creating a FormulaListValidator, and if my range has empty cells I could then get an empty option on my list, however, because the range may have duplicates, I get duplicated options.
After researching a little bit I found a workaround in a different language which I adapted to Typescript (Angular 6)
export const getListValidatorFromArray = (spread: GC.Spread.Sheets.Workbook, data: any[]) => {
// saving validation list values in a hidden sheet
spread.addSheet(spread.getSheetCount());
const sheet = spread.getSheet(spread.getSheetCount() - 1);
sheet.visible(false);
for (let i = 0; i < data.length; i++) {
sheet.setValue(i, 0, data[i]);
}
// create validator based on the values
const dv = GC.Spread.Sheets.DataValidation.createFormulaListValidator(
'=' + sheet.name() + '!$A$1:' + sheet.name() + '!$A$' + data.length
);
return dv;
};
Note: This creates an extra sheet for each validator you create. Makes sure you reuse them as much as possible (i.e. assigning it to a variable when it's created, and reusing the variable for other columns/rows that use the same one).

COM IContextMenu::InvokeCommand - matching LPCMINVOKECOMMANDINFO::lpVerb to item

I have created a shell extension for windows with COM, however I seem to fail to properly match the ids of items I add in the overload of IContextMenu::QueryContextMenu with what I receive in the overload of IContextMenu::InvokeCommand. In my code I use InsertMenu and InsertMenuItem (as far as I understood they do the same, but the latter has some more features?). However I'm not sure which arguments passed to InsertMenu/InsertMenuItem correspond to what I must be looking for in LPCMINVOKECOMMANDINFO::lpVerb. I need some way to easily know that when I add items x, y, z to a context menu, I can then know exactly which one of x, y or z has been clicked.
EDIT: It seems that the verb equals the number from top to bottom of the item in the current menu/submenu. However I have two sub-menus each with x amount of items, so they have the same IDs of 1,2,3. How do I set custom IDs or something?
Firstly you should define an enum that holds the command IDs for your menu items, e.g.
enum {
CMDID_FIRST = 0,
CMDID_DOSOMETHING = CMDID_FIRST,
CMDID_DOSOMETHINGELSE,
CMDID_LAST,
};
These ID values need to start from 0.
In your IContextMenu::QueryContextMenu implementation:
when you add your menu items you need to give each of them an ID by setting the MIIM_ID flag in the MENUITEMINFO.fMask field, and setting the MENUITEMINFO.wID value.
give each of your menu items an ID derived from its command ID as defined above, plus the value of idCmdFirst which is passed into QueryContextMenu. E.g. the "Do Something" menu item would have MENUITEMINFO.wID set to idCmdFirst + CMDID_DOSOMETHING, and "Do Something Else" would have MENUITEMINFO.wID set to idCmdFirst + CMDID_DOSOMETHINGELSE.
the return value from QueryContextMenu needs to be MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, x) where x is the ID of the highest-numbered item you added plus 1 (alternatively, if all items were sequentially numbered, the total number of items). Basically, you're telling the host which menu item ID values are now in use so that no other context menu extensions add items that clash with yours. In the above example, you'd return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, CMDID_LAST).
In IContextMenu::InvokeCommand:
test if lpVerb (or lpVerbW) is an integer value using the IS_INTRESOURCE macro.
if so, the command ID can be found in the low word. E.g, if the user selected "Do Something Else", you would find that LOWORD(lpVerb) == CMDID_DOSOMETHINGELSE.

How to use QlineEdit to enter integer values

I am trying to use QlineEdit.
How would I enter a value into the edit bar when I run the program and get that valued stored as a variable to be used later. So far I have only found out how to enter text using
void parameter_settings::on_lineEdit_textEdited(const QString &arg1)
{
ui->lineEdit->setText("");
}
I have a GUI that requires the user to enter a value within a specific range. That value would be stored as a variable for later use. I have read about validators but can't get it to work as intended.
I am not entirely sure what your question is, but you can get the input from a QLineEdit with the command text():
QString input = ui->lineEdit->text();
and an integer input by using:
int integer_value = ui->lineEdit->text().toInt();
As you mentioned validators: You can use validators to allow the user to insert only integers into the QLineEdit in the first place. There are different ones but I generally like to use 'RegEx' validators. In this case:
QRegExpValidator* rxv = new QRegExpValidator(QRegExp("\\d*"), this); // only pos
QRegExpValidator* rxv = new QRegExpValidator(QRegExp("[+-]?\\d*"), this); // pos and neg
ui->lineEdit->setValidator(rxv);
Note: As mentioned in the comments by Pratham, if you only require integers to be entered you should probably use a QSpinBox which does all this out-of-the-box and comes with extra handles to easily increase and decrease of the value.
Use this method:
QString str = QString::number(4.4);
ui->lineEdit->setText(str);

How do I access a member tab of a QTabWidget class by using a variable name?

In a function I am currently working on, I am creating a multi-dimensional array of checkboxes, with the dimensions specified at run-time by the user. In order to represent the 'z' dimension, I create multiple tabs -- each one representing a different dimension -- and create an array of check boxes in each tab. The tabs are labeled dim1, dim2, dim3, ... etc.
The problem I am having is the fact that in order to create the array of check boxes (within 3 'for' loops), I have to call the tabs as follows:
checkBoxVector.append(new QCheckBox( ui->dim1 ));
Where checkBoxVector holds pointers to the checkboxes. Now my first thought was that I would simply create a variable name that would change with each loop. With each iteration, it would go: "dim1", then "dim2", "dim3", ... etc. The problem with this is that I cannot reference the tabs with a string variable, I must type in the actual name of the tab. Here is a sample of that code:
int num = k+1;
QString dim = "dim";
QString tab_name = dim.append(QString("%1").arg(num));
checkBoxVector.append(new QCheckBox( ui->tab_name ));
This gives me the error " 'class Ui::MainWindow' has no member named 'tab_name' ".
Therefore; my question is: how can I apply this idea of changing the NAME of the tab with each loop, without causing such an error?
EDIT: I think I forgot to mention that the tabs have already been created at this point, and have already been labeled with the "dim1", "dim2", "dim3", ... names. The only issue I am having is how to reference these tabs after they have been created. I feel like there is a simple syntax solution.
Store the pointers to tabs in an array and index it with the variable that you use for iterating over the third dimension of your multidimensional array of checkboxes, your code would look something like this:
QTabWidget* tabs[3];
tabs[0] = ui->dim1;
tabs[1] = ui->dim2;
tabs[2] = ui->dim3;
// ... and then
checkBoxVector.append(new QCheckBox( tabs[z] ));
Someone will say it better (there is a concept name for that) but you can't dynamically declare members in c++ ... if you want QString tab_name content to be in any way related to a member of ui in this part of code:
QString tab_name = dim.append(QString("%1").arg(num));
checkBoxVector.append(new QCheckBox( ui->tab_name ));
The compiler need to know at compile time witch member of ui it will use to find the parent of the the new QCheckBox.
Correct me if I am wrong, you have dimz tabs and dimy*dimx QcheckBox in each tabs. You don't know any dim* when you build you ui file ?
So create your own widget (QWidget) it will store an array of QcheckBox* that you can dynamically create in constructor for example. This widget will take care of the proper layout of the check boxes.
Then finally you create you own QTabWidget that will create dimz tabs of your widget. You will access your tabs with their indexes corresponding to their z coordinate.
You're trying to reference a member variable that does not exist:
int num = k+1;
QString dim = "dim";
QString tab_name = dim.append(QString("%1").arg(num));
checkBoxVector.append(new QCheckBox( ui->tab_name ));
The error is caused by the fact that you are passing a non-existing member variable to the constructor of QCheckBox. The object the ui pointer is pointing to has no member variable named tab_name. If I understood your description correctly, just pass the local variable tab_name to the QCheckBox constructor like this:
checkBoxVector.append(new QCheckBox( tab_name ));