• 7793阅读
  • 6回复

[提问]在 qt 事件中含有耗时操作的函数的处理 [复制链接]

上一主题 下一主题
离线qypan
 

只看楼主 倒序阅读 楼主  发表于: 2016-07-26
就比如我希望实现这样的功能:
我单击鼠标时,程序以鼠标当前坐标 (x, y) 为圆心画了一个圆,半径随意(比如 30),然后我希望程序在我单击 3 秒后自动以 (x+40, y+40) 为圆心画一个跟前面同样大小的圆.
3 秒只是模拟耗时操作,这里我并不希望使用多线程,我上网查过,应该可以使用 QCoreApplication::processEvents() 或 QEventLoop 类实现。但没有找到实例,这两个东西真心不会用。希望有人可以提供可以解决我问题的链接,或者给我提供一个类似的实例。
我的代码(可在 linux 系统编译执行):
//mything.h
#ifndef MYTHING_H
#define MYTHING_H

#include <QtGui>

class myThing : public QLabel{
    Q_OBJECT
public:
    myThing(QWidget *parent = 0);
protected:
    void drawAnother(int x, int y);
    void paintEvent(QPaintEvent *event);
    void mousePressEvent(QMouseEvent *event);
private:
    QPixmap *pixmap;
};

#endif

------------------------------------------------------------------------------------------
//mything.cpp
#include <unistd.h> //linux 系统函数库
#include "mything.h"

myThing::
myThing(QWidget *parent)
    : QLabel(parent)
{
    resize(400, 200);
    pixmap = new QPixmap(400, 200);
    pixmap->fill(QColor(255, 255, 255));
}

void myThing::
paintEvent(QPaintEvent *event){
    QPainter painter(this);
    QRect dirtyRect = event->rect();
    painter.drawPixmap(dirtyRect, *pixmap, dirtyRect);
}

void myThing::
drawAnother(int x, int y){
    sleep(3); //其他平台做适当更改
    QPainter painter;
    painter.begin(pixmap);
    painter.setPen(Qt::NoPen);
    painter.setBrush(QColor(56, 12, 23, 141));
    painter.drawEllipse(QPoint(x, y), 30, 30);
    update(QRect(QPoint(x-30, y-30), QSize(60, 60)).
            normalized().adjusted(-2, -2, 2, 2));
    painter.end();
}

void myThing::
mousePressEvent(QMouseEvent *event){
    int x = event->x();
    int y = event->y();
    QPainter painter;
    painter.begin(pixmap);
    painter.setPen(Qt::NoPen);
    if(event->button() == Qt::LeftButton){
        painter.setBrush(QColor(43, 56, 233, 111));
        painter.drawEllipse(QPoint(x, y), 30, 30);
        update(QRect(QPoint(x-30, y-30), QSize(60, 60)).
                normalized().adjusted(-2, -2, 2, 2));
        painter.end();
        // 下面的函数是耗时函数,程序执行的效果是,单击鼠标左键 3 秒后连续画了 2 个圆,我希望的效果是单击时画一个,3 秒后再自动画一个。问题是鼠标事件没返回,所以事件循环队列里的第一个圆的绘图事件处理不了;直到下面的函数调用之后,才一次处理两个绘图事件
        drawAnother(x+40, y+40);
    }
}
------------------------------------------------------------------------------------------
//main.cpp
#include "mything.h"

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
      
    QCoreApplication::processEvents();
    myThing window;
    window.setWindowTitle("myThing");
    window.show();

    return app.exec();
}
离线圣域天子

只看该作者 1楼 发表于: 2016-07-26
和昨天重复的?
离线圣域天子

只看该作者 2楼 发表于: 2016-07-26
给你一段代码看看:
QByteArray TcHttp::get(const QString& url)
{
    QNetworkAccessManager   nam;
    QEventLoop loop;
    QNetworkReply* reply = nam.get(QNetworkRequest(QUrl(url)));
    QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()), Qt::DirectConnection);
    QTimer::singleShot(m_timeout, &loop, SLOT(quit()));
    loop.exec();

    return reply->readAll();
}
离线6gongzi

只看该作者 3楼 发表于: 2016-07-26
“然后我希望程序在我单击 3 秒后自动以 (x+40, y+40) 为圆心画一个跟前面同样大小的圆.”
可以采用 定时器,在你鼠标点击后,启动一个定时器,给定时器设置成3秒
在定时器的触发函数中,重新绘制一个圆,
这么做的好处是,不用多线程,而且不会阻塞主线程

QEventLoop会阻塞主线程,所谓的耗时操作,可以什么也不做,否者界面容易假死
离线qypan

只看该作者 4楼 发表于: 2016-07-26
回 圣域天子 的帖子
圣域天子:和昨天重复的? (2016-07-26 09:04) 

恩,第一次在论坛提问,我找发贴都找了好一会~,发了后发现分类写错了,重新弄了一遍,不要介意哈
离线qypan

只看该作者 5楼 发表于: 2016-07-26
回 6gongzi 的帖子
6gongzi:“然后我希望程序在我单击 3 秒后自动以 (x+40, y+40) 为圆心画一个跟前面同样大小的圆.”
可以采用 定时器,在你鼠标点击后,启动一个定时器,给定时器设置成3秒
在定时器的触发函数中,重新绘制一个圆,
这么做的好处是,不用多线程,而且不会阻塞主线程
....... (2016-07-26 13:43) 

感谢你的回复!其实我目的是写一个五子棋的 AI,而计算机计算落子需要几秒时间,玩家落子是用 mousePressEvent() 实现的,而我在玩家落子后把计算机的求解函数放在了 mousePressEvent() 里面,所以出现我在单击后,直到计算机计算好落子点后才把两个棋子同时画在棋盘上~然而搞了挺久地,在这卡住了。。。
离线qypan

只看该作者 6楼 发表于: 2016-07-26
回 圣域天子 的帖子
圣域天子:给你一段代码看看:
QByteArray TcHttp::get(const QString& url)
{
    QNetworkAccessManager   nam;
    QEventLoop loop;
....... (2016-07-26 09:06) 

感谢你的回复!我学 qt4 三个星期,只是敲了 demos 里面几个基础的例子,不太能理解这段代码的具体意思,不过楼下说 QEventLoop 会阻塞主线程,那我想 QEventLoop 无法解决我的问题。如果能运行一遍我的代码,提出恰当的建议就最好了,看出来你应该是老前辈了。谢谢!
快速回复
限100 字节
 
上一个 下一个