Code generated checkboxes in QT-Creator crashes program - c++

I have a function who's job is to generate a list of checkboxes based upon the contents of an enum.
void Controller::createCheckBoxes()
{
const QMetaObject &mo = LicenseManager::staticMetaObject;
int index = mo.indexOfEnumerator("Packages");
QMetaEnum metaPackeges = mo.enumerator(index);
for (int i=0; i != metaPackeges.keyCount(); ++i)
{
QString name = (metaPackeges.key(i));
if(!packageCheckBoxes.contains(name))
{
QCheckBox* box = new QCheckBox;
ui->layoutCheckBoxes->addRow(box);
box->setText(name); box->setCheckable(true);
packageCheckBoxes.insert(name, box);
}
}
}
Where "Packages" is the enum containing the packages, and "packageCheckBoxes" is the QMap that is holding the checkboxes for other functions to operate on them, and "layoutCheckBoxes" is a Qt form layout that the checkboxes visually reside in.
Now, the checkboxes appear on screen looking correct, exactly how I intend them too, and inside the layout. However, clicking on them, or asking the code to do anything to them, instantly results in a crash and I can't figure out why. There's no explanation given by "Application Output" other than "The program has finished unexpectedly." which amazingly I figured out on my own without this notice /s
I had checkboxes in "layoutCheckBoxes" before, but they were manually generated from Design, and those worked perfectly. The reason I'm going through this hassle is to allow packages to be easily added through the enum, with various functions performing the operations necessary to generate the required checkboxes and hook them up to their appropriate functions.
The function that calls "createCheckboxes" is in the same source file, as well as the other functions that operate on the check boxes.
I don't have control over the enum, it is what it is, and it's what I need to work with.

Related

std::vector becomes invalid after calling size() on it inside filterAcceptsRow

I am using a selfmade QSortFilterProxyModel to do the filtering and sorting of a model in my application.
Here is the filterAcceptsRow function:
//---------------------------------------------------------------------------------
bool
SkillSortFilterProxyModel::filterAcceptsRow(int p_row, const QModelIndex& p_parent) const
{
QModelIndex currentIndex = sourceModel()->index(p_row, 0, p_parent);
SkillModelItem* currentItem = (SkillModelItem*)currentIndex.internalPointer();
// Check the item
bool accept = filterAcceptsItem(currentItem);
// We may hide a category if it is empty
if (accept && currentItem->isCategory && !_showEmptyCategories)
{
// Iterate over the children to find out if any will be accepted
// And if so, accept the category
int numChildren = currentItem->children.size();
accept = false;
for (int i = 0; i < numChildren; ++i)
{
SkillModelItem* item = currentItem->children[i];
if (filterAcceptsItem(item))
{
accept = true;
break;
}
}
}
// Return result
return accept;
}
Here is what it is supposed to do: I think the exact nature of the SkillModelItem is not important here, but you should understand that the same model item class is used for skill categories and skills themselves. The filterAcceptsRow function calls filterAcceptsItem to see if the particular item should be shown or not. That works well.
However, if the item is a category, its children should also be checked to see if it has any accepted children, and if so, the category should be shown.
Should work in theory, but what happens in practice is that after currentItem->children.size() is called, the currentItem->children (which is a std::vector) becomes invalid! It returns the correct size, but if I call it again, the size is now some random number. And accessing the child items in the for loop after crashes the application.
I have no idea what is going on here. The application is not threaded (at least I do not use any threads). I am using Qt Creator on Windows, using MinGW as the compiler. I also tried using MSVC but that will not even compile as it claims it cannot find any header files (which MinGW can find without problems). Also tried recompiling, re-running qmake, etc. All to no avail.
Any ideas what could be the problem here?
If it helps, you can look at the sources here: GitHub repo
Turns out this is a debugger problem.
If I do not step through at runtime, the function works just fine.
Seems like there is a bug in either Qt Creator or the MinGW version coming with it.

Qt User customizable hotkeys

I'm trying to design a Qt GUI application with user customize-able hotkeys. The main issue I'm running into is how to synchronize the hotkeys across the application since a particular hotkey (for example, copy) may be used by multiple widgets/components.
My current strategy is to use a reference class which holds a list of QKeySequence objects for each different hotkey. Each widget would have to have a way to reference this master list and have custom implementations of low-level the keyPressEvent which would compare inputted keys vs. the hotkeys. I don't particularly like this strategy, though, as it requires significant re-implimentation in each widget and feels like I'm trying to re-invent the wheel.
I also tried using QAction objects which can hold QKeySequence shortcuts internally, then use these to trigger higher-level events which I can handle using slots & signals. However, the main issue I have here is how to manage which slots signals get routed to.
For example, say I have 2 open widgets which can both receive a copy action signal. I can connect a slot for both of these to the same signal and take advantage of the single update point for shortcuts, but then things get messy since only the active widget should act on the copy signal, not both widgets. I can re-implement the focusOutEvent and focusInEvent handlers to connect/disconnect slots manually, but this also seems to run into the same issue above where I'm trying to re-invent the wheel and doing more work than is necessary.
Is there an easier way around this problem?
I don't think there is a particularly easy/non-tedious solution to this problem, but when I needed to add user-customizable hotkeys to my application, here is how I did it:
1) Start with your application that has hard-coded key shortcuts, e.g. code like this:
QMenu * editMenu = new QMenu;
QAction * copyItem = menu->addAction(tr("Copy"), this, SLOT(CopyData()));
copyItem->setShortcut(tr("Ctrl+C"));
2) Create a GetKeySequence() function that looks something like this:
static QHash<QString, QKeySequence> _usersKeyPreferences;
static bool _usersKeyPreferencesLoaded = false;
QKeySequence GetKeySequence(const QString & keySequence, const QString & contextStr)
{
if (_usersKeyPreferencesLoaded == false)
{
// Oops, time to load in the user's saved custom-key settings from a file somewhere
_usersKeyPreferences = LoadUsersKeyPreferencesFromFile();
_usersKeyPreferencesLoaded = true; // so we'll only try to load the file once
}
if (_usersKeyPreferences.contains(contextStr))
{
return _usersKeyPreferences[contextStr];
}
else
{
// No user preference specified? Okay, fall back to using the
// hard-coded default key sequence instead.
return QKeySequence(qApp->translate(contextStr, keySequence));
}
}
3) Now the tedious part: grovel over all of your code, and anywhere you've specified a key-sequence explicitly (like in the third line of the code shown for step 1), wrap it with a call to GetKeySequence(), like this:
copyItem->setShortcut(GetKeySequence(tr("Ctrl+C"), tr("Edit_Menu|Copy")));
4) At this point, your program's key-sequences will be customizable; just make sure that the key-settings-file is present on disk before GUI-creation code runs. Here's an excerpt from my program's key-mappings file (which I store as a simple ASCII text file):
Edit_Menu|Copy = Ctrl+C
Edit_Menu|Cut = Ctrl+X
Edit_Menu|Paste = Ctrl+V
[... and so on for all other menu items, etc...]
... of course one downside to this approach is that once the GUI is created, the key-bindings can't be modified "on the fly" (at least, not without a lot of additional coding). My program gets around this simply by closing and then re-creating all windows after the user clicks "Save and Apply" in the Edit Key Bindings dialog.
5) An optional further step (which is some extra work up front but saves time in the long run) is to write a program (or script) that greps all the .cpp files in your program's codebase looking for calls GetKeySequence() in the code. When it finds a GetKeySequence() call, it parses out the two arguments to the call and prints them as a line in a key-bindings file with the default settings. This is useful because you can make this script part of your autobuild, and thereafter you'll never have to remember to manually update the default key-settings-file whenever you add a new menu item (or other key-sequence specifier) to your program.
This worked well for me, anyway. The advantage is that you don't have to refactor your existing program at all; you can just go through it inserting GetKeySequence() as necessary while leaving the larger logic/structure of the program intact.

QTreeWidget Passing multiple Items (more then one selection) through a function

I am a student programmer using Qt to build a GUI for work. I have ran into an issue; more or less and inconvience of sorts wiith multiple selections in the QTreeWidget. My GUI has a main interface with a QTreeWidget as the central item in this window. Below the QTreeWidget I have several buttons; copy, edit, and delete. As you might've already guessed each one of these buttons correlates to a function that executes the command. My tree widget has the ability to select multiple items; however, when multiple items are selected the only item that is passed through is the last item that was selected. I was hoping that somebody with some more insight in this IDE might be able to point me in the right direction for accomplishing this. Here is the process that is followed when one of these functions is executed.
void InjectionGUI::copyInjection_Clicked(QTreeWidgetItem *itemToCopy)
{
InjectionData copyInjectionData; //first use data from the tree widget row
QString converter = itemToCopy->text(0); //to find the vector item that will be copied
int id = converter.toInt();
int nameNumber;
copyInjectionData = qTreeInjectionData.at(id);
qTreeInjectionData.append(copyInjectionData);
buildTreeWidget();
}
void InjectionGUI::slotInjectionCopy()
{
if(ui->treeWidgetInjections->currentItem() == 0)
{
QMessageBox invalidSelection;
invalidSelection.setText("No row selected to copy");
invalidSelection.setWindowTitle("Error");
invalidSelection.exec();
}
else
{
copyInjection_Clicked(ui->treeWidgetInjections->currentItem());
}
}
I'm not too sure what code will be relevant towards making this change; so if there is additional structure that anyone would like to see please just requested. I'm pretty sure that my problem or my solution is going to lie in the way that I'm using current item. After reviewing the documentation from Qt's website I'm still unsure how I would change this to allow multiple selections to be passed through the function. Please only provide constructive feedback; I'm only interested in learning and accomplishing a solution. Thanks in advance.
UPDATE! SOLVED!!!
Just thought it might be nice to show what this looked like implemented:
QList<QTreeWidgetItem *> items = ui->treeWidgetInjections->selectedItems();
for(int i = 0; i < items.size(); i++)
{
QTreeWidgetItem *qTreeWidgetitem = new QTreeWidgetItem;
qTreeWidgetitem = items.at(i);
copyInjection_Clicked(qTreeWidgetitem);
}
If you need to know which items are selected, you can use
QList<QTreeWidgetItem *> QTreeWidget::selectedItems() const
to have a list of all the currently selected items in the tree.
Then you may call your function once for every item in the list, or you can overload your function to take as argument a QList<QTreeWidgetItem *> and then run through the list inside the called function.

Using the GroupBoxes in Qt

I'm a student programmer and I am using Qt to build a GUI application. I'm trying to ensure that some check boxes are checked in order to proceed. These check boxes enable or disable the group box itself and are part of the QGroupBox class. Accepted combinations could be either or both. The problem I am running into is getting the boolean value(at least that's what I think it is) from the QGroupBox member function QGroupBox::setChecked(bool) and use it to determine whether or not to display an error message. I have tried several methods and reference Qts documentation hoping for a good example. Because the QGroupBox I'm trying to use is a member of my ui class I tried creating a new instance of QGroupBox and setting it to the values of the ui. Then; using an if statement, find out whether or not the boxes are check or not. Here's my code for this:
QGroupBox activeParticleInjection = ui->groupBoxParticleInjection;
QGroupBox activeFluidInjection = ui->groupBoxFluidInjection;
if (activeParticleInjection::setChecked(false) && activeFluidInjection(false));
{
QMessageBox noInjectionSelectedError;
noInjectionSelectedError.setText("Error: No injection type selected");
noInjectionSelectedError.exec();
}
else
{
transData.particleInjectionActive = activeParticleInjection::setChecked();
transData.fluidInjectionActive = activeFluidInjection::setChecked();
This doesn't work; starting with the way I'm trying to pass the Ui properties to the new instance of QGroupBox. I know that is question is relatively generic question but I tried passing the ui checkbox directly and that caused even more issues. I looked through the documentation and that led me to the way im trying to do it know; with no luck. I was hoping for some feedback on a better method of handling QGroupBox. Being a student sometimes its hard to see the answer especially when dealing with such unique members as the ones put together in QT.
Prior to changes I was using this method to build this process; and I received errors for the way my if parameters were setup. Compile error was : no matching function for call to 'QGroupBox::isChecked(bool)'
if (ui->groupBoxFluidInjection->isChecked(false) && ui->groupBoxParticleInjection->isChecked(false));
{
QMessageBox noInjectionSelectedError;
noInjectionSelectedError.setText("Error: No injection type selected");
noInjectionSelectedError.exec();
}
else
{
transData.particleInjectionActive = ui->groupBoxParticleInjection->isChecked();
transData.fluidInjectionActive = ui->groupBoxFluidInjection->isChecked();
}
I have been using these sites for most help:
QGroupBox
QCheckBox
You're mixing several things:
The QGroupBox instances in ui are pointers, so you must assign them to a QGroupBox* (pointer), not a QGroupBox (object on the stack).
:: is used with methods only if the method you call is static (class method), which is not the case here.
setChecked() is a setter setting the checked state of the group box. It doesn't return anything (void), so you cannot use them as conditions. What you want there is the getter bool QGroupBox::isChecked().
Your code snippet cleansed:
QGroupBox* activeParticleInjection = ui->groupBoxParticleInjection;
QGroupBox* activeFluidInjection = ui->groupBoxFluidInjection;
if (!activeParticleInjection->isChecked() && !activeFluidInjection->isChecked())
{
QMessageBox::critical(this, tr("Error"), tr("No injection type selected"));
}
else
{
transData.particleInjectionActive = activeParticleInjection->isChecked();
transData.fluidInjectionActive = activeFluidInjection->isChecked();
}
Not really sure what you tried to do in your code, but that's actually a lot easier to achieve. Also don't try to create copies (which you do in your example). Work with references or pointers in that case!
QGroupBox group("my group box"); // of course this might be a class member, too
group.setCheckable(true);
// do other things...
if(group.isChecked())
{
// do whatever if it's checked
}
else
{
// do stuff if it isn't checked
}
To check for at least one of multiple groups (or check boxes) being checked:
if(group1.isChecked() || group2.isChecked())

Using images in QListWidget, is this possible?

I am using QT to create a chat messenger client. To display the list of online users, I'm using a QListWidget, as created like this:
listWidget = new QListWidget(horizontalLayoutWidget);
listWidget->setObjectName("userList");
QSizePolicy sizePolicy1(QSizePolicy::Preferred, QSizePolicy::Expanding);
sizePolicy1.setHorizontalStretch(0);
sizePolicy1.setVerticalStretch(0);
sizePolicy1.setHeightForWidth(listWidget->sizePolicy().hasHeightForWidth());
listWidget->setSizePolicy(sizePolicy1);
listWidget->setMinimumSize(QSize(30, 0));
listWidget->setMaximumSize(QSize(150, 16777215));
listWidget->setBaseSize(QSize(100, 0));
listWidget->setContextMenuPolicy(Qt::CustomContextMenu);
Users are shown by constantly refreshing the list, like this: (Note: There are different channels, with different userlists, so refreshing it is the most efficient thing to do, as far as I know.)
void FMessenger::refreshUserlist()
{
if (currentPanel == 0)
return;
listWidget = this->findChild<QListWidget *>(QString("userList"));
listWidget->clear();
QList<FCharacter*> charList = currentPanel->charList();
QListWidgetItem* charitem = 0;
FCharacter* character;
foreach(character, charList)
{
charitem = new QListWidgetItem(character->name());
// charitem->setIcon(QIcon(":/Images/status.png"));
listWidget->addItem(charitem);
}
}
This has always worked perfectly. The line that I commented out is the one I have problems with: my current goal is to be able to display a user's online status with an image, which represents whether they are busy, away, available, etc. Using setIcon() does absolutely nothing though, apparently; the items still show up as they used to, without icons.
I'm aware that this is probably not the way this function needs to be used, but I have found little documentation about it online, and absolutely no useful examples of implementations. My question is, can anybody help me with fixing this problem?
This is how you may conduct your debugging:
Try the constructor that has both icon and text as arguments.
Try to use that icon in another context to ensure it is displayable (construct a QIcon with same argument and use it elsewhere, e.g. QLabel!).
Use icon() from the QListWidgetItem to receive back the icon and then look at that QIcon.
Create a new QListWidget, change nothing, and ordinarily add some stock items in your MainWidget's constructor. See if the icons show up there.