(Qt)I want to know why the if statement won't be excuted - qt

I want to make a simple timer by Qt. When I want to implement pause and resume functionality,it seemed that the if statement in void Widget::on_Pause_clicked()didn't work .
widget.h:
#include <QWidget>
#include <QTimer>
#include <QTime>
#include <QString>
#include <QLCDNumber>
#include <QMouseEvent>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
private:
Ui::Widget *ui;
QLCDNumber *lcd;
QTimer *ptime;
QTime *timerecord;
QPoint windowPos;
QPoint mousePos;
QPoint dPos;
bool isStart;
public:
Widget(QWidget *parent = nullptr);
~Widget();
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
private slots:
void on_Start_clicked();
void updatetime();
void initTime();
void on_Pause_clicked();
void on_Clear_clicked();
public slots:
};
widget.cpp:
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
ptime = new QTimer;
timerecord = new QTime;
ui->Timer->setDigitCount(11);
initTime();
connect(ptime,SIGNAL(timeout()),this,SLOT(updatetime()));
this->setWindowFlags(Qt::FramelessWindowHint);//remove system border
isStart=false;//determine if the timer is running
ui->Start->setEnabled(true);
ui->Pause->setEnabled(false);
ui->Clear->setEnabled(false);
}
Widget::~Widget()
{
delete ui;
}
void Widget::initTime()
{
timerecord->setHMS(0, 0, 0);
ui->Timer->display(timerecord->toString("mm:ss:zzz "));
}
void Widget::updatetime()
{
*timerecord = timerecord->addMSecs(1);
ui->Timer->display(timerecord->toString("mm:ss:zzz "));
}
void Widget::on_Start_clicked()//when the start button is clicked
{
ptime->start(1);
isStart=true;
ui->Start->setEnabled(false);
ui->Pause->setEnabled(true);
ui->Clear->setEnabled(false);
}
void Widget::on_Pause_clicked()//when the pause button is clicked
{
if(isStart == true)
{
ptime->stop();
ui->Pause->setText("继续");
isStart=false;
ui->Start->setEnabled(false);
ui->Pause->setEnabled(true);
ui->Clear->setEnabled(true);
}
if(isStart == false)
{
ptime->start(1);
ui->Pause->setText("暂停");
isStart=true;
ui->Start->setEnabled(false);
ui->Pause->setEnabled(true);
ui->Clear->setEnabled(false);
}
}
void Widget::on_Clear_clicked()
{
ptime->stop();
initTime();
ui->Start->setEnabled(true);
ui->Pause->setEnabled(false);
ui->Clear->setEnabled(false);
}
void Widget::mousePressEvent(QMouseEvent *event)//make the window movable
{
this->windowPos = this->pos();
this->mousePos = event->globalPos();
this->dPos = mousePos - windowPos;
}
void Widget::mouseMoveEvent(QMouseEvent *event)//make the window movable
{
this->move(event->globalPos() - this->dPos);
}

In your code:
void Widget::on_Pause_clicked()//when the pause button is clicked
{
if(isStart == true)
{
ptime->stop();
ui->Pause->setText("继续");
isStart=false;
ui->Start->setEnabled(false);
ui->Pause->setEnabled(true);
ui->Clear->setEnabled(true);
}
if(isStart == false)
{
ptime->start(1);
ui->Pause->setText("暂停");
isStart=true;
ui->Start->setEnabled(false);
ui->Pause->setEnabled(true);
ui->Clear->setEnabled(false);
}
}
if isStart starts out to be true, then it enters the first if condition block. Within it, isStart becomes false.
However, when it exits that block, it hits the if (isStart == false) block and since isStart is false, therefore it goes into that block and changes isStart to true.
What you should do (bear in mind my qT is rusty):
void Widget::on_Pause_clicked()//when the pause button is clicked
{
if(isStart == true)
{
ptime->stop();
ui->Pause->setText("继续");
isStart=false;
ui->Start->setEnabled(false);
ui->Pause->setEnabled(true);
ui->Clear->setEnabled(true);
} else {
ptime->start(1);
ui->Pause->setText("暂停");
isStart=true;
ui->Start->setEnabled(false);
ui->Pause->setEnabled(true);
ui->Clear->setEnabled(false);
}
}

Related

MouseMoveEvent stops being called

I'm using QCustomPlot (plot_ object) on QQuickPaintedItem (SinePlot class) so I can use it in QML. In mousePressEvent I collect initial point and in mouseMoveEvent I'm making calculations to add new points and updating cursor point:
void SinePlot::mousePressEvent(QMouseEvent* event)
{
prevPoint_ = event->globalPos();
}
void SinePlot::mouseMoveEvent(QMouseEvent* event)
{
QPointF tmp = event->globalPos();
qreal prop = (prevPoint_.x() - tmp.x()) / width();
if(prop > 0)
{
data_->shiftLeft(prop);
} else {
data_->shiftRight(prop);
}
plot_->xAxis->setRange(data_->minX, data_->maxX);
...
prevPoint_ = tmp;
update();
}
I have also trying to use pos() and localPos() but it does not make any difference, here is what I got:
As you can see mouseMoveEvent stops being called after some time(before releasing) and moving cursor does not call it.
Here is minimal reproducible example:
#ifndef SINEPLOT_H
#define SINEPLOT_H
#include "qcustomplot.h"
#include <QtQuick>
#include <QDebug>
class SinePlot : public QQuickPaintedItem
{
Q_OBJECT
public:
explicit SinePlot(QQuickItem* parent=nullptr)
{
setAcceptedMouseButtons(Qt::AllButtons);
plot_ = new QCustomPlot();
plot_->setInteractions(QCP::iRangeDrag);
plot_->addGraph();
}
virtual ~SinePlot()
{
delete plot_;
}
void paint(QPainter* painter)
{
QPicture picture;
QCPPainter qcpPainter;
qcpPainter.begin(&picture);
plot_->toPainter(&qcpPainter, width(), height());
qcpPainter.end();
picture.play(painter);
};
protected:
virtual void mousePressEvent(QMouseEvent* event) {};
virtual void mouseMoveEvent(QMouseEvent* event)
{
qDebug() << "mouse move";
};
private:
QCustomPlot* plot_;
};
#endif
In my case I got "mouse move" ~10 times.

Color channels are changing using Qt QImage with data and I don't know why

I have written a function in Qt to extract the data out of an image for the purpose of manipulating it.
I then have another function to reinsert the data back to an image and display it. The problem I am having is that even if I do no manipulation on the pixel data other than extract and reinsert, it is still changing the data. On a yellow image it changes it to turquoise blue when it should remain yellow.
I am including the function code to extract and reinsert as specimen code. I can include more if it is needed such as the display function etc...Does anyone know if I am doing something wrong?
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
filter = "All Picture Files (*.png *.jpg *.jpeg *.bmp *.tif *.tiff)"
";; Bitmap Files (*.bmp) ;; JPEG (*.jpg *.jpeg) ;; PNG (*.png) ;; TIFF (*.tif *.tiff)";
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::importImage()
{
importCancelled = false;
QString filename = QFileDialog::getOpenFileName(nullptr, QObject::tr("Import Image"), "", filter);
if(!filename.isEmpty()){
image.load(filename);
image = image.convertToFormat(QImage::Format_RGBA8888);
}
else {
importCancelled = true;
if(importCancelled){
QString cleanPlateCancelled = "Operation Cancelled";
ui->statusBar->showMessage(cleanPlateCancelled,5000);
return;
}
}
}
void MainWindow::scaleImage()
{
if (image.isNull()){
return;
}
else {
image = image.scaledToHeight(ui->view->height(), Qt::TransformationMode::SmoothTransformation);
}
}
void MainWindow::displayImage()
{
if (image.isNull()){
return;
}
else {
scene = new QGraphicsScene;
showImage = new QGraphicsPixmapItem(QPixmap::fromImage(image));
scene->addItem(showImage);
ui->view->setScene(scene);
}
}
void MainWindow::rgbaExtraction()
{
numberOfBytes = static_cast<uint>(image.sizeInBytes());
auto const imageData = image.bits();
rgba = std::vector<uchar>(numberOfBytes,0);
rgbaReset = std::vector<uchar>(numberOfBytes,0);
for (uint i{0}; i < numberOfBytes; ++i) {
rgbaReset[i] = rgba[i] = imageData[i];
}
}
void MainWindow::rgbaInsertion()
{
auto *imageData = new uchar[numberOfBytes];
for (uint i{0};i < numberOfBytes;++i) {
imageData[i] = rgba[i];
}
image = QImage(imageData, image.width(), image.height(), QImage::Format_RGBA8888);
}
void MainWindow::on_importButton_clicked()
{
importImage();
scaleImage();
displayImage();
rgbaExtraction();
}
void MainWindow::on_quitButton_clicked()
{
QApplication::quit();
}
void MainWindow::sceneUpdater()
{
showImage->setPixmap(QPixmap::fromImage(image));
scene->update();
ui->view->update();
}
void MainWindow::on_redSlider_valueChanged(int value)
{
QString redString = QString::number(value);
ui->redLabel->setText(redString);
redDelta = value;
colorRed();
rgbaInsertion();
sceneUpdater();
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QDebug>
#include <QImage>
#include <QFileDialog>
#include <string>
#include <QGraphicsScene>
#include <QGraphicsPixmapItem>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_importButton_clicked();
void on_quitButton_clicked();
void on_redSlider_valueChanged(int value);
private:
QGraphicsPixmapItem *showImage;
QGraphicsScene *scene;
QString filter;
QImage image;
bool importCancelled;
QStatusBar *statusBar;
uint numberOfBytes;
std::vector<uchar> rgba;
std::vector<uchar> rgbaReset;
int redDelta{0};
int greenDelta{0};
int blueDelta{0};
int opacityDelta{0};
void importImage();
void scaleImage();
void displayImage();
void rgbaExtraction();
void rgbaInsertion();
void sceneUpdater();
void colorRed(); // Implemented in color.cpp
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
color.cpp
#include <mainwindow.h>
void MainWindow::colorRed()
{
for (uint i{0}; i < rgba.size()*sizeof (rgba[i]);i+=4) {
if(rgbaReset[i] + static_cast<uchar>(redDelta)>=255){
rgba[i] = 255;
}
else {
rgba[i] = rgbaReset[i];// + static_cast<uchar>(redDelta);
}
}
}
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
The problem is in scaleImage(), because scaledToHeight() returns another image format. You may omit the scale operation, or convert the returned image to Format_RGBA8888:
void MainWindow::scaleImage()
{
if (image.isNull()){
return;
}
else {
image = image.scaledToHeight(ui->view->height(), Qt::TransformationMode::SmoothTransformation)
.convertToFormat(QImage::Format_RGBA8888);
}
}
My recomendation is to add some instrumentation after each image manipulation to check that it has the expected format:
qDebug() << Q_FUNC_INFO << "image format:" << image.format();

Qt: how to apply a 2-step key shortcut to action

I know how to apply a keyboard shortcut to an action. And in some software such as Visual Studio there are shortcuts that do the job in more than one step (such as Ctrl+K,Ctrl+C to comment the code).
Another example of that in Sublime Text:
I wonder whether or not it is possible to implement in Qt.
You can create it by using the multiple arguments constructor for QKeySequence.
like this:
auto ac = new QAction(this);
ac->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_K, Qt::CTRL + Qt::Key_C));
Try this:
action->setShortcut("Ctrl+K,Ctrl+C");
QKeySequence may be implicitly created from QString.
Due to documentation:
Up to four key codes may be entered by separating them with commas, e.g. "Alt+X,Ctrl+S,Q".
MOC generates almost same code when you create shortcut for a QAction via Qt Designer. But it makes it slightly different:
action->setShortcut(QApplication::translate("MainWindow", "Ctrl+K, Ctrl+C", 0));
but it's actually same thing.
You can use eventFilter to get mouse & keyboard events.
I use boolean to get first and second key, Ctrl + K then C.
I made you a sample code it's working.
.cpp file:
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
firstKey = false;
secondKey = false;
this->installEventFilter(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
bool MainWindow::eventFilter(QObject *object, QEvent *event)
{
if (object == this &&event->type() == QEvent::KeyPress)
{
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
if ((keyEvent->key() == Qt::Key_Control))
{
firstKey = true;
return true;
}
else if ((keyEvent->key() == Qt::Key_K))
{
secondKey = true;
return true;
}
else if ((keyEvent->key() == Qt::Key_C))
{
if(firstKey && secondKey)
{
firstKey = false;
secondKey = false;
QMessageBox::information(this, "", "Ctrl + k + c");
}
return true;
}
else
return false;
}
else
return false;
}
void MainWindow::keyReleaseEvent(QKeyEvent *e)
{
if (e->type() == QEvent::KeyRelease)
{
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(e);
if ((keyEvent->key() == Qt::Key_Control))
{
firstKey = false;
}
}
}
.h file:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QDebug>
#include <QMessageBox>
#include <QKeyEvent>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
bool firstKey;
bool secondKey;
bool eventFilter(QObject *object, QEvent *event);
void keyReleaseEvent(QKeyEvent *e);
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H

QMessagebox not show text when call show()

my problem is I need to show a message ask users wait when I check network availability of other clients.My way is I have a class workerThread to do the business, before start it I create a qMessageBox. But the message only shows the title, not the content. I have no idea why, pls help :(
Here's the worker thread:
#include <QObject>
#include <QString>
#include "clientdataobj.h"
class WorkerThread : public QObject
{
Q_OBJECT
public:
explicit WorkerThread(QObject *parent = 0);
QList<ClientDataObj> listClient() const;
void setListClient(const QList<ClientDataObj> &listClient);
signals:
void finished();
void error(QString err);
void listClientPingChecked( QList <ClientDataObj> list);
public slots:
void testPing();
private:
QList <ClientDataObj> mListClient;
bool pingEachClient(QString ip);
};
implement:
#include "workerthread.h"
#include <QFile>
#include <QMessageBox>
#include <QTextStream>
WorkerThread::WorkerThread(QObject *parent) :
QObject(parent)
{
}
void WorkerThread::testPing()
{
if (mListClient.size()==0) {
emit finished();
return;
}
else{
for(unsigned i=0;i<mListClient.size();i++){
bool result = pingEachClient(mListClient[i].ip());
if(result)
mListClient[i].setStatus(true);
else
mListClient[i].setStatus(false);
}
emit listClientPingChecked(mListClient);
}
emit finished();
}
bool WorkerThread::pingEachClient(QString ip)
{
QString pingCommand = "ping " +ip + " -c 3 | grep loss | awk ' {print $7}' > pingResult.txt";
system(qPrintable(pingCommand));
QString lossPercentTxt = readFileText("pingResult.txt") ;
lossPercentTxt.chop(1);
int lossPercent = lossPercentTxt.toInt();
if(lossPercent<10){
return true;
}
else return false;
}
QList<ClientDataObj> WorkerThread::listClient() const
{
return mListClient;
}
void WorkerThread::setListClient(const QList<ClientDataObj> &listClient)
{
mListClient = listClient;
}
How I call it in MainWindow:
on_pbSendUpdate_clicked()
{
changeModeWaitPing();
getClientOnlineList();
}
getClientOnlineList()
{
if(mListClient.size()==0){
return;
}
mpThreadPing = new QThread;
mpWorkerThread = new WorkerThread;
mpWorkerThread->setListClient(mListClient);
connectThreadPingToGui();
mpThreadPing->start();
}
changeModeWaitPing()
{
ui->pbSendUpdate->setEnabled(false);
callMsgBox("Pinging client... Pls wait!");
// callWaitDialog();
}
callMsgBox( QString text)
{
if (NULL==mMsg) {
return;
}
mMsg->setWindowTitle("INFO");
// mMsg->setAttribute(Qt::WA_DeleteOnClose);
mMsg->setWindowModality(Qt::NonModal);
mMsg->setModal(false);
QString info ="Pinging client... Pls wait!";
mMsg->setText(info);
mMsg->show();
}
connectThreadPingToGui()
{
connect(mpWorkerThread, SIGNAL(error(QString)), this, SLOT(errorString(QString)));
connect(mpThreadPing, SIGNAL(started()), mpWorkerThread, SLOT(testPing()));
connect(mpWorkerThread, SIGNAL(finished()), mpThreadPing, SLOT(quit()));
connect(mpWorkerThread, SIGNAL(finished()), mpWorkerThread, SLOT(deleteLater()));
connect(mpThreadPing, SIGNAL(finished()), mpThreadPing, SLOT(deleteLater()));
connect(mpWorkerThread,SIGNAL(listClientPingChecked(QList<ClientDataObj>)),this,SLOT(updateListClientOnline(QList<ClientDataObj>)));
}
updateListClientOnline(QList<ClientDataObj> list)
{
mListClientOnline = list;
mPingDone = true;
if (NULL==mMsg) {
return;
}
else{
mMsg->hide();
}
if(mpDialogWaitPing==NULL){
return;
}
else{
mpDialogWaitPing->hide();
}
launchClientListTable();
}
You create a new thread, but you don't move any objects to that thread. So your new thread does nothing. I assume you wan't mpWorkerThread to be moved to the new thread. In that case you're missing mpWorkerThread->moveToThread(mpThreadPing);

Movable QRubberband from one point to another

I have drawn a QRubberband on QLabel. i can resize it using QSizeGrip. Now I want to move it from one point to another using QMouseevents. Is there any one who can help me out.
void CropImage::mousePressEvent(QMouseEvent *event)
{
QLabel::mousePressEvent(event);
lastPoint = event->pos();
rubberband = new QRubberBand(QRubberBand::Rectangle,this);
rubberband->setGeometry(QRect(lastPoint, QSize()));
rubberband->show();
}
void CropImage::mouseReleaseEvent(QMouseEvent *event)
{
newPoint = event->pos();
}
this is my subclass part which is used for mouse events. the code is as following:
Resizable_rubber_band::Resizable_rubber_band(QWidget *parent) : QWidget(parent)
{
//tell QSizeGrip to resize this widget instead of top-level window
setWindowFlags(Qt::SubWindow);
QHBoxLayout* layout = new QHBoxLayout(this);
layout->setContentsMargins(0, 0, 0, 0);
QSizeGrip* grip1 = new QSizeGrip(this);
QSizeGrip* grip2 = new QSizeGrip(this);
layout->addWidget(grip1, 0, Qt::AlignLeft | Qt::AlignTop);
layout->addWidget(grip2, 0, Qt::AlignRight | Qt::AlignBottom);
rubberband = new QRubberBand(QRubberBand::Rectangle, this);
rubberband->move(0, 0);
rubberband->show();
}
void Resizable_rubber_band::resizeEvent(QResizeEvent *)
{
rubberband->resize(size());
}
void Resizable_rubber_band::mousePressEvent(QMouseEvent *event)
{
lastPoint = event->pos();
rubberband->childAt(lastPoint);
}
void Resizable_rubber_band::mouseReleaseEvent(QMouseEvent *event)
{
newpoint = event->pos();
int dragx=newpoint.x()-lastPoint.x();
int dragy=newpoint.y()-lastPoint.y();
band->move(0+dragx,0+dragy);
}
In this code, my problem is i am not getting the exact coordinates after dragging
thanks.
Ashish
Here is a quick example I made where you can move a QRubberBand using mouse events:
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QRubberBand>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
protected:
void mousePressEvent(QMouseEvent *e);
void mouseMoveEvent(QMouseEvent *e);
void mouseReleaseEvent(QMouseEvent *e);
private:
Ui::MainWindow *ui;
QRubberBand *rubberBand;
bool move_rubberband;
QPoint rubberband_offset;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QMouseEvent>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
move_rubberband = false;
rubberBand = new QRubberBand(QRubberBand::Rectangle, this);
rubberBand->setGeometry(0,0,50,50);
rubberBand->show();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::mousePressEvent(QMouseEvent *e)
{
if(rubberBand->geometry().contains(e->pos()))
{
rubberband_offset = e->pos() - rubberBand->pos();
move_rubberband = true;
}
}
void MainWindow::mouseMoveEvent(QMouseEvent *e)
{
if(move_rubberband)
{
rubberBand->move(e->pos() - rubberband_offset);
}
}
void MainWindow::mouseReleaseEvent(QMouseEvent *e)
{
move_rubberband = false;
}

Resources