Qt creating children threads using QFuture error - qt

I am trying to make a Collaborative Editor(I have to use Linux networking libraries for all the networking stuff), I have the main widget(custom made class that inherits QWidget) with all the components. In the constructor I create all the Widgets on this main Widget and at the end I try to create a new thread using QFuture(I use QFuture instead of QThread cause it allows me easily to call functions with any type of parameters, like QTextEdit, QTextCursor...) but it gives me this error at compilation:
"QObject: Cannot create children for a parent that is in a different thread.
(Parent is QTextDocument(0x1b064b0), parent's thread is QThread(0x1985750), current thread is QThread(0x1ae7610)".
How to solve the error?
Here is my code:
mainwindow.h:
...//includes
using namespace QtConcurrent;
...
namespace Ui {
class Widget;
class TextEdit;
}
class TextEdit;
class Widget;
class Widget : public QWidget {
Q_OBJECT
public:
Widget(QWidget *parent = 0);
~Widget();
...
QFuture<void> thread;
}
class TextEdit : public QTextEdit {
Q_OBJECT
...
}
static void receiveKeyPress(TextEdit *textedit, QTextCursor *secondUserCursor) {
unsigned long long int Number = NULL;
QMessageBox::information(textedit->parentWidget(), "UI Component", "This makes the thread to throw the error");
while(1) if(connected == 1) {
read(recvFileDescriptor, &Number, sizeof(unsigned long long int));
if( Number != NULL)
if( Number == Qt::Key_Home )
secondUserCursor->movePosition(QTextCursor::StartOfLine);
...
else {
QTextCharFormat backgroundFormat = textedit->textCursor().charFormat();
backgroundFormat.setBackground(QColor("lightGreen"));
//If I don't use QMessageBox up there, it breaks here on the next command
secondUserCursor->setCharFormat(backgroundFormat);
secondUserCursor->setPosition(textedit->textCursor().position());
secondUserCursor->insertText(QString::number(Number));
} //else
}//while
}//the function
And mainwindow.cpp:
#include "mainwindow.h"
Widget::Widget(QWidget *parent) {
...
thread = run(receiveKeyPress, this->edit1, this->edit1->secondUserCursor); //run is from QtConcurrent namespace
}
main.cpp:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget window;
...
window.show();
return a.exec();
}
I've read here on stackoverflow how others use QObject(which I never used and I don't get the idea of it) and QThread(the only combination) but I already tried to use QThread and I wasn't able to pass QTextEdit and QTextCursor to it.
Thanks in advance
Edit:
mainwindow.h
class TextEdit : public QTextEdit {
Q_OBJECT
...
public slots:
void receiveKeyPress(qulonglong);
...
};
mainwindow.cpp
void TextEdit::receiveKeyPress(qulonglong Number) {
if( Number == Qt::Key_Home )
...
}
recv-thread.h - created based on this link http://developer.qt.nokia.com/doc/qt-4.8/thread-basics.html#example-3-clock
#include <QThread>
#include "mainwindow.h" //To get TextEdit in here
class RecvThread : public QThread {
Q_OBJECT
signals:
void transferDataToSlot(qulonglong Data);
protected:
void run();
};
recv-thread.cpp
#include "recv-thread.h"
void RecvThread::run() {
unsigned long long int Number = NULL;
while(1) if(connected == 1) {
read(recvFileDescriptor, &Number, sizeof(unsigned long long int));
if( Number != NULL) {
emit transferDataToSlot(Number);
}
}
}
main.cpp
...
#include "recv-thread.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget window;
RecvThread recvThread;
...
QObject::connect(&recvThread, SIGNAL(transferDataToSlot(qulonglong)), window.edit1, SLOT(receiveKeyPress(qulonglong)), Qt::QueuedConnection); //line 38
recvThread.start();
//Displaying the window
window.show();
a.exec();
recvThread.quit();
recvThread.wait();
return 0;
}
Am I doing it right?

Related

QThread created in other QThread not calling destructor

I have a code:
#include <QApplication>
#include <QThread>
#include <QDebug>
class ChildThread : public QThread {
Q_OBJECT
public:
ChildThread() {
connect(this, &QThread::finished, this, &ChildThread::deleteLater);
}
~ChildThread() {
qDebug() << "~TR()";
}
protected:
void run() {
qDebug() << "RUN";
}
};
class ParentThread : public QThread {
Q_OBJECT
public:
protected:
void run() {
for (int i = 0; i < 10; i++) {
ChildThread *t = new ChildThread();
t->start();
msleep(1000);
}
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
ParentThread *t = new ParentThread();
t->start();
for (int i = 0; i < 10; i++) {
ChildThread *t = new ChildThread();
t->start();
QThread::msleep(1000);
}
return a.exec();
}
And I havnt understand, why all of the ChildThread that created in the ParentThread after reaching end of run() function not ending and desctructor of the ChildThread not called, but if I create ChildThread outside of ParentThread, deststructor of ChildThread was called?
Thank You!
The thread will not be destroyed when the run() function due to the
fact that the deleteLater() function is called when the parent (main) loop
get back the control.
Creating the ChildThread from main(), the QThread::msleep() call
give back the control to the main loop, so the destructor can be
called.

How can I use replacedlg.ui in mainwindow.cpp?

I have written a project which includes a mainwindow and a replacedlg.ui. I want to use replacedlg.ui in mainwindow.cpp.
I'd like to write things like ui->button in mainwindow.cpp, but I can't.
Who can help me make this work?
The whole project is here.
Don't try to share the ui variable between classes. It is bad design. Instead add methods in your classes which will let you do what you need to do.
In your case where you want to send the text of your line edit from replaceDlg class to your MainWindow class, you should use signals and slots. Here is an example:
#include <QtWidgets>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = Q_NULLPTR) : QMainWindow(parent)
{
setCentralWidget(&text_edit);
}
public slots:
void addText(const QString &text)
{
text_edit.append(text);
}
private:
QTextEdit text_edit;
};
class Dialog : public QDialog
{
Q_OBJECT
public:
Dialog(QWidget *parent = Q_NULLPTR) : QDialog(parent)
{
setLayout(new QHBoxLayout);
QPushButton *send_button = new QPushButton("Send");
layout()->addWidget(&line_edit);
layout()->addWidget(send_button);
connect(send_button, &QPushButton::clicked, this, &Dialog::sendButtonClicked);
}
signals:
void sendText(const QString &text);
private slots:
void sendButtonClicked()
{
emit sendText(line_edit.text());
accept();
}
private:
QLineEdit line_edit;
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
Dialog d;
QObject::connect(&d, &Dialog::sendText, &w, &MainWindow::addText);
w.show();
d.show();
return a.exec();
}
#include "main.moc"

declaring qtcpsocket class object as global

I am working on qt to develop a socket programming.i am posting the code here.
"mainwindow.h"
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
namespace Ui {
class MainWindow;
}
static void handler(int sig, siginfo_t *si, void *uc);
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
QTcpSocket *socket;
void timer();
void config();
private slots:
void newconnection();
private:
Ui::MainWindow *ui;
QTcpServer *server;
};
#endif // MAINWINDOW_H
"mainwindow.cpp"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
static char i;
ui->setupUi(this);
sock=socket;
// if(!i)
// {
// connect(ui->start_button,SIGNAL(clicked()),this,SLOT(config()));
// }
// i=1;
qDebug()<<i;
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow ::newconnection()
{
static int i;
socket=server->nextPendingConnection();
//connect(socket,SIGNAL(readyRead()),this,SLOT(timer_data_recieve()));
qDebug()<<"new connection";
qDebug()<<"server is reading..."<<socket->bytesAvailable();
qDebug()<<socket->readAll();
//time->start(1000); //QT timer started
if(!i)
timer();
i=1;
}
void MainWindow::timer()
{
timer_t t_id;
struct sigaction sa;
struct sigaction arg;
struct sigevent s_evnt;
struct itimerspec timer;
/* Establish handler for notification signal */
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = handler;
sigemptyset(&sa.sa_mask);
s_evnt.sigev_notify = SIGEV_SIGNAL;
s_evnt.sigev_signo = SIGRTMAX;
s_evnt.sigev_value.sival_ptr = &t_id;
if (sigaction(SIGRTMAX, &sa,NULL) == -1)
{
perror("sigaction");
}
//==============timer vlaues==============
timer.it_value.tv_sec=0;
timer.it_value.tv_nsec=20000000;
timer.it_interval.tv_sec=0;
timer.it_interval.tv_nsec=20000000;
if(timer_create(CLOCK_REALTIME,&s_evnt,&t_id)==-1);
perror("timer create");
if(timer_settime(t_id,0,&timer,NULL)==-1)
perror("timer_set_time");
}
void MainWindow::config()
{
//time=new QTimer(this);
server=new QTcpServer(this);
socket=new QTcpSocket(this);
connect(server,SIGNAL(newConnection()),this,SLOT(newconnection()));
// connect(time,SIGNAL(timeout()),this,SLOT(timer_data_sending()));
if(server->listen(QHostAddress::LocalHost,600))
{
qDebug()<<"server started";
}
else
qDebug()<<"server not started";
qDebug()<<MainWindow::server->errorString();
}
static void handler(int sig, siginfo_t *si, void *uc)
{
// MainWindow w;
qDebug("in handler");
// MainWindow *s = static_cast<MainWindow*>(&w);
static char first_call=1;
static unsigned sec;
static long nsec;
struct timespec start;
struct timespec curr;
if (first_call) {
first_call = 0;
if (clock_gettime(CLOCK_MONOTONIC, &start) == -1)
perror("clock_gettime");
}
if (clock_gettime(CLOCK_MONOTONIC, &curr) == -1)
perror("clock_gettime");
sec = (curr.tv_sec - start.tv_sec);
nsec = (curr.tv_nsec - start.tv_nsec);
if (nsec < 0)
{
sec--;
nsec += 1000000000;
}
start = curr;
}
"main.cpp"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
w.config();
return a.exec();
}
here evrything is working fine about handler.
but if want to access the handler data to socket to send to client,one way is to declare socket is global.but how to decalre globally to access in mainwindow member functions and as well as in handler?
please suggest me.it is very important to me .please don't avoid it.
NOTE:qtimer is not neded here
You can use Singletone Design Pattern architecture for your TCP Socket class. You need to create class that extends QTcpSocket. So you will create only one object and access the same globally using get_instance() method, as it is public static in this design pattern. You can go through Singleton design pattern
The documentation contains a good example about how to implement a Singleton and export it from C++ to QML.

Qt - How to get real size of maximized window that I have pointer to?

I have a method that get pointer to widget where should be setted some other widgets. I have to resize the main window, where that widget is placed and then I should get the real size of that widget.
I’ve tried to do this like:
void MyClass::setWidgets(QList<QWidget*> list, QWidget *parentWidget)
{
QWidget* mainWindow = parentWidget->window();
mainWindow->showMaximized();
int width = parentWidget->size().width();
int height = parentWidget->size().height();
/*... rest of method...*/
}
That method is call from other class.
But I read that I should wait for resizeEvent. Could anyone explain me how I should do this or if there is any option to get that size differently?
If you want to get events for a different object, you can install an event filter using QObject::installEventFilter.
A simple example for ResizeEvent is:
filter.hpp
#ifndef FILTER_HPP
#define FILTER_HPP
#include <QtGui>
class ResizeFilter : public QObject
{
Q_OBJECT
public:
ResizeFilter();
protected:
bool eventFilter(QObject *obj, QEvent *event);
};
#endif
filter.cpp
#include "filter.hpp"
ResizeFilter::ResizeFilter() : QObject() {}
bool ResizeFilter::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::Resize)
{
QResizeEvent* resizeEv = static_cast<QResizeEvent*>(event);
qDebug() << resizeEv->size();
}
return QObject::eventFilter(obj, event);
}
main.cpp
#include <QtGui>
#include "filter.hpp"
int main(int argc, char** argv)
{
QApplication app(argc, argv);
ResizeFilter filter;
QWidget window;
window.installEventFilter(&filter);
window.showMaximized();
return app.exec();
}
filter.pro
TEMPLATE = app
HEADERS = filter.hpp
SOURCES = main.cpp filter.cpp
When testing this on my PC it gave the output:
QSize(840, 420)
QSize(1280, 952)

QT hangs my toolbar and its buttons

I've created 2 classes, each:
has QWidget as a parent
has Q_OBJECT macros
inits some actions, creates menubar and toolbar, and connects actions to them
Then I created the main program file, created QMainWindow, and init my two classes by qmainwnd pointer.
And what I've got - menu works, the second toolbar works, but the first toolbar (created by class 1) doesn't respond to mouse clicks.
What happed with it? Why I can not even move this first toolbar or click its buttons?
Here a sample:
main.cpp
#include <QApplication>
#include <QMainWindow>
#include "CModDocument.h"
#include "CModEditor.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QMainWindow wnd;
// init CA
CModDocument a(&wnd);
// init CB
CModEditor b(&wnd);
wnd.show();
return app.exec();
}
CModDocument.h
#ifndef CMODDOCUMENT_H
#define CMODDOCUMENT_H
#include <QWidget>
QT_BEGIN_NAMESPACE
class QAction;
class QToolBar;
class QMainWindow;
QT_END_NAMESPACE
class CModDocument: public QWidget
{
Q_OBJECT
public:
CModDocument(QWidget *parent = 0);
QMainWindow *getMainWnd();
public slots:
void newFile();
void open();
bool save();
bool saveAs();
private:
void createActions();
void createToolBars();
void interCom();
QMainWindow *mainWnd;
QToolBar *fileToolBar;
QAction *newAct;
QAction *openAct;
QAction *saveAct;
QAction *saveAsAct;
};
#endif // CMODDOCUMENT_H
CModDocument.cpp
#include <QtGui>
#include <QDebug>
#include "CModDocument.h"
CModDocument::CModDocument( QWidget *parent )
: QWidget( parent )
, mainWnd( (QMainWindow*)parent )
{
createActions();
createToolBars();
interCom();
mainWnd->statusBar()->showMessage(tr("Ready"));
}
void CModDocument::newFile()
{
qDebug() << "newFile";
}
void CModDocument::open()
{
qDebug() << "open";
}
bool CModDocument::save()
{
qDebug() << "save";
bool retVal;
return retVal;
}
bool CModDocument::saveAs()
{
qDebug() << "saveAs";
bool retVal;
return retVal;
}
void CModDocument::createActions()
{
newAct = new QAction(tr("&New"), this);
newAct->setShortcuts(QKeySequence::New);
newAct->setStatusTip(tr("Create a new file"));
openAct = new QAction(tr("&Open..."), this);
openAct->setShortcuts(QKeySequence::Open);
openAct->setStatusTip(tr("Open an existing file"));
saveAct = new QAction(tr("&Save"), this);
saveAct->setShortcuts(QKeySequence::Save);
saveAct->setStatusTip(tr("Save the document to disk"));
saveAsAct = new QAction(tr("Save &As..."), this);
saveAsAct->setShortcuts(QKeySequence::SaveAs);
saveAsAct->setStatusTip(tr("Save the document under a new name"));
}
void CModDocument::createToolBars()
{
fileToolBar = mainWnd->addToolBar(tr("File"));
fileToolBar->addAction(newAct);
fileToolBar->addAction(openAct);
fileToolBar->addAction(saveAct);
}
void CModDocument::interCom()
{
connect(newAct, SIGNAL(triggered()), this, SLOT(newFile()));
connect(openAct, SIGNAL(triggered()), this, SLOT(open()));
connect(saveAct, SIGNAL(triggered()), this, SLOT(save()));
connect(saveAsAct, SIGNAL(triggered()), this, SLOT(saveAs()));
}
CModEditor.h
#ifndef CMODEDITOR_H
#define CMODEDITOR_H
#include <QWidget>
// #include "CModEdiWidget.h"
QT_BEGIN_NAMESPACE
class QMainWindow;
class QAction;
class QMenu;
class QMenuBar;
class QToolBar;
QT_END_NAMESPACE
class CModEditor : public QWidget
{
Q_OBJECT
public:
CModEditor(QWidget *parent = 0);
public slots:
void cut();
private:
void createActions();
void createToolBars();
void interCom();
QAction *cutAct;
QToolBar *editToolBar;
// parent
QMainWindow *mainWnd;
};
#endif
CModEditor.cpp
#include <QtGui>
#include <QDebug>
#include "CModEditor.h"
CModEditor::CModEditor(QWidget *parent)
: QWidget(parent)
, mainWnd( (QMainWindow*)parent )
{
createActions();
createToolBars();
interCom();
}
void CModEditor::cut()
{
qDebug() << "cut";
}
void CModEditor::createActions()
{
cutAct = new QAction(tr("Cu&t"), this);
cutAct->setShortcuts(QKeySequence::Cut);
cutAct->setStatusTip(tr("Cut the current selection's contents to the clipboard"));
}
void CModEditor::createToolBars()
{
editToolBar = mainWnd->addToolBar(tr("Edit"));
editToolBar->addAction(cutAct);
editToolBar->setIconSize(QSize(16, 16));
}
void CModEditor::interCom()
{
connect(cutAct, SIGNAL(triggered()), this, SLOT(cut()));
}
build.pro
CONFIG -= app_bundle
HEADERS = CModDocument.h CModEditor.h
SOURCES = CModDocument.cpp CModEditor.cpp main.cpp
The problem seems to be that you are trying to configure the QMainWindow as the parent to two QWidgets. I modified your main() function as follows and it worked:
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QMainWindow wnd;
QWidget w;
// init CA
CModDocument a(&wnd, &w);
// init CB
CModEditor b(&wnd, &w);
wnd.show();
return app.exec();
}
Notice the new QWidget w that parents a and b. I'm not even sure my approach is adequate (it probably isn't). I think it is better to add a QLayout to w and add a and b to that QLayout. Then you could set w as wnd's central widget.

Resources