QT Exception treatment - c++

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.

Related

What could be the cause for runtime "can't find linker symbol for virtual table..." error in Qt?

This question was asked in similar ways multiple times, for example at stackoverflow or forum.qt.io or qtcentre.org. The problem is that this error message is so vague that one solution cannot be applied to another scenario. Most of the threads are dead in the middle of the discussion though :-(
So the complete error message that I get in my Qt application is:
can't find linker symbol for virtual table for "OneOfMyClasses" value
found "QString::shared_null" instead
The OneOfMyClasses changes depending on various things, the QString::shared_null stays the same for all errors that I get. Here is a screenshot of my logging console:
Why is the font color pink, so who is printing this message?
Why do I only see this message when I set a breakpoint and step through my code? This message does not appear when simply running the application.
The point where it happens is in this function in the source line right before the current position (yellow arrow):
So according to the message I stepped into m_pStateWidget->insertNavLabel(...) and the error message is printed somewhere in the constructors inside Qt related to the QString class. So I tried the following, which moves the problem away from this code location:
When doing this I get the same error message a few code lines below with another class name in the message, note that the QString::shared_null stays the same.
It appears to me that I have some sort of corrupted memory.
How should I start investigating this issue? I'm afraid to change the code because this might hide the problem as described above.
What's up with the QString::shared_null? I have found that others often see the same in their error messages.
Thank you for any hint or help! :-)
Edit: It's becoming really interesting now. I have stepped into every single function just right before the message is printed and I ended up with these error messages:
at this location:
When I navigate through the call stack in QtCreator the error is printed again and again everytime I select another function in the stack.
Does this mean that the debugger is printing the message and that it is simply too stupid to resolve some sort of vtable stuff for me or does this mean that I have serious trouble going on?
Cause:
Somewhere in your code , you might have overrun the actual memory
Example 1 :
int elmArray[10];
for(int i = 0; i < 20; ++i)
{
elmArray[i] = 0;
}
In the above case, actual array size is 10 but we are assigning values to the index beyond 10.
Example 2:
char* cpyString;
strcpy(cpyString , "TEST");
These scenarios might end up in writing the values into other objects. Mostly could corrupt the virtual table.This gives the above warning.
Fix:
As you know, just correct the code as below.
Example :
int elmArray[10];
for(int i = 0; i < 10; ++i)
{
elmArray[i] = 0;
}
char cpyString[10];
strcpy(cpyString , "TEST");
In your case seems like, you are assigning the QTString::shared_null to some uninitialized string.
There are various threads on different websites where the
can not find linker symbol for virtual table
problem is discussed. Few explain why the problem exists, although some solutions are given to specific examples. Having experienced difficulty with this, I would like to share what I have learned.
First this error message only appeared for Linux builds, it did not show up for Windows builds.
In my case the problem was caused by a second call into a non-reentrant method from the same thread. Once I found the problem, it was easy to fix by using a static busy flag, and simply returning when busy was called a second time. In a nutshell that was the problem and solution. But how did I get into this mess?
Well the non-rentrant method was actually a Qt slot. Since I knew there was a possibility of the second call (actually an emit) being made from the first, the connect was set up with Qt::QueuedConnection. However, I later put up a splash screen QSplashScreen while the function was processing. Little did I realize that QSplashScreen::repaint() called QApplication::processEvents() which dispatched the second offending emit.
So I could have fixed the problem by removing the QSplashScreen and using a QLabel. However, while either works nicely in Windows, neither actually works in Linux, they put up a semi-transparent window and don't paint the contents (even repaint() and or processEvents() doesn't do it). So that is probably a Qt Linux bug, which is another story.

Add accelerator ctrl+F for text search

I am trying to add a Ctrl+F accelerator to my gtkmm textview program. I already implemented the search function into an gtk Entry field, so the only thing I need is to get focus the find entry when Ctrl+F is pressed.
I googled and checked tutorials/reference of gtkmm (2.4, I'm working with that) but the only things I found were accelerators in context with menus and toolbars using UIManager, which I don't have in that .cc file I use (and I can't add them, cause its an existing program).
I tried to add an action with an AccelKey on a button or tried the function add_accelerator() but I wasn't able to use them properly (I am pretty new to gtkmm and there aren't enough samples - at least none I understand). Here some examples I tried:
_gtkActionGroup->add(
Gtk::Action::create("find", "Find", "search in file"),
Gtk::AccelKey("<control>F"),
sigc::mem_fun(this, &SrcFilesView::onGtkTxtFindAccKeyPressed));
I didn't know how to add this action to the button (in the toolbar) I created...
_gtkAccelGroup(Gtk::AccelGroup::create()) //initialized in the constructor of the class
...
_gtkBtnFind.add_accelerator("find", _gtkAccelGroup, GDK_Find,
Gdk::ModifierType::CONTROL_MASK, Gtk::ACCEL_VISIBLE);
I tried here something, but I didn't really understand neither the parameters I needed to enter here nor how this method works - ofc it didn't work...
I'd be really happy if anyone can explain me how this things work properly and sorry for my bad english. If there are any things you need just tell me please. Thanks in advance
Greetings
edit: I looked up in the gtk sources and tried to understand the parameters of add_accelerator. Now I tried this but still doesn't work...:
_gtkBtnFind.add_accelerator("clicked", _gtkAccelGroup, GDK_KEY_F /* or better GDK_KEY_f ?*/,
Gdk::ModifierType(GDK_CONTROL_MASK), Gtk::AccelFlags(GTK_ACCEL_VISIBLE));
_gtkBtnFind.signal_clicked().connect(
sigc::mem_fun(this, &SrcFilesView::onGtkTxtFindAccKeyPressed));
UPDATE:
Okay I have understood most I think now, and I know why it doesn't work. The problem is that I have to add the accel_group to the window widget, but I got only a scrolled window and boxes in my program....and now I have no clue how to continue... :)
UPDATE2:
Alright I managed to do it without accelerators by using the "on_key_press_event" handler by checking the state and keyval parameter. Hope this helps some ppl at least ^^.
bool on_key_press_event(GdkEventKey* event) { /* declaration in my constructor removed */
if(event->state == GDK_CONTROL_MASK && event->keyval == GDK_KEY_f
|| event->state == (GDK_CONTROL_MASK | GDK_LOCK_MASK)
&& event->keyval == GDK_KEY_F) {
_gtkEntFind.grab_focus();
}
return false;
}
I would be still interested in a solution with the accelerators if there is any ! Greetings

Qt C++ : removing next-to-last item from QListWidget makes program crash

in this program, items (markers) are added to a QListWidget calles ui->lwMarkers. These items can also be removed again by pressing the "Remove button" which calls the following function
void Form::on_pbRemoveMarker_clicked()
{
if (ui->lwMarkers->currentRow() < 0) return;
delete ui->lwMarkers->takeItem(ui->lwMarkers->currentRow());
}
Inside the function, the first line is to make sure an item (marker) is actually selected.
The second line is (at least, I hope) to delete the selected item.
Adding and removing: all goes well, unless when you want to remove next-to-last item. Then it crashes, unfortunately. I do not see why.
Can anyone shed a light on this issue?
If it can help: the full code is from the qt-google-maps project: https://code.google.com/p/qt-google-maps/ . This project uses the Google Maps API v2, I altered the code to use v3.
The question that I ask, is a particular behaviour of their code, and I simply don't see the reason of the crash. Any help?
The crash always happens just before the delete, I believe it is because of the takeItem and the error I get is as follows:
ASSERT failure in QList::operator[]: "index out of range", file ../../QtSDK/Desktop/Qt/473/gcc/include/QtCore/qlist.h, line 464
Could it be that takeItem is the evildoer? According to the class reference , it removes the item from the QListWidget and returns it. It also mentions:
Items removed from a list widget will not be managed by Qt, and will need to be deleted manually.
This is why, to me, the original code seems correct, you remove the item from the list widget and delete it afterwards. Still, it gives the above mentioned error when trying to remove the next-to-last item.
I suggest to use the item() function instead, and delete it accordingly:
void Form::on_pbRemoveMarker_clicked()
{
if (ui->lwMarkers->currentRow() < 0) return;
delete ui->lwMarkers->item(ui->lwMarkers->currentRow());
}
The frontend of the program is now working as expected, but do I leave memory leaks this way?
Any other problem you might see?

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.

Why can't I add a string to a combo box?

This seems trivial, but with MFC I always end up with some stupid trivial problem that puts a stop to my workflow.
I am getting a "Debug Assertion Failed" error pointing to afxcmn2.inl line 352:
_AFXCMN_INLINE int CComboBoxEx::AddString(LPCTSTR lpszString)
{ UNUSED_ALWAYS(lpszString); ASSERT(FALSE); return CB_ERR;}
I am attempting to just add some strings to a combo box on initialization like so:
BOOL myDialog::OnInitDialog()
{
CDHtmlDialog::OnInitDialog();
cb_direction.AddString(CString("North"));
}
Most of the answers on Google seem to suggest that the AddString is happening before OnInitDialog, which doesn't seem to be the case here. Another series of answers on Google suggests the data exchange isn't happening or it's wrong, but it's not:
void myDialog::DoDataExchange(CDataExchange* pDX)
{
CDHtmlDialog::DoDataExchange(pDX);
DDX_Control(pDX, IDC_WHEDIT_DIR, cb_direction);
}
Another suggestion was that the combo box hasn't been created yet, but if I disable the combobox using the following code, not only do I NOT get an error, but it actually works and disables the box!
BOOL myDialog::OnInitDialog()
{
CDHtmlDialog::OnInitDialog();
cb_direction.EnableWindow(FALSE);
}
I've cleaned the solution and rebuilt it. I'm not sure what else I am missing. And all I want to do is to add a string to a combo box, which would take 2 seconds in .Net (this program that was written years ago by someone else which is why it's in MFC rather than .Net, but I digress).
Entering the game a little late but, who knows, this might help someone someday:
COMBOBOXEXITEM item;
ZeroMemory(&item, sizeof(item));
item.mask = CBEIF_TEXT;
item.iItem = 0;
item.pszText = _T("Hello");
m_ComboEx.InsertItem(&item);
FWIW, AddString() functionality is removed from CComboEx because the purpose of the control is to display advanced items (with images, identation, whatever...), not straight regular text items.
Well if you look at what the method is doing they have an ASSERT(FALSE) in there, so no wonder. It doesn't actually do anything that would indicate it adds an item to the ComboBoxEx control. Per the docs
This function is not supported by the Windows ComboBoxEx control. For more information on this control, see ComboBoxEx Controls in the Platform SDK.
The documentation is your friend :)