Qt - Detect item information change in QListView - c++

I have a QListView which is connected to a QStandardItemModel. How do I detect any information change in the model or the QListView? I tried the Signals and Slots with the itemChanged() for the model but it seems to crash the whole program.
Qbject::connect(bugModel, SIGNAL(itemChanged(QStandardItem*)), this, SLOT(bugInfoChanged()));
That is the code I'm using to connect the Signal. the function bugInfoChanged() just runs a qDebug() that says "Changed". But when I start the program, it shows a crash error.

When I comment this line (//QObj...) then the crash doesn't occur, but again when I remove the comment it does crash. I have this in my "Private Slots" area:
void bugInfoChanged();
and it's like this in the cpp:
void MainWindow::bugInfoChanged()
{
qDebug() << "Changed";
}
I have no clue as to what causes the crash :/

I fixed it myself. Turns out if I place the connecting code in a function where the list is populated, it works just fine. It used to crash because the list didn't have any item at the moment when the App started.

Related

ListView not initially showing data

My QML ListView doesn't show my data until I perturb it with the mouse (e.g. just drag it up and down.) After this the view shows the model without issue until it empties, and then I once again need to perturb it to get it working again. Is there way to kick this ListView into working?
I'm using Qt 5.8 on Linux 14.04. My model is a subclass of QAbstractListModel. I build it by following the AbstractItemModel Example. The main difference is that my list model is a property of an entity, rather than being set with setContextProperty in main.cpp.
There are a few similar issues here on SO about the ListViews not updating, but none seem to only have an issue at the start. Most of them relate to the OP calling dataChanged manually instead of beforeInsertRows() & endInsertRows() - both methods I'm calling (see below.)
My ListView is in an item loaded with a SceneLoader.
I posted all the relevant code here, because I'm a little suspicious of how I use the Layouts on my ListView (maybe that's causing it? Maybe my hierarchy is broken? I haven't been able to prove that though.)
In short though,
ListView:
ListView {
anchors.fill: parent
model: sceneGraph.blobs
delegate: delegate
}
BlobModel.cpp:
auto BlobModel::addBlob(const BlobPointDataPtr& data) -> void
{
// ...
// Each blob has a uuid
const auto idx = Contains(uuid);
if (-1 != idx)
{
blobs_[idx]->Update(data);
Q_EMIT dataChanged(createIndex(idx, 0), createIndex(idx, 0));
}
else
{
beginInsertRows(QModelIndex(), rowCount(), rowCount());
blobs_ << new Blob{data, id_count_}; id_count_++;
endInsertRows(); // responsible for the QQmlChangeSet
Q_EMIT dataChanged(createIndex(rowCount(), 0), createIndex(rowCount(), 0));
}
}
Also, on my terminal, I receive the message:
QObject::connect: Cannot queue arguments of type 'QQmlChangeSet'
(Make sure 'QQmlChangeSet' is registered using qRegisterMetaType().)
This seems to be emitted by endInsertRows(), but I'm not sure why. In the past the solution has been to register the missing type, e.g. qRegisterMetaType<QQmlChangeSet*>("QQmlChangeSet"); but this seems not to be a public type with Qt, and because everything mostly works without it, I'm not sure missing that is the exact issue.
The problem, as pointed out in the comments, was that I was modifying my model outside of the main thread.
My code was set up so that another thread would trigger additions to my model by directly calling addData. The reason my minimal example wasn't able to replicate this was because in it I used a QTimer to simulate the other thread, however QTimer also runs on the main thread.
The solution was to change my direct call to addData(data) to emitted a signal to do the addition, thus moving the actual work back to the main thread.

QListWidget causes crash when clear() is called while items are selected

My application crashes, when I try to clear() all items from a QListWidget and at least one item is selected. Calling clearSelection() first causes the program to crash, too (at the clearSelection() call). Removing the items in a while loop, leads also to a crash. The error-message is
ASSERT: "!isEmpty()" in file /usr/include/qt4/QtCore/qlist.h, line 282.
Some example code:
void MainWindow::clearListWidget()
{
// ui->listWidget->clearSelection(); // --> causes crash
// ui->listWidget->clear(); // --> also causes crash
while(ui->listWidget->count()>0) // --> no crash calling count()
ui->listWidget->takeItem(0); // --> crash again
}
As mentioned, the application only crashes, if items are selected. If nothing is selected, then the methods above work as intended. I work with Qt 4.8.4 on Ubuntu.
I would be thankful for any suggestions, how I can solve the problem.
I have found a solution on my own. The problem was seemingly caused by accessing a selected item in a slot-method, that was connected to the signal itemSelectionChanged(). Here I accessed the text of the selected item via
string text = ui->listWidget->selectedItems().first()->text().toStdString();
Afterwards the crash appeared as described in my question by calling e.g. clear(). I guess the selection process is not finished, when itemSelectionChanged() is emitted and the QListWidget gets somehow confused, when the selected items are already accessed at this point of time. After replacing the signal by itemClicked(QListWidgetItem*), the application no longer crashed.
ui->listWidget->blockSignals(true);
ui->listWidget->clear();
ui->listWidget->blockSignals(false);
This worked in my case.

WT widget not updating in boost thread

I have run into an interesting problem with WT, I have solved it, but I do not understand WHY my solution solved the problem. I've dug through WT documentation for the widgets and have come up empty handed so far, so maybe someone who knows more about WT can help me out here.
Anyway, the problem is with a WComboBox widget in a boost thread not updating it's data when clicked on and having it's selection changed.
I created a boost thread in a class
class MyConsole: public WApplication
{
private:
boost::shared_ptr<boost::thread> _thread;
WComboBox* _combo_box;
bool running;
//Thread function
void my_thread(Wt::WApplication *app);
}
Then I fill the combo box with data, lets use "foo" and "goya" as the 2 entries. I made a function for the thread, and put a loop into it.
void MyConsole::my_thread(Wt::WApplication *app)
{
while(running)
{
std::string test;
Wt::WApplication::UpdateLock lock(app);
if(lock)
{
test = _combo_box->valueText().narrow();
}
if (strcmp("foo", test.c_str()) == 0)
{
cout << "we got foo" << endl;
}
else if (strcmp("goya", test.c_str()) == 0)
{
cout << "we got goya" << endl;
}
}
}
Without changing the initial selection of the combo box, the above code always enters the foo if statement, which is expected. However, when I change the selection of the _combo_box to "goya" the above code still enters the "foo" if statement, which is very unexpected. Investigating the matter further such as printing out the current index of the combo box before the if statement showed me that it is always 0 and never gets incremented when the selection changes.
The way I fixed it was by connecting the combo box changed() signal to a do nothing function that I added to the class.
class MyConsole: public WApplication
{
private:
...
void WWidgetForceUpdate(void)
{
}
...
}
...
_combo_box->changed().connect(this, &MyConsole::WWidgetForceUpdate);
With the addition of that function call when the selection changes, the "foo" and "goya" if statements worked properly, and printing out the current index of the combo box before the if statement confirmed that the index was now changing.
Why did connecting the changed() signal to a do nothing function remedy the situation? I am sure there is a bigger problem that I am not seeing here :(
Any help would be much appreciated.
Wt sends changes from the browser to the server when events happen. If your program is not interested in an event, this synchronisation will not take place (otherwise synchronisation would take place on every character of text you enter in an input box, on every mose movement, .... even if your application is not doing anything with it). Nothing connected to changed() means that nothing is interested in that specific event, and the browser will not notify the server when it happens.
Any event that is being listened upon will send all changes of all widgets to the server, so that the full widget tree is synchronised. So if you have a button with clicked() listener, and a combobox without a changed() listener, the state of the combobox will still be updated in the widget tree when you click the button.
There is however a bug in your code: you cannot just access the widget tree from a random thread without grabbing the update lock (WApplication::UpdateLock).

qt signals cause segmentation fault on connect

I made a widget that behaves as a window and when a button is pressed it simply emits a signal:
signals:
void SaveTask( void );
in my mainwindow.cpp I define (in the constructor):
connect( taskWindow, SIGNAL(SaveTask()), task_view, SLOT(UpdateFromTasks()) );
taskWindow = pointer to window where this signal emits.
task_view = pointer to treewidget in mainwindow with a slot.
It is designed so that when you save a task it is displayed in the treeview.
unfortunately when I try to run the program it causes a segfault on the connect line, when I remove it the program just runs fine (apart from this functionality ofcourse). It does compile and all elements are initialized and useable. I simply don't see how this can fail.
It seems like maybe you are doing the connection before you have initalized the taskWindow or task_view and are using uninitialized pointers.
Also you could try this signature (which should be the same thing, but just for good measure)
signals:
void SaveTask();

Qt C++ WebKit windowCloseRequested Signal

I am trying to connect QWebpage::windowCloseRequested() to a slot that just prints out a debug message. When I call window.close(); in JavaScript it doesn't bubble the signal up or call the slot...
connect(webView->page(), SIGNAL(windowCloseRequested()),this, SLOT(windowCloseRequested()));
The slot is setup, it is in my window.h file as a slot like this:
public slots:
void windowCloseRequested();
And the function is defined as:
void MyWindow::windowCloseRequested(){
qDebug() << "I was called";
}
When I compile, there are no errors, there were before saying I had the slots wrong, I figured that part out, no more error, but now when I click a link, or call window.close() with javascript in a loaded webpage, it doesn't do anything. If I manually call the function, it prints out the debug message.
Any pointers, or help/solutions would be appreciated. Note, this code above is based on the Tabwidget.cpp code for a browser example. It's the best reference I could find.
Attaching an onclick to an <a> tag is ... questionable. Use a span, and blammo, it works. This is why you should take breaks when coding, or else you make really dumb mistakes that waste time.