【Qt-Event-信号和槽】

Qt编程指南

  • ■ Qt事件
    • ■ Qt鼠标事件
    • ■ Qt事件同步和异步分发
    • ■ Qt事件循环(exec、eventloop)
    • ■ Qt事件-发送-过滤
    • ■ QT事件过滤
  • ■ 信号和槽
    • ■ 一个信号可以连接多个槽
    • ■ 多个信号可以连接同一个槽
    • ■ 一个信号可以连接另外一个信号
    • ■ 信号槽连接
    • ■ [=]()

■ Qt事件

  1. Qt使用了一个事件队列,当新的事件发生时,会被追加到事件队列的尾部,前一个事件完成以后,取出后面的时间进行处理。
  2. 必要时候Qt事件也是可以不进入事件队列的,而是直接处理。
  3. 事件还可以使用 “事件过滤器” 进行过滤。
  4. 我们使用组件关心的是信号槽;如果自定义组件,我们关心的是事件,因为我们可以通过事件来改变组件的默认操作。
  5. QApplication对象,然后调用了它的exec()函数,其实这个函数就是开始QT的事件循环,
  6. Qt创建一个事件对象,QT所有的事件都继承于QEvent类。在事件对象创建完毕后,QT将这个事件对象传递给QObject的event()函数。Event()函数不直接处理事件,而是按照事件对象的类型分派特定的事件处理函数。
  7. Qt事件处理分五个层次:重定义事件处理函数、重定义event()函数、为单个组件安装事件过滤器、为QApplication安装事件过滤器、重定义QCoreApplication的notify()函数。这几个层次的控制是逐层增大的。
  8. 事件比信号槽优点:1事件分发可以使同步也可以使异步的,2 事件可以使用过滤器。

■ Qt鼠标事件

1.鼠标键按下
virtual void mousePressEvent (QMouseEvent*);
2.鼠标键弹起
virtual void mouseReleaseEvent (QMouseEvent*);
3.鼠标键双击
virtual void mouseDoubleClickEvent (QMouseEvent*);
4.鼠标键按下的同时移动
virtual void mouseMoveEvent (QMouseEvent*);
触发按键:
Qt::MouseButton QMouseEvent::button (void);
Qt::LeftButton
Qt::MiddleButton
Qt::RightButton
按键状态:
Qt::MouseButtons QMouseEvent::buttons (void);
Qt::LeftButton
#include mouseevent.h
MouseEvent::MouseEvent(QWidget *parent)
    : QMainWindow(parent)
{
    setWindowTitle(tr(鼠标事件));
    statusLabel = new QLabel;
    statusLabel->setText(tr(当前位置:));
    statusLabel->setFixedWidth(100);
    MousePosLabel = new QLabel;
    MousePosLabel->setText(tr());
    MousePosLabel->setFixedWidth(100);
    statusBar()->addPermanentWidget(statusLabel);
    statusBar()->addPermanentWidget(MousePosLabel);
    this->setMouseTracking(true);
    resize(400,200);
}

MouseEvent::~MouseEvent()
{    
}

void MouseEvent::mousePressEvent(QMouseEvent *e)
{
    QString str=(+QString::number(e->x())+,+QString::number(e->y())+);
    if(e->button()==Qt::LeftButton)
    {
        statusBar()->showMessage(tr(左键:)+str);
    }
    else if(e->button()==Qt::RightButton)
    {
        statusBar()->showMessage(tr(右键:)+str);
    }
    else if(e->button()==Qt::MidButton)
    {
        statusBar()->showMessage(tr(中键:)+str);
    }
}

void MouseEvent::mouseMoveEvent(QMouseEvent *e)
{
    MousePosLabel->setText((+QString::number(e->x())+, +QString::number(e->y())+));
}

void MouseEvent::mouseReleaseEvent(QMouseEvent *e)
{
    QString str=(+QString::number(e->x())+,+QString::number(e->y())+);
    statusBar()->showMessage(tr(释放在:)+str,3000);
}
void MouseEvent::mouseDoubleClickEvent(QMouseEvent *e){}

■ Qt事件同步和异步分发

sendEvent 发出的事件会立即被处理,也就是“同步”执行。
postEvent 发送的事件会被加入事件队列,在下一轮事件循环时才处理,也就是“异步”执行。
sendPostedEvents,是将已经加入队列中的准备异步执行的事件立即同步执行。



■ Qt事件循环(exec、eventloop)

QApplicaion::exec()、QMessageBox::exec()都是事件循环。其中前者又被称为主事件循环。QEventLoop::quit()能够终止事件循环。
当事件太多而不能马上处理完的时候,待处理事件被放在一个“队列”里,称为“事件循环队列”。当事件循环处理完一个事件后,就从“事件循环队列”中取出下一个事件处理之。当事件循环队列为空的时候,它和一个啥事也不做的永真循环有点类似,但是和永真循环不同的是,事件循环不会大量占用CPU资源。
事件循环的本质就是以队列的方式再次分配线程时间片。

事件循环是可以嵌套的,一层套一层,子层的事件循环执行exec()的时候,父层事件循环就处于中断状态;当子层事件循环跳出exec()后,父层事件循环才能继续循环下去。
如果某个子事件循环仍然有效,但其父循环被强制跳出,此时父循环不会立即执行跳出,而是等待子事件循环跳出后,父循环才会跳出。

■ Qt事件-发送-过滤

void frmInput2019::sendEvent(quint8 type, const QString &text)
{
    if (type == 0) {
        //切换中英模式
        QMouseEvent mousePress(QEvent::MouseButtonPress, QPoint(0, 0), Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
        QApplication::sendEvent(ui->labType->isVisible() ? ui->labType : ui->labType2, &mousePress);
    } else if (type == 1) {
        //隐藏汉字候选面板
        QMouseEvent mousePress(QEvent::MouseButtonPress, QPoint(0, 0), Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
        QApplication::sendEvent(ui->labMore, &mousePress);
    } else if (type == 2) {
        //删除
        QKeyEvent keyPress(QEvent::KeyPress, Qt::Key_Backspace, Qt::NoModifier, QString());
        QApplication::sendEvent(currentWidget, &keyPress);
    } else if (type == 3) {
        //插入回车符
        QKeyEvent keyPress(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier, QString(\n));
        QApplication::sendEvent(currentWidget, &keyPress);
    } else if (type == 4) {
        //插入字符
        QKeyEvent keyPress(QEvent::KeyPress, 0, Qt::NoModifier, QString(text));
        QApplication::sendEvent(currentWidget, &keyPress);
    }
}

bool frmInput2019::eventFilter(QObject *watched, QEvent *event)
{
    //qDebug() << TIMEMS << watched << event;
    if (watched == this) {
        //处理自身拖动
        QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
        //按下的时候记住坐标,移动到鼠标松开的位置
        if (event->type() == QEvent::MouseButtonPress) {
            if (mouseEvent->button() == Qt::LeftButton) {
                mousePressed = true;
                mousePoint = mouseEvent->globalPos() - this->pos();
                return true;
            }
        } else if (event->type() == QEvent::MouseButtonRelease) {
            mousePressed = false;
            return true;
        } else if (event->type() == QEvent::MouseMove) {
            //bottom为固定的底部禁用拖动
            if (mousePressed && position != "bottom") {
                this->move(mouseEvent->globalPos() - mousePoint);
                this->update();
                return true;
            }
        }
    } else if (watched == ui->labMore) {
        //打开更多汉字候选面板
        if (event->type() == QEvent::MouseButtonPress) {

               }
    } else if (watched == ui->labType) {
        //中英模式切换,由于采用的标签所以在这里处理
        if (event->type() == QEvent::MouseButtonPress) {
            setInputType(inputType == "english" ? "chinese" : "english");
        }
    } else if (watched == ui->labType2) {
        //固定切换到英文模式
        if (event->type() == QEvent::MouseButtonPress) {
            setInputType("english");
        }
    } else if (watched == ui->widgetCn) {
        //没有汉字或者按下的地方没有汉字或者当前汉字标签个数过少都不用继续
        if (pinyinHelper.getCount() == 0 || lastText.isEmpty()) {
            return false;
        }

        //记住最后按下拖动的时间,过短则认为是滑动,启动滑动动画
        //static bool pressed = false;
        static QPoint lastPos = QPoint();
        static QDateTime lastTime = QDateTime::currentDateTime();
        QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);

        if (event->type() == QEvent::MouseButtonPress) {
            
        } else if (event->type() == QEvent::MouseMove) {  
        }
    } else if (watched == ui->widgetMore) {
        //没有汉字或者按下的地方没有汉字或者当前汉字标签个数过少都不用继续
        if (pinyinHelper.getCount() == 0 || lastText.isEmpty()) {
            return false;      }

        //记住最后按下拖动的时间,过短则认为是滑动,启动滑动动画

        QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);

        if (event->type() == QEvent::MouseButtonPress) {

        } else if (event->type() == QEvent::MouseButtonRelease) {

            }
        } else if (event->type() == QEvent::MouseMove) {

                return true;
            }
        }
    } else if (watched->inherits("QLabel")) {
        //单击的是汉字标签
        QLabel *lab = (QLabel *)watched;

        //2022-1-7增加硬键盘模式下单击汉字标签选中
        if (useHardKeyBoard && event->type() == QEvent::MouseButtonPress) {

            return true;
        }

        if (!upper && inputType == "chinese") {
            if (lab->property("labCn").toBool()) {
                //记住最后按下的滚动条位置,如果滚动条一直没有变化则认为单击了标签
                static int lastPosition = 0;
                if (event->type() == QEvent::MouseButtonPress) {
                      } else if (event->type() == QEvent::MouseButtonRelease) {                 
                if (event->type() == QEvent::MouseButtonPress) {
       
                } else if (event->type() == QEvent::MouseButtonRelease) {      
  
        } else if (event->type() == QEvent::RequestSoftwareInputPanel) {
            showPanel();
        } else if (event->type() == QEvent::CloseSoftwareInputPanel) {
            hidePanel();
        }
    }
    return QWidget::eventFilter(watched, event);
}

■ QT事件过滤

#include eventfilter.h
#include 
#include 
#include 
#include 

EventFilter::EventFilter(QWidget *parent,Qt::WindowFlags f)
    : QDialog(parent,f)
{
    setWindowTitle(tr(事件过滤));
    label1 = new QLabel;
    Image1.load(../image/1.png);
    label1->setAlignment(Qt::AlignHCenter|Qt::AlignVCenter);
    label1->setPixmap(QPixmap::fromImage(Image1));

    label2 = new QLabel;
    Image2.load(../image/2.png);
    label2->setAlignment(Qt::AlignHCenter|Qt::AlignVCenter);
    label2->setPixmap(QPixmap::fromImage(Image2));

    label3 = new QLabel;
    Image3.load(../image/3.png);
    label3->setAlignment(Qt::AlignHCenter|Qt::AlignVCenter);
    label3->setPixmap(QPixmap::fromImage(Image3));

    stateLabel = new QLabel(tr(鼠标按下标志));
    stateLabel->setAlignment(Qt::AlignHCenter);
    QHBoxLayout *layout=new QHBoxLayout;
    layout->addWidget(label1);
    layout->addWidget(label2);
    layout->addWidget(label3);

    QVBoxLayout *mainLayout = new QVBoxLayout(this);
    mainLayout->addLayout(layout);
    mainLayout->addWidget(stateLabel);

    label1->installEventFilter(this);
    label2->installEventFilter(this);
    label3->installEventFilter(this);
}

EventFilter::~EventFilter()
{    
}

bool EventFilter::eventFilter(QObject *watched, QEvent *event)
{
    if(watched==label1)
    {
        if(event->type()==QEvent::MouseButtonPress)
        {
            QMouseEvent *mouseEvent=(QMouseEvent *)event;
            if(mouseEvent->buttons()&Qt::LeftButton)
            {
                stateLabel->setText(tr(左键按下左边图片));
            }
            else if(mouseEvent->buttons()&Qt::MidButton)
            {
                stateLabel->setText(tr(中键按下左边图片));
            }
            else if(mouseEvent->buttons()&Qt::RightButton)
            {
                stateLabel->setText(tr(右键按下左边图片));
            }


            QMatrix matrix;
            matrix.scale(1.8,1.8);
            QImage tmpImg=Image1.transformed(matrix);
            label1->setPixmap(QPixmap::fromImage(tmpImg));
        }
        if(event->type()==QEvent::MouseButtonRelease)
        {
            stateLabel->setText(tr(鼠标释放左边图片));
            label1->setPixmap(QPixmap::fromImage(Image1));
        }
    }
    else if(watched==label2)
    {
        if(event->type()==QEvent::MouseButtonPress)
        {
            QMouseEvent *mouseEvent=(QMouseEvent *)event;
            if(mouseEvent->buttons()&Qt::LeftButton)
            {
                stateLabel->setText(tr(左键按下中间图片));
            }
            else if(mouseEvent->buttons()&Qt::MidButton)
            {
                stateLabel->setText(tr(中键按下中间图片));
            }
            else if(mouseEvent->buttons()&Qt::RightButton)
            {
                stateLabel->setText(tr(右键按下中间图片));
            }

            QMatrix matrix;
            matrix.scale(1.8,1.8);
            QImage tmpImg=Image2.transformed(matrix);
            label2->setPixmap(QPixmap::fromImage(tmpImg));
        }
        if(event->type()==QEvent::MouseButtonRelease)
        {
            stateLabel->setText(tr(鼠标释放中间图片));
            label2->setPixmap(QPixmap::fromImage(Image2));
        }
    }
    else if(watched==label3)
    {
        if(event->type()==QEvent::MouseButtonPress)
        {
            QMouseEvent *mouseEvent=(QMouseEvent *)event;
            if(mouseEvent->buttons()&Qt::LeftButton)
            {
                stateLabel->setText(tr(左键按下右边图片));
            }
            else if(mouseEvent->buttons()&Qt::MidButton)
            {
                stateLabel->setText(tr(中键按下右边图片));
            }
            else if(mouseEvent->buttons()&Qt::RightButton)
            {
                stateLabel->setText(tr(右键按下右边图片));
            }

            QMatrix matrix;
            matrix.scale(1.8,1.8);
            QImage tmpImg=Image3.transformed(matrix);
            label3->setPixmap(QPixmap::fromImage(tmpImg));
        }
        if(event->type()==QEvent::MouseButtonRelease)
        {
            stateLabel->setText(tr(鼠标释放右边图片));
            label3->setPixmap(QPixmap::fromImage(Image3));
        }
    }
    return QDialog::eventFilter(watched,event);
}

■ 信号和槽

SIGNAL 和 SLOT 是 Qt 的宏,用于指明信号和槽,并将它们的参数转换为相应的字符串。

■ 一个信号可以连接多个槽

connect(spinNum, SIGNAL(valueChanged(int)), this, SLOT(addFun(int));
connect(spinNum, SIGNAL(valueChanged(int)), this, SLOT(updateStatus(int));

■ 多个信号可以连接同一个槽

connect(ui->rBtnBlue,SIGNAL(clicked()),this,SLOT(setTextFontColor()));
connect(ui->rBtnRed,SIGNAL(clicked()),this,SLOT(setTextFontColor()));
connect(ui->rBtnBlack,SIGNAL(clicked()),this,SLOT(setTextFontColor()));

■ 一个信号可以连接另外一个信号

connect(spinNum, SIGNAL(valueChanged(int)), this, SIGNAL (refreshInfo(int));

严格的情况下,信号与槽的参数个数和类型需要一致,至少信号的参数不能少于槽的参数。
如果不匹配,会出现编译错误或运行错误。
在使用信号与槽的类中,必须在类的定义中加入宏 Q_OBJECT。
当一个信号被发射时,与其关联的槽函数通常被立即执行,就像正常调用一个函数一样。
只有当信号关联的所有槽函数执行完毕后,才会执行发射信号处后面的代码。

/* 设定两个QPushButton对象的位置 */
pushButton1->setGeometry(300,200,80,40);
pushButton2->setGeometry(400,200,80,40);

■ 信号槽连接

connect(pushButton1, SIGNAL(clicked()), this, SLOT(pushButton1_Clicked()));
connect(pushButton2, SIGNAL(clicked()), this, SLOT(pushButton2_Clicked()));

■ =

connect(sndTimer,&QTimer::timeout,={
updateQStringList();
emit edit_textChanged(getstep().toInt(),m_stlist);
});

你可能感兴趣的:(#,Qt,qt,开发语言)