day02:Qt绘图与事件信号的学习与作业

  • 2020/6/22

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

1. 继承QDialog

  • 头文件:
#ifndef GK_DIALOG_H
#define GK_DIALOG_H
#include <QtWidgets/QDialog>
#include <QtWidgets/QPushButton>

class GKDialog: public QDialog{
public:
    GKDialog(QWidget *parent=0);
    ~GKDialog();
private:
    QPushButton *btn;
};
#endif

  • 代码实现:
include "gkdialog.h"
#include <iostream>


GKDialog::GKDialog(QWidget *parent):
    QDialog(parent){
    std::cout << "对话框初始化" << std::endl;
    // 初始化
    btn = new QPushButton("确定",this);
    btn->move(250, 300);
}

GKDialog::~GKDialog(){
    std::cout << "释放" << std::endl;
    delete btn;
}

2. QApplication

  • 头文件:
#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

  • 代码实现:
#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;
}

3. main.cpp:

#include "gkapp.h"
// #include "gkdialog.h"

int  main(int argc, char **argv){
    // 创建Qt应用
    GKApp app(argc, argv);
    // 创建对话框
    // GKDialog dlg;
    // dlg.resize(600, 400);
    // dlg.move(200, 200);
    // dlg.show();
    // 消息循环
    // 返回状态码
    return app.exec();
}

4. Makefile编译脚本:

INCLUDES = /I "D:/Qt/Qt5.13.0/5.13.0/msvc2017_64/include"

LIBS     = /LIBPATH:"D:/Qt/Qt5.13.0/5.13.0/msvc2017_64/lib" \
           /DYNAMICBASE  \
             "Qt5Widgetsd.lib"  \
             "Qt5Guid.lib" \
             "Qt5Cored.lib"
CL_ARGS  = /EHsc \
           /MDd \
           /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

三种使用模式的体会:

    1. 在main函数中直接绘制对话框:

    即在main.cpp中利用继承好的GKDialog类对象去直接调用相应方法来绘制出对话窗口。该使用模式的逻辑顺序最适应我们的思维方式,故该种模式的优点是使我们更容易接受与理解;但是由于将执行过程直接暴露于main函数中,使得该模式的对象间的管理结构与职能分布不对称,从工程级别的角度来看是较为失败的一种搭建模式。

    1. 在gkapp类中初始化对话框属性:

    即在gkapp.h和gkapp.cpp文件的QApplication去加载GKDialog类并初始化出对话框属性,main函数不再起到绘制作用而是调用作用,该使用模式突出了面向对象编程的思维方式,解放了main函数的职能,使得工具类和对话框类对象间具备了包含关系,很好的提高了代码的封装性和可读性;由于对话框属性是在构造器里面进行初始化,使得该使用模式的内存分配较为冗杂,不是最为合理的使用模式。

    1. 在gkapp类中直接构造对话框的初始化列表:
      即在第二种使用模式的基础上,改变对话框初始化方式,直接进行构造初始化列表,该使用模式不仅使代码具有很好的封装性和复用性,而且还减少了对话框初始化分配内存时的寻址过程,使得程序的效率和性能更为突出,相比于以上两种模式,我认为该模式最为高效和专业。

设计UI(Qt Designer)

代码实现:

    1. 定义成员
    1. 创建对象
    1. 设置属性

工具实现

  • 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设计中的槽函数

  1. 所有定义了槽函数的头文件需要编译成moc的cpp文件。
    • cpp需要编译与链接

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

    • moc [options] [header-file]

      • 选项: -o 输出的文件moc_***.cpp
  • 附gkdialog.cpp(初始化对话框的cpp文件)代码实现:
#include "gkdialog.h"
#include <iostream>
#include <QtGui/QPainter>
#include <QtGui/QKeyEvent>
GKDialog::GKDialog(QWidget *parent):
    QDialog(parent),
    ui(new Ui::gk()){
    std::cout << "对话框初始化" << std::endl;
    // 初始化

    // ui = new Ui::gk();
    ui->setupUi(this);
    // btn = new QPushButton("确定",this);
    // btn->move(200, 200);
}

GKDialog::~GKDialog(){
    std::cout << "释放" << std::endl;
    // delete btn;
    delete ui;
}

void GKDialog::sobel(){
    std::cout << "sobel" << std::endl;
}
void GKDialog::laplace(){
    std::cout << "laplace" << std::endl;
}
void GKDialog::gauss(){
    std::cout << "gauss" << std::endl;
}
void GKDialog::conv(){
    std::cout << "conv" << std::endl;
}

  • 编译脚本:
INCLUDES = /I "D:\Qt\Qt5.13.0\5.13.0\msvc2017_64\include"

LIBS     = /LIBPATH:"D:\Qt\Qt5.13.0\5.13.0\msvc2017_64\lib" \
           /DYNAMICBASE  \
             "Qt5Widgetsd.lib"  \
             "Qt5Guid.lib" \
             "Qt5Cored.lib"
CL_ARGS  = /EHsc \
           /MDd \
           /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
    @cl /c $(CL_ARGS) /Fo:moc_dialog.obj  $(INCLUDES) moc_gkdialog.cpp
    @link $(LINK_ARGS) $(LIBS) /OUT:main.exe  main.obj app.obj dialog.obj moc_dialog.obj

clean:
    @del *.exe *.obj *.exp 2>/Nul

uic:gk.ui
    @uic -o gk.h  gk.ui

moc:
    @moc -o moc_gkdialog.cpp  gkdialog.h

Qt画图

  1. Qt应用
    QApplication
    | - QDialog
  1. 绘制事件

    • 完成绘图编程模式

    • QPainter

  2. 键盘事件

    • 通过键盘控制=图形的活动
  • 附thdialog.cpp(内含绘制和键盘事件跟踪的代码语句):
#include "thdialog.h"
#include <iostream>
#include <QtGui/QPainter>
THDialog::THDialog(QWidget *parent):
    QDialog(parent),
    fish(new THFish(100, 100)){
        
}

THDialog::~THDialog(){

}

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

Qt多线程

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

  2. 通信机制:信号与槽

    1. 定义信号
    2. 发送信号
    3. 绑定信号到目标
    4. 目标需要有一个slot函数处理信息
  3. 绘制刷新实现动画

  • 附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)){
    QObject::connect(fish, SIGNAL(sign_open()), this, SLOT(repaint()));
    QObject::connect(fish2, SIGNAL(sign_open()), this, SLOT(repaint()));
    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_W){
        std::cout << "up" << std::endl;
        fish->changeDir(90);
        fish->swim();
    }
    if(e->modifiers() == Qt::ControlModifier && e->key() == Qt::Key_S){
        std::cout << "down" << std::endl;
        fish->changeDir(270);
        fish->swim();
    }
    if(e->modifiers() == Qt::ControlModifier && e->key() == Qt::Key_A){
        // std::cout << "left" << std::endl;
        fish->changeDir(180);
        fish->swim();
    }
    if(e->modifiers() == Qt::ControlModifier && e->key() == Qt::Key_D){
        // std::cout << "right" << std::endl;
        fish->changeDir(0);
        fish->swim();
    }
    this->repaint();
}

作业:使用Qt绘制图型

提交作业:

  • thapp.h代码:
#ifndef TH_APP_H
#define TH_APP_H
#include <QtWidgets/QApplication>
#include "thdialog.h"

class THApp : public QApplication{
public:
    THApp(int argc, char **argv);
    ~THApp();
private:
    THDialog  *dlg;
};
#endif

  • thapp.cpp代码:
#include "thapp.h"

THApp::THApp(int argc, char **argv):
    QApplication(argc, argv),
    dlg(new THDialog()){
    
    dlg->resize(600, 400);
    // 完成其他初始化
    dlg->show();
}

THApp::~THApp(){
   
}

  • thdialog.h代码:
#ifndef TH_DIALOG_H
#define TH_DIALOG_H
#include <QtWidgets/QDialog>
#include <QtGui/QKeyEvent>

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

};

#endif
  • thdialog.cpp代码:
#include "thdialog.h"
#include <iostream>
#include <QtGui/QPainter>
THDialog::THDialog(QWidget *parent):
    QDialog(parent){

}

THDialog::~THDialog(){

}

// override绘制函数
void THDialog::paintEvent(QPaintEvent *e){
    // 在这里完成绘制工作
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing,true);
    painter.save();
    QPainterPath path;
    path.moveTo(80,320);
    path.cubicTo(200,80,320,80,480,320);

    painter.setPen(QPen(Qt::black,8));
    painter.drawPath(path);
    painter.restore();

    painter.save();
    painter.translate(100,0);
    QPointF baseline(200,200);
    QLinearGradient myGradinet(50,100,300,350);
    myGradinet.setColorAt(0.0,Qt::white);
    myGradinet.setColorAt(0.2,Qt::green);
    myGradinet.setColorAt(1.0,Qt::black);
    QPainterPath myPath;
    myPath.addText(baseline,QFont("Arial", 25),tr("Qt"));
    painter.setPen(QPen(Qt::yellow,1));
    painter.setFont(QFont("Arial", 25));
    painter.setBrush(myGradinet);
    painter.drawPath(myPath);
    painter.restore();
}

  • 编译脚本:
INCLUDES = /I "D:\Qt\Qt5.13.0\5.13.0\msvc2017_64\include"

LIBS     = /LIBPATH:"D:\Qt\Qt5.13.0\5.13.0\msvc2017_64\lib" \
           /DYNAMICBASE  \
             "Qt5Widgetsd.lib"  \
             "Qt5Guid.lib" \
             "Qt5Cored.lib"
CL_ARGS  = /EHsc \
           /MDd \
           /source-charset:utf-8 \
           /execution-charset:utf-8 \
           /nologo
LINK_ARGS = /MACHINE:X64  /NOLOGO 

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

clean:
    @del *.exe *.obj *.exp 2>/Nul
    
  • 绘图如下:


©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。