QGraphicsTextItem mouseDoubleClickEvent - quartz-graphics

I am a new guy for QT. Now a question confuses me.
Code in the MainWindow as follows:
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
QGraphicsView *view = new QGraphicsView;
QGraphicsScene *scene =new QGraphicsScene;
GraphicsTextItem *item = (GraphicsTextItem*)scene->addText(QString("hello world"));
item->setPos(100,100);
scene->addItem(item);
QGraphicsItem *i = scene->itemAt(120,110);
view->setScene(scene);
view->show();
}
class GraphicsTextItem inherits QGraphicsTextItem and protected method mousePressDown is reimplemented as follows:
void GraphicsTextItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
{
qDebug()<<"mouseDoubleClickEvent happens";
QGraphicsTextItem::mouseDoubleClickEvent(event);
}
The application can works normally, but when I give the GraphicsTextItem object double click, nothing happens to the mouseDoubleClickEvent in class GraphicsTextItem.
Be expecting your response!

I searched my code and I developed an example, because I was left with the question but here it is:
#include <QGraphicsTextItem>
class GraphicsTextItem : public QGraphicsTextItem
{
Q_OBJECT
public:
GraphicsTextItem(QGraphicsItem * parent = 0);
protected:
void mouseDoubleClickEvent ( QGraphicsSceneMouseEvent * event );
};
implementation:
#include "graphicstextitem.h"
#include <QDebug>
#include <QGraphicsSceneMouseEvent>
GraphicsTextItem::GraphicsTextItem(QGraphicsItem * parent)
:QGraphicsTextItem(parent)
{
setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
}
void GraphicsTextItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
{
if (textInteractionFlags() == Qt::NoTextInteraction)
setTextInteractionFlags(Qt::TextEditorInteraction);
QGraphicsItem::mouseDoubleClickEvent(event);
}
the view
#include "mainwindow.h"
#include <QtGui>
#include <QtCore>
#include "graphicstextitem.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
QGraphicsScene * scene = new QGraphicsScene();
QGraphicsView * view = new QGraphicsView();
view->setScene(scene);
GraphicsTextItem * text = new GraphicsTextItem();
text->setPlainText("Hello world");
scene->addItem(text);
text->setPos(100,100);
text->setFlag(QGraphicsItem::ItemIsMovable);
setCentralWidget(view);
}
in this example you can interact with and change the text QGraphicsTextItem by doubleclick. I hope you will be helpful.

Related

Timers cannot be stopped from another thread Qt

I am working on Qt application. There I am using two threads, one for the GUI and one for do the processing.
I have worker class which has QTimer as member class.
.h file:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QTimer>
#include <QThread>
class Worker : public QObject
{
Q_OBJECT
public:
Worker();
QTimer t;
public slots:
void process();
void startWorker();
};
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
QThread workerThread;
Worker wt;
};
#endif // MAINWINDOW_H
cpp file
#include "mainwindow.h"
#include <QDebug>
#include <iostream>
Worker::Worker() : t(this)
{
connect(&t, SIGNAL(timeout()), this, SLOT(process()));
}
void Worker::process()
{
std::cout << "triggering timer" << std::endl;
}
void Worker::startWorker()
{
t.start(1000);
}
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
wt.moveToThread(&workerThread);
qDebug() << "worker thread " << wt.thread();
qDebug() << "timer thread " << wt.t.thread();
connect(&workerThread, SIGNAL(started()), &wt, SLOT(startWorker()));
connect(&workerThread, &QThread::finished, &workerThread, &QObject::deleteLater);
workerThread.start();
}
MainWindow::~MainWindow()
{
workerThread.quit();
workerThread.wait();
}
I can start the thread with no error. However when I close the application I am getting warning message.
QObject::killTimer: Timers cannot be stopped from another thread
QObject::~QObject: Timers cannot be stopped from another thread
If QTimer is child of worker class and it has been moved to thread why Qt is complaining about stopping it from different thread?
Note: I have added logs to print thread id and it outputs same value in both cases:
worker thread QThread(0x72fdf0)
timer thread QThread(0x72fdf0)
Can someone please explain? I do not understand what it's happening here
Thanks in advance
I finally was able to fix the error by:
Converting QTimer to pointer
Adding slot stopWorker as suggested by #Amfasis
In that slot not only stop QTimer but also delete it
Thanks all
You should stop the timer before QObject deletes it itself
in .h file, add the destructor:
class Worker : public QObject
{
Q_OBJECT
public:
Worker();
~Worker();
private:
QTimer t;
public slots:
void process();
void startWorker();
void stopWorker(); //this line was added
};
in .cpp file, add:
Worker::stopWorker()
{
t.stop();
}
and in constructor
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
...
connect(&workerThread, &QThread::finished, &wt, &Worker::stopWorker); //add this line!
...
}
You should new your timer in your task object slot, not in the task construtor. Stop the timer when your task object is deleted.
My task object header: Worker.h
#pragma once
#include <QObject>
class QTimer;
class Worker : public QObject
{
Q_OBJECT
public:
explicit Worker(QObject *parent = nullptr);
~Worker();
public slots:
void WorkerTaskStartSlot(void);
void TaskFinished(void);
private slots:
void TimerOutToDoSomethingSlot(void);
signals:
void WorkertResultSig(void);
private:
QTimer *m_pTimer = nullptr;
};
Worker.cpp:
#include "Worker.h"
#include <QDebug>
#include <QThread>
#include <QTimer>
Worker::Worker(QObject *parent) : QObject(parent)
{
qDebug()<<__FUNCTION__<<"threadid"<< QThread::currentThreadId();
}
Worker::~Worker()
{
TaskFinished();
qDebug()<<__FUNCTION__<<"threadid"<< QThread::currentThreadId();
}
void Worker::WorkerTaskStartSlot(void)
{
qDebug()<<__FUNCTION__<<"threadid"<< QThread::currentThreadId();
emit WorkertResultSig();
m_pTimer = new QTimer(this);
connect(m_pTimer,&QTimer::timeout,this,&Worker::TimerOutToDoSomethingSlot);
m_pTimer->start(1000);
}
void Worker::TaskFinished(void)
{
qDebug()<<__FUNCTION__<<"threadid"<< QThread::currentThreadId();
if(m_pTimer)
{
if(m_pTimer->isActive())
{
m_pTimer->stop();
qDebug()<<__FUNCTION__<<"stop timer"<< QThread::currentThreadId();
}
delete m_pTimer;
m_pTimer = nullptr;
}
}
void Worker::TimerOutToDoSomethingSlot(void)
{
qDebug()<<__FUNCTION__<<"threadid"<< QThread::currentThreadId();
}
The controller header: MainWindow.h
#pragma once
#include <QMainWindow>
class QPushButton;
class QWidget;
class Worker;
class QThread;
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
void InitCtrl(void);
private slots:
void StartTaskBtnSlot(const bool &checked);
void WorkertResultSlot(void);
private:
QPushButton *m_pStartTaskBtn = nullptr;
QWidget *m_pCenterWidget = nullptr;
Worker *m_pWorker = nullptr;
QThread *m_pWorkerThread = nullptr;
};
MainWindow.cpp
#include "MainWindow.h"
#include <QVBoxLayout>
#include <QPushButton>
#include <QWidget>
#include <QDebug>
#include <QThread>
#include "Worker.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
InitCtrl();
qDebug()<<__FUNCTION__<<"mainwindow thread id"<< QThread::currentThreadId();
}
MainWindow::~MainWindow()
{
}
void MainWindow::InitCtrl(void)
{
m_pCenterWidget = new QWidget(this);
m_pStartTaskBtn = new QPushButton(QStringLiteral("Start"),this);
QVBoxLayout *pvertlayout = new QVBoxLayout();
pvertlayout->addWidget(m_pStartTaskBtn);
m_pCenterWidget->setLayout(pvertlayout);
setCentralWidget(m_pCenterWidget);
m_pStartTaskBtn->setCheckable(true);
connect(m_pStartTaskBtn,&QPushButton::clicked,this,&MainWindow::StartTaskBtnSlot);
}
void MainWindow::StartTaskBtnSlot(const bool &checked)
{
if(checked)
{
m_pStartTaskBtn->setText(QStringLiteral("Close"));
m_pWorkerThread = new QThread();
m_pWorker = new Worker();
// move the task object to the thread BEFORE connecting any signal/slots
m_pWorker->moveToThread(m_pWorkerThread);
connect(m_pWorkerThread, SIGNAL(started()), m_pWorker, SLOT(WorkerTaskStartSlot()));
connect(m_pWorker, SIGNAL(WorkertResultSig()), this, SLOT(WorkertResultSlot()));
// automatically delete thread and task object when work is done:
connect(m_pWorkerThread, SIGNAL(finished()), m_pWorker, SLOT(deleteLater()));
connect(m_pWorkerThread, SIGNAL(finished()), m_pWorkerThread, SLOT(deleteLater()));
m_pWorkerThread->start();
}
else
{
m_pStartTaskBtn->setText(QStringLiteral("Start"));
m_pWorkerThread->quit();
m_pWorkerThread->wait();
}
}
void MainWindow::WorkertResultSlot(void)
{
qDebug()<<__FUNCTION__<<"threadid"<<QThread::currentThreadId();
}
Finally, it will output result like this:
MainWindow::MainWindow mainwindow thread id 0x2bf0
Worker::Worker threadid 0x2bf0
Worker::WorkerTaskStartSlot threadid 0x4af0
MainWindow::WorkertResultSlot threadid 0x2bf0
Worker::TimerOutToDoSomethingSlot threadid 0x4af0
Worker::TimerOutToDoSomethingSlot threadid 0x4af0
Worker::TimerOutToDoSomethingSlot threadid 0x4af0
Worker::TimerOutToDoSomethingSlot threadid 0x4af0
Worker::TaskFinished threadid 0x4af0
Worker::TaskFinished stop timer 0x4af0
Worker::~Worker threadid 0x4af0

Qt serial communication using UART RS232C

I want to connect qt and a device using UART cable (RS232C) in linux.
I´m writing code, making ui and operating, but it does not work.
I want to connect when i click some button(ui) device turn on and connect.
Also i want to make a function that if i enter some command device will recognize and execute.
Below is my code , someone help me please.
<mainwindow.cpp>
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QtSerialPort/QSerialPort>
#include <QMessageBox>
#include <QObject>
#include <QIODevice>
#include <QDebug>
QSerialPort serial;
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
QSerialPort*port=new QSerialPort();
port->setPortName("/dev/ttyUSB0");
port->setBaudRate(QSerialPort::Baud19200);
port->setDataBits(QSerialPort::Data8);
port->setParity(QSerialPort::NoParity);
port->setStopBits(QSerialPort::OneStop);
port->setFlowControl(QSerialPort::NoFlowControl);
port->open(QIODevice::ReadWrite);
ui->setupUi(this);
serial = new QSerialPort(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_connect_clicked()
{
port=new QSerialPort();
QObject::connect(port,SIGNAL(readyRead()),this,
SLOT(on_pushButton_connect_clicked()));
if(!port->open(QIODevice::ReadWrite)){
QMessageBox::information(this, tr("connect"),
"serialcommunication start");
}
else
{
QMessageBox::critical(this, tr("fail"), serial-
>errorString());
}
}
void MainWindow::on_pushButton_disconnect_clicked()
{
port->close();
QMessageBox::information(this, tr("disconnect"), "serial
communication end");
}
<mainwindow.h>
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QtSerialPort/QSerialPort>
#include <QMessageBox>
#include <QIODevice>
#include <QDebug>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
QSerialPort*serial; //plus
QSerialPort*port;
QWidget*main_widget;
void readData();
~MainWindow();
private slots:
void on_pushButton_connect_clicked();
void on_pushButton_disconnect_clicked();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
<main.cpp>
#include "mainwindow.h"
#include <QApplication>
#include <QSerialPort>
#include <QSerialPortInfo>
#include <QDebug>
#include <QMessageBox>
#include <QIODevice>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
foreach(const QSerialPortInfo
&info,QSerialPortInfo::availablePorts()){
QSerialPort serial;
serial.setPort(info);
if (serial.open(QIODevice::ReadWrite))
serial.close();
}
MainWindow w;
w.show();
return a.exec();
}
First of all it is not guaranteed that your device will be always connected to /dev/ttyUSB0 so you'l better search for your device by QSerialPortInfo with parameter
QString manufacturer() const or quint16 productIdentifier() const or QString serialNumber() const.
Also you are creating too many QSerialPort and don't handle it. Create just one.
Here is sample code:
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
class QSerialPort;
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
//! Receives all the data from serial port
void readSerialData();
void on_pushButton_connect_clicked();
void on_pushButton_disconnect_clicked();
private:
Ui::MainWindow *ui;
QSerialPort *mSerialPort;
};
#endif // MAINWINDOW_H
Next check your Your product manufacturer or serial number and set here.
Also you need separate handler for received data like I created readSerialData
mainwindows.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QSerialPort>
#include <QSerialPortInfo>
#include <QMessageBox>
#include <QDebug>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow),
mSerialPort{new QSerialPort}
{
ui->setupUi(this);
mSerialPort->setBaudRate(QSerialPort::Baud19200);
mSerialPort->setDataBits(QSerialPort::Data8);
mSerialPort->setParity(QSerialPort::NoParity);
mSerialPort->setStopBits(QSerialPort::OneStop);
mSerialPort->setFlowControl(QSerialPort::NoFlowControl);
connect(mSerialPort, SIGNAL(readyRead()), this, SLOT(readSerialData()));
}
MainWindow::~MainWindow()
{
delete mSerialPort;
delete ui;
}
void MainWindow::readSerialData()
{
QByteArray lTmpBA;
lTmpBA = mSerialPort->readAll();
qDebug() << "Received data: " << lTmpBA;
}
void MainWindow::on_pushButton_connect_clicked()
{
foreach(QSerialPortInfo item, QSerialPortInfo::availablePorts()) {
if (item.manufacturer() == "Your product") { //past your manufacturer here
mSerialPort->setPort(item);
if(!mSerialPort->open(QIODevice::ReadWrite)){
QMessageBox::information(this, tr("connect"),
"serialcommunication start");
} else {
QMessageBox::critical(this, tr("fail"), mSerialPort->errorString());
}
} else {
qDebug() << "No connected device found";
}
}
}
void MainWindow::on_pushButton_disconnect_clicked()
{
mSerialPort->close();
}
latter if you want to send some data to your UART device just implemente slot and call method:
mSerialPort->write("Some command");

Qt start an external program in Qt gridLayout

I was wondering, is it possible to start an external program via Qt and display the program in Qt gridLayout (or inside Qt window)?
At the moment, I'm able to start an external program via Qt, but I haven't find a way to display the program inside the QtWindow. In other words, the program just appear outside Qt window.
Qt Pro file
#-------------------------------------------------
#
# Project created by QtCreator 2016-09-21T16:31:30
#
#-------------------------------------------------
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = WifiProject
TEMPLATE = app
SOURCES += main.cpp\
mainwindow.cpp
HEADERS += mainwindow.h
FORMS += mainwindow.ui
Main window .h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QtNetwork/QNetworkConfigurationManager>
#include <QtNetwork/QNetworkSession>
#include <QtNetwork/QNetworkInterface>
#include <QDebug>
#include <QList>
#include <QProcess>
#include <QWidget>
#include <QBoxLayout>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_StartWicd_clicked();
private:
Ui::MainWindow *ui;
void searchForNetwork();
QProcess *wicdProgram;
void addWicdProgram();
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QWindow>
QString program = "/usr/bin/wicd-gtk";
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
searchForNetwork();
addWicdProgram();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::searchForNetwork(){
}
void MainWindow::addWicdProgram(){
wicdProgram = new QProcess(this);
wicdProgram->setProgram(program);
WId winid = this->winId();
QWindow *container = QWindow::fromWinId(winid);
QWidget *program_start = createWindowContainer(container);
setCentralWidget(program_start);
ui->wifiGridLayout->addWidget(program_start);
wicdProgram->start();
qDebug()<<"wicd addded";
//ui->wifiGridLayout->addWidget(program_start);
}
void MainWindow::on_StartWicd_clicked()
{
//wicdProgram->start(program);
qDebug()<<"the wicd should have started";
wicdProgram->terminate();
}
A solution is to retrieve the window id of the application launch by qt and you can do like this :
QWindow *window = QWindow::fromWinId("Id of the application");
window->setFlags(Qt::FramelessWindowHint);
QWidget *widget = QWidget::createWindowContainer(window);

How to use signals & slots in Qt for inter-threading communication

I want to make an application where the user will hit a QPushButton and this will trigger a secondary thread which will add some text to a QListWidget in the main window. But for a reason that I cannot figure out ,although the signal from the thread to the main window is emitted it never reaches the destination. Probably because the connection fails. But why this happens here is my code(my application is compiled using Visual Studio 2010):
mythread.h
#ifndef MY_THREAD_H
#define MY_THREAD_H
#include <QThread>
#include <QString>
class mythread:public QThread
{
Q_OBJECT
public:
void setName(QString& name);
signals:
void sendMsg(QString& msg);
protected:
void run();
private:
QString m_name;
QString msg;
};
#endif
mythread.cpp
#include "mythread.h"
void mythread::setName(QString& name)
{
m_name=name;
}
void mythread::run()
{
msg="Hello "+m_name;
emit sendMsg(msg);
}
mydialog.h:
#ifndef MY_DIALOG_H
#define MY_DIALOG_H
#include <QtGui>
#include "mythread.h"
class mydialog:public QDialog
{
Q_OBJECT
public:
mydialog();
public slots:
void receiveMsg(QString& msg);
void fillList();
private:
QListWidget list1;
QPushButton btn1;
QGridLayout layout;
mythread thread;
};
#endif
mydialog.cpp:
#include "mydialog.h"
mydialog::mydialog()
{
layout.addWidget(&list1,0,0);
btn1.setText("Find");
layout.addWidget(&btn1,0,1);
setLayout(&layout);
QString myname="leonardo";
thread.setName(myname);
connect(&btn1,SIGNAL(clicked()),this,SLOT(fillList()));
connect(&thread,SIGNAL(sendMsg(QString&)),this,SLOT(receiveMsg(Qstring&)));
}
void mydialog::fillList()
{
thread.start();
}
void mydialog::receiveMsg(QString& msg)
{
list1.addItem(msg);
}
find.cpp:
#include <QApplication>
#include "mydialog.h"
int main(int argc,char* argv[])
{
QApplication app(argc,argv);
mydialog window;
window.setWindowTitle("Find");
window.show();
return app.exec();
}
find.pro:
TEMPLATE = app
TARGET =
DEPENDPATH += .
INCLUDEPATH += .
# Input
HEADERS += mydialog.h mythread.h
SOURCES += find.cpp mydialog.cpp mythread.cpp
Two things:
In your second connect call, Qstring must be changed to QString
Qt cannot deliver QString& accross threads by default. There's two ways to fix this:
Change your Signals and Slots and the connect to use QString rather than QString&
Use qRegisterMetaType in order to make QString& usable.
I still recommend reading
https://www.qt.io/blog/2010/06/17/youre-doing-it-wrong
and Kari's comment
https://www.qt.io/blog/2010/06/17/youre-doing-it-wrong#commento-comment-name-a6fad43dec11ebe375cde77a9ee3c4331eb0c5f0bcac478ecbe032673e8ebc82
when working with threads, though.
First of all use const qualifier for arguments if you're not planning to modify it. After fixing typo in connection SLOT(receiveMsg(Qstring&)) and changing signals and slots signature to const references everything works fine

VC++ does not show output

I am new to VC++ and its been a few times now, and this is the third program that does not give output even after it is build succesfully.
#include <AFXWIN.H>
#include <math.h>
#define PI 3.1415926
#define SEGMENTS 500
class CMyApp : public CWinApp {
public:
virtual BOOL InitInstance();
};
class CMainWindow : public CFrameWnd
{
public:
CMainWindow();
protected:
afx_msg void OnPaint();
afx_msg void OnLButtonDown(UINT, CPoint);
DECLARE_MESSAGE_MAP();
};
CMyApp myAPP;
BOOL CMyApp::InitInstance() {
m_pMainWnd = new CMainWindow;
m_pMainWnd->ShowWindow(SW_MAXIMIZE);
m_pMainWnd->UpdateWindow();
return TRUE;
}
BEGIN_MESSAGE_MAP (CMainWindow, CFrameWnd)
ON_WM_PAINT ()
END_MESSAGE_MAP ()
CMainWindow::CMainWindow() {
Create(NULL,"The Hello Application",WS_OVERLAPPEDWINDOW);
}
void CMainWindow::OnPaint() {
CRect rect;
int nWidth = rect.Width();
int nHeight = rect.Height();
CPaintDC dc (this);
CPoint aPoint[SEGMENTS];
for (int i =0; i < SEGMENTS; i++){
aPoint[i].x = ((i*nWidth)/SEGMENTS );
aPoint[i].y= (int)((nHeight/2)* (1-(sin((2*PI*i)/SEGMENTS))));
}
dc.Polyline(aPoint, SEGMENTS);
UpdateData(false);
}
The above program should give Sine curve as the output, except that I get a blank window. And I don't know why does it happen. If it helps, I am using VC++ 6.0
The problem is probably that the rectangle you use to get the width and height is not initialized. You have to get the rectangle from somewhere, see e.g. CWnd::GetClientRect.

Resources