c++ - Qt GUI becomes unresponsive emitting signals too fast -
i've got small chat client stores history in sqlite
database. when user clicks on history
tab in application app fetches relevant history , displays in qwebview
. im fetching background thread dbthread
below , sending signals update qwebview
accordingly.
this works fine, until database grows. when database gets larger app starts crashes. gui unresponsive few seconds until loaded (4-6 secs) depending on database
size.
i've tried add qt::queuedconnection
on signals , mentioned above i'm handling database
queries background thread
.
i'm guessing i'm emitting signals fast. ideas how solve this?
signals
connect(dbtrad, signal(addallhistorymessage(qstring, qstring, qstring, qstring, qstring)), this, slot(addallhistorymessage(qstring, qstring, qstring, qstring, qstring)), qt::queuedconnection); connect(dbtrad, signal(addallhistorymessageinner(qstring, qstring, qstring, qstring, qstring)), this, slot(addallhistorymessageinner(qstring, qstring, qstring, qstring, qstring)), qt::queuedconnection);
code fetches history sqlite database:
// loads local history void dbthread::loadallhistory(qstring agentid, qstring agentname) { bool ret = false; bool retinner = false; qstring retval = ""; qdatetime datetime = datetime.currentdatetime(); qstring datetimefortodaycheck = datetime.tostring("yyyy-mm-dd"); if (db.isopen()) { qsqlquery query(db); qsqlquery queryinner(db); ret = query.exec(qstring("select channelid, sender, time, message chathistory sender != 'servermessage' , channelid not '%agent%' group channelid order time desc;")); if (ret) { while (query.next()) { qstring channelid = query.value(0).tostring(); qstring sender = query.value(1).tostring(); qstring time = query.value(2).tostring(); qstring msg = query.value(3).tostring(); qstring timestr; qstring fmt = "yyyy-mm-dd hh:mm:ss"; qdatetime dt = qdatetime::fromstring(time, fmt); qdatetime dtcompare = qdatetime::fromstring(time, fmt); if(datetimefortodaycheck == dtcompare.tostring("yyyy-mm-dd")) { // if today timestr = "today " + dt.tostring("hh:mm"); } else { timestr = dt.tostring("dd mmm yyyy"); } if(sender == agentid) { sender = agentname; } // grab tags qstring temptagsforchannelid = gethistorytagsstring(channelid); emit addallhistorymessage(channelid, sender, timestr, msg, temptagsforchannelid); // load sub-history retinner = queryinner.exec(qstring("select * chathistory sender != 'servermessage' , channelid = '%1' , message != '%2' order time desc;").arg(channelid).arg(msg)); if (retinner) { while (queryinner.next()) { qstring channelidinner = queryinner.value(0).tostring(); qstring senderinner = queryinner.value(1).tostring(); qstring timeinner = queryinner.value(4).tostring(); qstring msginner = queryinner.value(2).tostring(); qstring timestr2; qstring fmt = "yyyy-mm-dd hh:mm:ss"; qdatetime dt = qdatetime::fromstring(timeinner, fmt); qdatetime dtcompare = qdatetime::fromstring(timeinner, fmt); if(datetimefortodaycheck == dtcompare.tostring("yyyy-mm-dd")) { // if today timestr2 = "today " + dt.tostring("hh:mm"); } else { timestr2 = dt.tostring("dd mmm yyyy"); } if(senderinner == agentid) { senderinner = agentname; } emit addallhistorymessageinner(channelidinner, senderinner, timestr2, msginner, temptagsforchannelid); } } } } } }
my code update:
void mainwindow::addallhistorymessageinner(qstring channelidinner, qstring senderinner, qstring timestr2, qstring msginner, qstring temptagsforchannelid) { ui->webviewhistory->page()->mainframe()->evaluatejavascript("$('#history tbody').append('<tr id=\"" + channelidinner+ "\" class=\"hiddenrow\"><td>" + senderinner + "</td><td align=\"center\">" + timestr2 + "</td><td align=\"center\" style=\"word-wrap:break-word;\">" + msginner.remove(qregexp("<[^>]*>")) + "</td><td align=\"center\">" + temptagsforchannelid + "</td></tr>');undefined"); } void mainwindow::addallhistorymessage(qstring channelid, qstring sender, qstring timestr, qstring msg, qstring temptagsforchannelid) { ui->webviewhistory->page()->mainframe()->evaluatejavascript("$('#history tbody').append('<tr id=\"" + channelid + "\"><td>" + sender + "</td><td align=\"center\">" + timestr + "</td><td align=\"center\" style=\"word-wrap:break-word;\">" + msg.remove(qregexp("<[^>]*>")) + "</td><td align=\"center\" style=\"word-wrap:break-word;\">" + temptagsforchannelid + "</td></tr>');undefined"); }
edit: implementation of dbthread
thread = new qthread(this); dbtrad = new dbthread(); dbtrad->movetothread(thread);
edit 2: how call loadallhistory
i create signal:
connect(this, signal(loadallhistorys(qstring, qstring)), dbtrad, slot(loadallhistory(qstring, qstring)));
and call this:
emit loadallhistorys(agentid, agentname);
the problem is, main thread interrupted every single row in innerquery
. destroys benefits of loading data in separate thread. overhead of signal/slot communication on thread boundaries higher costs of loading single row database.
i recommend collect rows in qlist
instance while
loop. when done, push complete result via 1 signal invocation main thread:
first declare simple class storing history items:
class historyitem { public: qstring channelid; /* additonal fields omitted brevity */ /* also, private fields getters , setters better */ }
then, create list of such objects before while
loop:
qlist<historyitem*> innerresult; while (queryinner.next()) { /* snip */ historyitem* item = new historyitem(); item.channelid = channelidinner; /* more lines ommited */ innerresult.append(historyitem); } emit historyloaded(innerresult);
obviously, need matching signal definition in worker class:
q_signal void historyloaded(qlist<historyitem*> result);
also noted in comments, have start background thread qthread::start()
.
Comments
Post a Comment