Qt - Edit just QGraphicsLineItems within a QGraphicsScene - c++

I am using Qt to draw out some data visualisations. I have lines which indicate certain important points along a timeline, but I would like to be able to remove these lines from view so that the information underneath is more clearly visible.
I understand how to remove them from sight, but the problem is how to find which QGraphicsItems in the scene's view are Lines and which are not.
I have tried using
try {
qgraphicsitem_cast<QGraphicsLineItem>(scene->items()[i]);
} catch (...) {
}
But this doesn't even compile. I tried checking the output of qgraphicsitem_cast() to see if was 0, but the compiler didn't like that, either.
This is my most current code:
void Plotter::showHideLines() {
int i;
QGraphicsLineItem l;
for (i = 0; i < scene->items().count(); i++) {
try {
qgraphicsitem_cast<QGraphicsLineItem>(scene->items()[i]);
scene->items()[i]->setVisible(!scene->items()[i]->isVisible());
} catch (...) {
}
}
}
Ignore l, I didn't bother to delete it after trying something else.
I am pretty new to Qt, I have just been learning it over the last few days. Can anybody help?

I wouldn't advise iterating through every scene item, just to hide a certain type as things will get slow when the number of items gets large.
Instead, whenever a line is created, add it to a list. When they need to be hidden, iterate through list and hide them. It takes slightly more memory, but is much faster, safer, and requires less coding.

Related

QT Exception treatment

I've been trying to make a list in Qt that adds and removes integers for my Data Structures class, the teacher asked for a GUI, but I've been struggling a bit with the exception. I have managed to show the error when the list is empty, but the program closes after that, I wanted it to keep running after the warning popup window, but i have no idea how to proceed. I'm using try and catch to do that. Here is one of my remove buttons, this one removes the first int of the list.
void MainWindow::on_removerInicio_clicked()
{
try
{
throw ListaSeq.isEmpty();
}
catch(...)
{
QMessageBox::warning(this,tr("Aviso!"),tr("Lista Vazia!"));
}
ui->listWidget->takeItem(0);
ListaSeq.removeFirst();
nElementos--;
ui->nElementos->setText(QString::number(nElementos));
}
I know it's wrong but I don't know how to fix it, when clicked it shows the warning, but also closes the program. Can you help me?
Edit: Also if i take out the code
ui->listWidget->takeItem(0);
ListaSeq.removeFirst();
nElementos--;
ui->nElementos->setText(QString::number(nElementos));
The programs works fine and return to the mainwindow.

Weird bug in Qt application

In my application, I have my re-implemented QGraphicsView checking for a mouseReleaseEvent(), and then telling the item at the position the mouse is at to handle the event.
The QGraphicsItem for my view is made up of two other QGraphicsItems, and I check which one of the two is being clicked on (or rather having the button released on), and handle the respective events.
In my Widget's constructor, I set one of the items as selected by default, using the same methods I used when the items detect a release.
When I debugged, I found that for the LabelItem, select is called without a problem from the constructor (and the result is clear when I first start the application). But, when I click on the items, the application terminates. I saw that I was getting into the select function, but not leaving it. So the problem is here.
Which is very weird, because the select function is just a single line setter.
void LabelItem::select()
{
selected = true;
}
This is the mouseReleaseEvent;
void LayerView::mouseReleaseEvent(QMouseEvent *event)
{
LayerItem *l;
if(event->button() == Qt::LeftButton)
{
l = (LayerItem *) itemAt(event->pos());
if(l->inLabel(event->pos()))
{ //No problem upto this point, if label is clicked on
l->setSelection(true); //in setSelection, I call select() or unselect() of LabelItem,
//which is a child of LayerItem, and the problem is there.
//In the constructor for my main widget, I use setSelection
//for the bottom most LayerItem, and have no issues.
emit selected(l->getId());
}
else if(l->inCheckBox(event->pos()))
{
bool t = l->toggleCheckState();
emit toggled(l->getId(), t);
}
}
}
When I commented the line out in the function, I had no errors. I have not debugged for the other QGraphicsItem, CheckBoxItem, but the application terminates for its events as well. I think the problem might be related, so I'm concentrating on select, for now.
I have absolutely no clue as to what could have caused this and why this is happening. From my past experience, I'm pretty sure it's something simple which I'm stupidly not thinking of, but I can't figure out what.
Help would really be appreciated.
If the LabelItem is on top of the LayerItem, itemAt will most likely return the LabelItem because it is the topmost item under the mouse. Unless the LabelItem is set to not accept any mouse button with l->setAcceptedMouseButtons(0).
Try to use qgraphicsitem_cast to test the type of the item. Each derived class must redefine QGraphicsItem::type() to return a distinct value for the cast function to be able to identify the type.
You also could handle the clicks in the items themselves by redefining their QGraphicsItem::mouseReleaseEvent() method, it would remove the need for the evil cast, but you have to remove the function LayerView::mouseReleaseEvent() or at least recall the base class implementation, QGraphicsView::mouseReleaseEvent(), to allow the item(s) to receive the event.
I have seen these odd behaviours: It was mostly binary incompatibility - the c++ side looks correct, and the crash just does not make sense. As you stated: In your code the "selected" variable cannot be the cause. Do you might have changed the declaration and forgot the recompile all linked objects. Just clean and recompile all object files. Worked for me in 99% of the cases.

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.

how can iterate foreach item in QListWidget

i just can find any example in the internet how to loop and get each item in the QListWidget
int count = listWidget->count();
for(int index = 0;
index < count;
index++)
{
QListWidgetItem * item = listWidget->item(index);
// A wild item has appeared
}
The foreach thing is totally different, I think.
If you want more info on that, look at this
http://doc.qt.digia.com/4.2/containers.html#the-foreach-keyword
scroll down to where it talks about the foreach keyword.
Special thanks to Tomalak Geret'kal for adding the proper characters which my keyboard is unable to produce :)
Due to so many upvotes on this, i'll explain the foreach macro here as well.
foreach is a Qt specific C++ addition, implemented using the preprocessor. If you want to disable the thing, just add CONFIG += no_keywords to your XX.pro file.
Qt makes a copy of the list being iterated, but don't worry about performance. Qt containers use implicit sharing, where the actual contents are not copied. Think of it as two reference variables using the same actual variable. This makes it possible to modify the list you are iterating over, without messing up the loop. Note that modifying the list forces Qt to make a copy of the actual contents of the list the first time it's modified.
foreach can be used to loop over all Qt basic containers, QList QVector QMap QMultiMap and so on. QListWidget is not one of these, so it doesn't work on it, sadly. To make matters worse, QListWidget doesn't provide a list of all items, only the ones selected. There is a method called items, which would seem to be nice, but is protected.
To loop over selected items, I think this would work
foreach(QListWidgetItem * item, listWidget->selectedItems())
{
// A wild item has appeared
}
The first Google result for "QWidgetList" told me how to do it.
You can use a QWidgetListIt iterator.
QWidgetList wl = get_some_widget_list();
for (QWidget* w = wl.first(); w != 0; w = wl.next()) {
// use w
}
// or
foreach (QWidget* w, wl) {
// use w
}
I'm not quite sure where this foreach comes from. If it's not provided by Qt, it may be a macro expanding to BOOST_FOREACH, for which you'll need to include boost/foreach.hpp.

Removing rows from QAbstractTableModel derived class don't work, why?

I have a Qt application for which I derived my own model class from QAbstractTableModel. I have implemented the necessary methods as prescribed in the documentation. When I call removeRows method the changes are correct in my View (the rows I wanted to remove are removed).
But somehow, the operations on the model doesn't seem to be propagated to the QList I use in the model to store my data. When I save the values stored in the QList to the disk, it look like nothing was erased from it by removeRows.
Here is what my removeRows implementation looks like (it is based on the code from the book Advanced Qt Programming, Chapter 3, p.125):
bool MyModel::removeRows(int row, int count, const QModelIndex&)
{
beginRemoveRows( QModelIndex(), row, row + count - 1);
for (int i = 0; i < count; ++i) {
mMyQList.removeAt(row);
}
endRemoveRows();
return true;
}
How do I fix this? What did I miss?
Thanks!
Like Frank O. implies, it's hard to know what's going on without seeing some code. But from the sound of it, the values haven't been removed from QList simply because you haven't taken them out. When you move from Widget to Model/View classes, you have to do this yourself. I.e., in your removeRows() method you must remove the rows from the QList 'by hand'.
It turns out that nothing was wrong with my implementation of removeRows.
The save method was called by my unit tests just before showing my dialog. The dialog was not calling the save method at all.
No wonder the change were visible in the View and not in the output file...