Qt绘图与信号事件

Qt应用开发的基本模式(面向对象)

  1. 继承QDailog
  • gkdialog.h
#ifndef GK_DIALOG_H
#define GK_DIALOG_H
#include <QtWidgets/QDialog>

class GKDialog: public QDialog{
public:
    GKDialog(QWidget *parent=0);
    ~GKDialog();
};
#endif
  • gkdialog.cpp
#include "gkdialog.h"
#include <iostream>

GKDialog::GKDialog(QWidget *parent):
    QDialog(parent){
    std::cout << "对话框初始化" << std::endl;
}

GKDialog::~GKDialog(){
    std::cout << "释放" << std::endl;
}
  1. QApplication
  • gkapp.h
#ifndef GK_APP_H
#define GK_APP_H
#include <QtWidgets/QApplication>
#include "gkdialog.h"
class GKApp : public QApplication{
public:
    GKApp(int argc, char **argv);
    ~GKApp();
private:
    GKDialog *dlg;
};
#endif
  • gkapp.cpp
#include "gkapp.h"
#include <iostream>
GKApp::GKApp(int argc, char **argv):
    QApplication(argc, argv),
    dlg(new GKDialog()){  // 构造初始化列表
    dlg = new GKDialog();
    dlg->resize(600, 400);
    dlg->move(200, 200);
    dlg->show();
    std::cout << "应用初始化" << std::endl;
}

GKApp::~GKApp(){
    std::cout << "应用释放" << std::endl;
    delete dlg;
}
  1. main.cpp
#include "gkapp.h"
// #include "gkdialog.h"

int  main(int argc, char **argv){
    // 创建Qt应用
    GKApp app(argc, argv);
    // 创建对话框
    // 消息循环
    // 返回状态码
    return app.exec();
}
  1. Makefile
INCLUDES = /I "C:/Qt/Qt5.13.0/5.13.0/msvc2017_64/include"

LIBS     = /LIBPATH:"C:/Qt/Qt5.13.0/5.13.0/msvc2017_64/lib" \
           /DYNAMICBASE  \
	         "Qt5Widgets.lib"  \
		     "Qt5Gui.lib" \
		     "Qt5Core.lib"
CL_ARGS  = /EHsc \
           /MD \
		   /source-charset:utf-8 \
		   /execution-charset:utf-8 \
		   /nologo
LINK_ARGS = /MACHINE:X64  /NOLOGO 

main:main.cpp gkapp.cpp gkdialog.cpp
	@cl /c $(CL_ARGS) /Fo:main.obj  $(INCLUDES) main.cpp
	@cl /c $(CL_ARGS) /Fo:app.obj  $(INCLUDES) gkapp.cpp
	@cl /c $(CL_ARGS) /Fo:dialog.obj  $(INCLUDES) gkdialog.cpp
	@link $(LINK_ARGS) $(LIBS) /OUT:main.exe  main.obj app.obj dialog.obj 

clean:
	@del *.exe *.obj *.exp 2>/Nul
  • 说明:
    • 三种使用模式的体会:
      • 第一种对话框与应用程序并列呈现,我们通常不采用这种并列的方式
      • 第二种(即为上面的代码形式),对话框与应用程序为包含关系,这种方式可控性强、风险低。

设计UI(Qt Designer)

代码实现

  1. 定义成员

  2. 创建对象

  3. 设置属性

工具实现

  • Qt Designer(Qt设计大师)
  1. 步骤1:创建模板,保存为ui文件

  2. 拖组件满足功能

  3. 外观的设计

  4. 命名规范

  5. 交互设计

    1. 设计槽(slot)函数
    2. 组件的信号与槽函数关联

使用UI

  • 条件是*.ui文件
  1. 编译ui文件为.h文件

    • uic [options] [uifile]
      1. -o 输出的文件 : 建议文件输出为.h文件
  2. 创建ui对象

  3. 使用ui对象的setupUi绑定我们的对话框
    ui->setupUi(this);

  4. 实现ui设计中的槽函数

  5. 所有定义了槽函数的头文件需要编译成moc的cpp文件。

    • cpp需要编译与链接

    • 注意事项;定义槽函数或者是信号的类,需要添加一个宏,Q_OBJECT

    • moc [options] [header-file]

      • 选项: -o 输出的文件moc_***.cpp

Qt画图

  1. Qt应用
    QApplication

    • QDialog
  2. 绘制事件

    • 完成绘图编程模式

    • QPainter

  3. 键盘事件

    • 通过键盘控制=图形的活动
  4. 代码

  • hwdialog.h
#ifndef HW_DIALOG_H
#define HW_DIALOG_H
#include <QtWidgets/QDialog>
#include <QtGui/QkeyEvent>

class HWDialog: public QDialog{
public:
    HWDialog(QWidget *parent=0);
    ~HWDialog();
public:
    virtual void paintEvent(QPaintEvent *e);
    virtual void keyPressEvevt(QKeyEvent *e);
private:
    int x, y;
};
#endif
  • hwdialog.cpp
#include "hwdialog.h"
#include <iostream>
#include <QtGui/QPainter>

HWDialog::HWDialog(QWidget *parent):
    QDialog(parent),
    x(100), y(100){
    
}

HWDialog::~HWDialog(){
   
}

void HWDialog::paintEvent(QPaintEvent *e){
    QPainter painter(this);
    QColor color(255, 0, 0, 255);
    QPen pen(color);
    painter.setPen(pen);
    painter.drawRoundedRect(x, y, 100,200,20, 15); 
}

void HWDialog::keyPressEvevt(QKeyEvent *e){
    if(e->modifiers() == Qt::ControlModifier && e->key() == Qt::Key_Up){
        y -= 2;
    }
    if(e->modifiers() == Qt::ControlModifier && e->key() == Qt::Key_Down){
        y += 2;
    }
    if(e->modifiers() == Qt::ControlModifier && e->key() == Qt::Key_Left){
        x -= 2;
    }
    if(e->modifiers() == Qt::ControlModifier && e->key() == Qt::Key_Right){
        x += 2;
    }
    this->repaint();
}
  • QApplication、main.cpp、Makefile三部分代码与Qt开发的基本模式相同,在此不再进行展示。

  • 运行展示

Qt多线程

  1. 使用线程完成数据同步处理
  • 代码

thdialog.h

#ifndef TH_DIALOG_H
#define TH_DIALOG_H
#include <QtWidgets/QDialog>
#include <QtGui/QKeyEvent>
#include "thfish.h"

class THDialog: public QDialog{
public:
    THDialog(QWidget *parent=0);
    ~THDialog();
public:
    virtual void  paintEvent(QPaintEvent *e);
    virtual void  keyPressEvent(QKeyEvent *e);

private:
    THFish *fish;

    THFish *fish2;
};

#endif

thdialog.cpp

#include "thdialog.h"
#include <iostream>
#include <QtGui/QPainter>
THDialog::THDialog(QWidget *parent):
    QDialog(parent),
    fish(new THFish(100, 100)),
    fish2(new THFish(200, 100)){
    fish->start(); // 线程启动
    fish2->start();
}

THDialog::~THDialog(){

}

// override绘制函数
void THDialog::paintEvent(QPaintEvent *e){
    // 在这里完成绘制工作
    QPainter painter(this);
    fish->showFish(&painter);
    fish2->showFish(&painter);
}
void  THDialog::keyPressEvent(QKeyEvent *e){
    if(e->modifiers() == Qt::ControlModifier && e->key() == Qt::Key_Up){
        // std::cout << "up" << std::endl;
        fish->changeDir(90);
        fish->swim();
    }
    if(e->modifiers() == Qt::ControlModifier && e->key() == Qt::Key_Down){
        // std::cout << "down" << std::endl;
        fish->changeDir(270);
        fish->swim();
    }
    if(e->modifiers() == Qt::ControlModifier && e->key() == Qt::Key_Left){
        // std::cout << "left" << std::endl;
        fish->changeDir(180);
        fish->swim();
    }
    if(e->modifiers() == Qt::ControlModifier && e->key() == Qt::Key_Right){
        // std::cout << "right" << std::endl;
        fish->changeDir(0);
        fish->swim();
    }
    this->repaint();
}

thfish.h

#ifndef TH_FISH_H
#define TH_FISH_H
#include <QtCore/QThread>
#include <QtGui/QPainter>

class THFish : public QThread{
    Q_OBJECT
public:
    THFish(int x=0, int y=0, int m=45, int d=0);
    void openMouth();
    void changeDir(int dir);
    void swim();
    void showFish(QPainter *painter);
protected:
    virtual void run();
private:
    int mouth;
    int pos_x, pos_y;
    int dir;
    bool isopen;
};
#endif

thfish.cpp

#include "thfish.h"

THFish::THFish(int x, int y, int m, int d):
    mouth(m), isopen(false), 
    pos_x(x), pos_y(y), 
    dir(d){
    
}
void THFish::run(){
    while(true){
        openMouth();
        QThread::usleep(100000);
    }
}
void THFish::openMouth(){
    if(isopen){
        mouth += 5;
        if(mouth >= 45){
            isopen=!isopen;
            mouth = 45;
        }
    }else{
        mouth -= 5;
        if(mouth <= 0){
            isopen=!isopen;
            mouth = 0;
        }
    }
}
void THFish::changeDir(int dir){
    this->dir = dir;
}
void THFish::swim(){
    if(this->dir == 0){
        pos_x += 2;
    }
    if(this->dir == 90){
        pos_y -= 2;
    }
    if(this->dir == 180){
        pos_x -= 2;
    }
    if(this->dir == 270){
        pos_y += 2;
    }
}
void THFish::showFish(QPainter *painter){
    QColor color(255, 0, 0, 255);
    QPen pen(color);
    painter->setPen(pen);
    painter->drawPie(pos_x, pos_y, 50, 50, mouth * 16 + dir * 16, (360 - 2 * mouth) *16);
}
  1. 通信机制:信号与槽

    1. 定义信号
      在fish.h文件的类中定义:
      •    signals:
           void sign_open();
        
    2. 发送信号
      在fish.cpp文件的run()函数中发送:
      •    emit sign_open();
        
    3. 绑定信号到目标
    4. 目标需要有一个slot函数处理信息
      在dialog.cpp文件中,线程启动前绑定:
      •   QObject::connect(fish, SIGNAL(sign_open()), this, SLOT(repaint()));
          QObject::connect(fish2, SIGNAL(sign_open()), this, SLOT(repaint()));
        
  2. 绘制刷新实现动画

  3. 运行展示
    在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值