Get an object from the QListWidget and delete it - c++

I have a qt and cpp application that creates threads on create button and runs them with a certain start time specified by the user. It list the thread object created into a QListWidget in the application with some random id generated. I can select and delete the QListWidget item as shown below.
void MainWindow::on_stopPushButton_clicked()
{
qDebug() << mythread->threadIdGenerator();
QList<QListWidgetItem*> items = ui->threadWithId->selectedItems();
foreach(QListWidgetItem* item, items){
ui->threadWithId->removeItemWidget(item);
delete item; // Qt documentation warnings you to destroy item to effectively remove it from QListWidget.
}
}
This delete operation just deletes the entry from the UI (QListWidget) of the application but the thread deleted from QListWidget is still running in the application.
My question is how can I get terminate this thread with deletion from the QListWidget from the UI of the application?
Or is there any way to get this thread object and delete it after being selected from the UI.
Update
void MainWindow::on_createNewThreadButton_clicked()
{
qDebug(" in create new thread slot");
mythread = new MyThread(this);
mythread->threadOccuranceTime = ui->insertThreadTimeoutHere->text().toInt();
mythread->start();
myThreadListCreatedObjects.append(mythread);
connect(mythread, SIGNAL(signalForThreadMessage(int)), this, SLOT(displayThreadMessages(int)));
connect(mythread, SIGNAL(sendThreadId(int)), this, SLOT(displayThread(int)));
}
MyThread.cpp
int MyThread::threadIdGenerator()
{
qDebug(" in threadIdGenerator function");
// qDebug() << 1 + (rand() % 100);
srand(time(0));
return 1 + (rand() % 100);
}
void MyThread::run()
{
this->threadId = 0;
qDebug() << this->threadId;
qDebug(" in run function for the thread");
this->threadId = this->threadIdGenerator();
qDebug(" id inside the run method of thread");
qDebug() << threadId;
emit sendThreadId(threadId);
while (1) {
msleep(this->threadOccuranceTime);
emit signalForThreadMessage(this->threadId);
}
}

I used QList to store all the threads created, and when a item is selected in the QLIstWidget I tried to get the thread with that id property, terminate it and then remove from the QListWidget from UI as shown below.
void MainWindow::on_stopPushButton_clicked()
{
QList<QListWidgetItem*> items = ui->threadWithId->selectedItems();
foreach(QListWidgetItem* item, items){
qDebug() << "the item selected to delete";
qDebug() << item->text();
ui->threadWithId->removeItemWidget(item);
QString selected = item->text();
QString subString = selected.mid(0,2);
qDebug() << "subString = ";
qDebug() << subString;
for(MyThread *sp:myThreadListCreatedObjects){
qDebug() << "thread id = ";
qDebug() << sp->threadId;
if(sp->threadId == subString.toInt()){
qDebug() << "subString = ";
qDebug() << subString;
sp->terminate();
delete sp;
}
}
delete item; // Qt documentation warnings you to destroy item to effectively remove it from QListWidget.
}
}
I am not sure this is the correct way of doing the things but it works some how. Any better solution is welcome :).

Related

How to get data out of readyReadSlot?

I am trying to get data out of slot with a signal readyRead(). But my method doesn't seem to work. I googled a lot but still I can't solve the problem.
Here what I have:
In my main function I call the method sendPOST() to get cookies. I got cookies from this method using inside of it SIGNAL finished(QNetworkReply *) and SLOT replyFinishedSlot_(QNetworkReply *) :
connect(manager_, SIGNAL(finished(QNetworkReply *)), this, SLOT(replyFinishedSlot_(QNetworkReply *)));
I made a public static bool variable isFinished = false by default to write if slot is finished it's job.
replyFinishedSlot_(QNetworkReply ):
if(reply->error())
qDebug() << "Error: " << reply->errorString();
else
{
cookie = reply->manager()->cookieJar()->cookiesForUrl(webReportsUrl);
QString cookieString = cookie[0].name() + "=" + cookie[0].value() + "; domain=" + cookie[0].domain() + "; path=" + cookie[0].path() + ";";
if(reply->isFinished()) isFinished = true; //isFinished is static public variable
}
reply->deleteLater();
And then I check in my main function if isFinished is true, and if it is I connect to another slot:
manager_ = new QNetworkAccessManager(this);
sendPOST("http://url");
if(isFinished)
{
QNetworkAccessManager *man = new QNetworkAccessManager();
QNetworkRequest request(webReportsUrl);
request.setHeader(QNetworkRequest::CookieHeader, QVariant::fromValue(cookie));
getReply = man->get(request);
connect(getReply, SIGNAL(readyRead()), this, SLOT(readyReadSlot_()));
if(isRead)
qDebug() << "reading";
else qDebug() << "not reading";
}
and isFinished in here works very well (but I am not sure if this is the right way to check finished or not like this). I get isFinished == true, and I can get cookies from replyFinishedSlot_.
But the problem is to get data from readyReadSlot_(). I tried different ways to receive the data from this slot, but there's no successful result.
I tried even something like this:
QEventLoop loop;
connect(getReply, SIGNAL(readyRead()), &loop, SLOT(readyReadSlot_()));
loop.exec();
But I got the error:
QObject::connect: No such slot QEventLoop::readyReadSlot_() in ...
Inside readyReadSlot_() I have to receive all the data from the page:
if(getReply->isReadable())
{
if(getReply->error() != QNetworkReply::NoError)
{
qDebug() << "Error: " << getReply->errorString();
}
else {
isRead = true;
response = getReply->readAll(); //here the data I need outside of this slot
qDebug() << "response: " << response;
}
}
getReply->deleteLater();
And I get it successfully inside, but I need to get response outside of this slot, in my main function, for example.
I know here's something with a threads, and I just don't wait till the data recieved, but I don't know how can I fix it.
I found a problem solvation for me.
void DataMartsModel::replyFinishedSlot_(QNetworkReply *reply)
{
static bool isRead = false;
if(reply->error())
qDebug() << "Error: " << reply->errorString();
else
{
cookie = reply->manager()->cookieJar()->cookiesForUrl(webReportsUrl);
QString cookieString = cookie[0].name() + "=" + cookie[0].value() + "; domain=" + cookie[0].domain() + "; path=" + cookie[0].path() + ";";
QNetworkAccessManager *man = new QNetworkAccessManager();
QNetworkRequest request(webReportsUrl);
request.setHeader(QNetworkRequest::CookieHeader, QVariant::fromValue(cookie));
getReply = man->get(request);
connect(getReply, &QNetworkReply::readyRead, [=](){
if(getReply->isReadable())
{
if(getReply->error() != QNetworkReply::NoError) qDebug() << "Error: " << getReply->errorString();
else {
isRead = true;
}
}
});
if(reply->isFinished() && getReply->isReadable()) isFinished = true; //here is the problem solvation I wanted
}
reply->deleteLater();
}
main function
manager_ = new QNetworkAccessManager(this);
sendPOST("http://url");
if(isFinished)
{
QByteArray array = getReply->readAll(); //here I got the data I needed to get from readyReady
qDebug() << array; //here I display it and I can use them in the future
}
If you know better way to solve the problem, I would like to check it, too.

QT show different images depending on input on serial interface

I'm new to QT and I'm trying to create a program that shows different images depending on input from a serial interface.
I realize that there are a number of ways to achieve this and I'm looking for input from someone with experience in QT.
My idea was to send new data to a compare function that returns an integer to the main function, this integer will determine what picture will be shown. However, using a while loop results in the picture being re-drawn and not static.
My question is, should i start another thread for the image viewer, or use a different class for it?
Or is this approach hideous and should i start over?
Thankful for any input!
if(!serial.open(QIODevice::ReadOnly))
qDebug() << serial.errorString();
QObject::connect(&serial, &QSerialPort::readyRead, [&]
{
int comp=0;
int landscape =1;
int total_data = serial.bytesAvailable();
qDebug() << "New data Available: " << serial.bytesAvailable();
QByteArray datas = serial.readAll();
comp= compare(total_data,datas);
while(comp == landscape){
qDebug() << "I Picture";
QLabel label("<img src='landscape.jpg' /> ");
label.show();
}
qDebug() << datas;
});
This is the compare function that reads data from serial interface
int compare(int x, QByteArray y)
{
int r=0;
for(int i = 0; i <= x ; i++){
if (strncmp (y, "\x00",1) ==0)
{
//picture();
r=1;
return r;
}
}
return r;
}
By doing this:
while(comp == landscape){
qDebug() << "I Picture";
QLabel label("<img src='landscape.jpg' /> ");
label.show();
}
You are creating a local QLabel on the stack. It will be destroyed at each iteration.
Qt uses its own mechanism to update its objects (the event loop) and you just have to change the picture in your QLabel when needed.
So, what you can do, it's creating a QLabel in your widget and change the image in your slot:
class Window: public QWidget
{
Q_OBJECT
public:
enum ImageType {
landscape = 1,
};
Window(QObject* parent=nullptr): QWidget(parent),
myLabel(new QLabel(this))
{
if(!serial.open(QIODevice::ReadOnly))
qDebug() << serial.errorString();
connect(&serial, &QSerialPort::readyRead, this, &Window::updateImage);
}
public slots:
void updateImage()
{
int total_data = serial.bytesAvailable();
qDebug() << "New data Available: " << serial.bytesAvailable();
QByteArray datas = serial.readAll();
int const comp = compare(total_data,datas);
if (comp == Window::landscape)
myLabel->setPixmap("landscape.png");
else
myLabel->setPixmap("anotherImg.png");
qDebug() << datas;
}
private:
QLabel* myLabel;
QSerialPort serial;
};
You can use signals/slots and a thread (only if you want to do more actions during the program execution). It is very typical when using the serial line, as it is an asynchronus protocol that has to be pulled to know if there exist new data.
To do so, emit a signal every time you receive data from serial line and create a slot that process it. In this way you will use similar than an event driven system.

QTableWidget Drag Item not Removing when Dropping on Invalid area

Pretty much as the tittle says, when i drag an item from QTableWidget it adds a child to ui->table->children, and then it launches ChildAdded event to my eventFilter, the problem is that if i drop the dragged item into an area that doesn't accept dropping that child won't be removed from ui->table->children whereas releasing the dragged item within an area that has dropping enabled it will, and also launches ChildRemoved event.
Here is my init code:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
m_ui(new Ui::MainWindow)
{
m_ui->setupUi(this);
m_ui->left_table->installEventFilter(this);
m_ui->right_table->installEventFilter(this);
m_ui->left_table->setColumnCount(1);
m_ui->left_table->setRowCount(25);
m_ui->left_table->setHorizontalHeaderLabels({"Source"});
m_ui->left_table->horizontalHeader()->setStretchLastSection(true);
m_ui->left_table->setAcceptDrops(false);
m_ui->left_table->setDragEnabled(true);
m_ui->right_table->setColumnCount(1);
m_ui->right_table->setHorizontalHeaderLabels({"Receiver"});
m_ui->right_table->horizontalHeader()->setStretchLastSection(true);
m_ui->right_table->setAcceptDrops(true);
for (int i = 0; i < 25; ++i) {
m_ui->left_table->setItem(i, 0, new QTableWidgetItem(QString::number(i)));
}
qDebug() << "Left childs: " << m_ui->left_table->children().size();
}
and the event filter:
bool MainWindow::eventFilter(QObject *watched, QEvent *event)
{
if (event->type() == QEvent::ChildAdded || event->type() == QEvent::ChildRemoved) {
qDebug() << "Object: " << watched->objectName()
<< " Event: " << event->type()
<< "Childs: " << m_ui->left_table->children().size();
}
return false;
}
Example of dropping on invalid area, this wont remove the child added before:
Example of dropping on valid area, this will remove the child and call the ChildRemoved event:

Qt Creator - Remove all UI keyboard shortcuts (QButton, QSlider etc.)

I was wondering if there was a way I could remove all keyboard shortcuts from the UI so I can use the event filter to grab key commands instead.
Currently, I have this in my eventFilter() function and it does the job but it also affects the QSliders, QLineEdits and QButtons I have on there - and I don't want it to.
bool LinkControl::eventFilter(QObject *o, QEvent *e)
{
QKeyEvent *keyEvent = NULL;
// qDebug() << "TYPE: " << e->type();
switch(e->type())
{
case 51:
// qDebug() << this->overrideControl;
if(this->overrideControl == true)
{
keyEvent = static_cast<QKeyEvent*>(e);
// this->handleKeyboardInput(true, keyEvent->key());
// emit handleInput(true, keyEvent->key());
this->handleKeyboardInput(true, keyEvent->key());
// qDebug() << "PRESS: " << keyEvent->key();
}
this->overrideControl = !this->overrideControl;
return true;
break;
case QEvent::KeyRelease:
keyEvent = static_cast<QKeyEvent*>(e);
// this->handleKeyboardInput(false, keyEvent->key());
// emit handleInput(false, keyEvent->key());
this->handleKeyboardInput(false, keyEvent->key());
// qDebug() << "RELEASE: " << keyEvent->key();
return true;
break;
default:
return QMainWindow::eventFilter(o, e);
}
}
For example, In my handleKeyboardInput function, I have the up arrow key increment a value and it does that but it also moves a QSlider if it's selected.
Thank you.

Howto use Qt QWebView::createWindow(QWebPage::WebWindowType type) correctly?

I have a serious problem with QWebView::createWindow() and how to handle creating
new browser window.
I have sub-classed QWebView as told by docs (MyWebView) and reimplemented it's createWindow() method and also it's contextMenuEvent(QContextMenuEvent * event) method so that I could add and change my own menu entries.
The context menu entries "Open Link", "Open Link in New Tab" and "Open Image" all work perfectly and either open the required link/image into same tab if "Open Link" is selected or into a new tab if one of the other three remaining "Open ..." entries is selected. Also, when clicking web pages that want to open in new window they will open in new tab, as expected.
However, I added new menu entry called "Open Link in New Window" and for the life of me can't get it working. It opens completely new browser window but it does not load the clicked url. Even worse, if I manually enter some www address to this new browser window and then try to open new tabs they will open in the old window!!!
Could someone please kindly check what is wrong with my code ?
First, the MyWebView constructor:
MyWebView::MyWebView(QWidget * parent):
QWebView(parent),newWindow(false)
{
this->myPage = new MyWebPage;
this->setPage(this->myPage);
/* Just change text and nothing more ... */
this->action_openLinkInNewWindow = this->pageAction(QWebPage::OpenLinkInNewWindow);
if(this->action_openLinkInNewWindow) {
if(this->action_openLinkInNewWindow->isEnabled()) {
this->action_openLinkInNewWindow->setText("Open Link in New Window");
}
}
}
Then the "Open Image", "Open Link in New Tab" and "Open Link in New Window" functionality
(default "Open Link" worked just fine so I did not need to reimplement that one)
void MyWebView::openImage()
{
#ifndef NDEBUG
qDebug() << "=================================================";
qDebug() << __FUNCTION__ << " called ...";
#endif
this->imageUrl = true;
this->newWindow = false;
this->createWindow(QWebPage::WebBrowserWindow);
}
void MyWebView::openLinkInNewTab()
{
#ifndef NDEBUG
qDebug() << "=================================================";
qDebug() << __FUNCTION__ << " called ...";
#endif
this->linkUrl = true;
this->newWindow = false;
this->createWindow(QWebPage::WebBrowserWindow);
}
void MyWebView::openLinkInNewWindow()
{
#ifndef NDEBUG
qDebug() << "=================================================";
qDebug() << __FUNCTION__ << " called ...";
#endif
this->linkUrl = true;
this->newWindow = true;
this->createWindow(QWebPage::WebBrowserWindow);
}
Then, my reimplemented contextMenuEvent()
void MyWebView::contextMenuEvent(QContextMenuEvent * event)
{
#ifndef NDEBUG
qDebug() << "=================================================";
qDebug() << __FUNCTION__ << " called ...";
#endif
this->rel_pos = event->pos();
QWebHitTestResult r = page()->mainFrame()->hitTestContent(event->pos());
QMenu menu(this);
if (!r.linkUrl().isEmpty()) {
menu.addAction(pageAction(QWebPage::OpenLink));
menu.addAction(tr("Open Link in New Tab"), this, SLOT(openLinkInNewTab()));
menu.addAction(tr("Open Link in New Window"),this,SLOT(openLinkInNewWindow()));
menu.addAction(pageAction(QWebPage::DownloadLinkToDisk));
menu.addAction(pageAction(QWebPage::CopyLinkToClipboard));
menu.addSeparator();
}
if(!r.imageUrl().isEmpty()) {
menu.addAction(tr("Open Image"),this,SLOT(openImage()));
menu.addAction(pageAction(QWebPage::DownloadImageToDisk));
menu.addAction(pageAction(QWebPage::CopyImageToClipboard));
menu.addAction(pageAction(QWebPage::CopyImageUrlToClipboard));
}
if(!r.linkUrl().isEmpty() || !r.imageUrl().isEmpty()) {
menu.exec(mapToGlobal(rel_pos));
return;
}
QWebView::contextMenuEvent(event);
}
And finally, the problematic createWindow()
QWebView* MyWebView::createWindow(QWebPage::WebWindowType type)
{
#ifndef NDEBUG
qDebug() << "=================================================";
qDebug() << __FUNCTION__ << " called ...";
#endif
switch(type) {
case QWebPage::WebBrowserWindow:
{
QWebHitTestResult hitTest = this->page()->mainFrame()->hitTestContent(rel_pos);
QUrl url;
if(this->linkUrl) {
url = hitTest.linkUrl();
this->linkUrl = false;
}
if(this->imageUrl) {
url = hitTest.imageUrl();
this->imageUrl = false;
}
if(newWindow) {
/* This does not work!!!!*/
MainWindow *mw = new MainWindow;
mw ->show();
return mw->currentTab();
} else {
MyBrowser* browser = new MyBrowser(url);
TabbedBrowser::getInstance()->newTab(browser,"Loading ...");
return browser->getwebView();
}
}
break;
}
return QWebView::createWindow(type);
}
If there is anything else with my code, besides createWindow() then I would gladly
hear.
Thank you!