CVTE实习-周二

1.VS扩展QT过程

出现了如上图的错误,参考

https://blog.csdn.net/zhoufei95/article/details/121030163

 打开cmd,关闭VS,设置环境变量 TRACEDESIGNTIME = true,并重启 Visual Studio查看日志以进行调查具体问题。

2.gcc,mingw,区别

MinGW -> Minimalist GNU for Windows

MinGW 提供了一套简单方便的Windows下的基于GCC 程序开发环境。MinGW 收集了一系列免费的Windows 使用的头文件和库文件;整合了GNU的工具集,特别是GNU 程序开发工具,如经典gcc, g++, make等。它在Windows平台上模拟了Linux下GCC的开发环境,为C++ 的跨平台开发提供了良好基础支持,为了在Windows下工作的程序员熟悉Linux下的C++工程组织提供了条件。

3.Qt中的窗口类

常用的窗口类有3个,在创建Qt窗口的时候, 需要让自己的窗口类继承其中一个

  • QWidget

        所有窗口类的基类,Qt中的控件(按钮, 输入框, 单选框…)都属于窗口,
        可以内嵌到其他窗口中: 没有边框
        可以不内嵌单独显示: 独立的窗口, 有边框

  • QDialog

        对话框类, 后边的章节会具体介绍这个窗口
        不能内嵌到其他窗口中

  • QMainWindow

        有工具栏, 状态栏, 菜单栏, 后边的章节会具体介绍这个窗口
        不能内嵌到其他窗口中

4.模态对话框和非模态对话框

对话框通常会是一个顶层窗口,出现在程序最上层,不能最大最小化,用于实现短期任务或者简洁的用户交互。对话框分为模态对话框和非模态对话框。

  • 模态:不关闭不能操作同一进程的其他窗口
  • 非模态:不关闭可以操作同一进程的其他窗口

5.QT的内存回收机制

  • 在Qt中创建对象的时候会提供一个 Parent对象指针,QObject是以对象树的形式组织起来的。当你创建一个QObject对象时,会看到QObject的构造函数接收一个Parentt指针作为参数,我们创建的这个QObject对象会自动添加到其父对象(parent,不是继承意义的父类)的children()列表,当父对象析构的时候,列表中的所有对象也被析构。
  • QWidget是能够在屏幕上显示的一切组件的父类。QWidget继承自QObject,因此也继承了这种对象树关系。例如,当用户关闭一个对话框的时候,应用程序将其删除,那么,我们希望属于这个对话框的按钮、图标等应该一起被删除。事实就是如此,因为这些都是对话框的子组件。
  • 对象树一定程度上解决了内存问题。当一个QObject对象在堆上创建的时候,Qt 会同时为其创建一个对象树(对象树中对象的顺序是没有定义的,销毁的时候也是)。任何对象树中的 QObject对象 delete 的时候,如果这个对象有 parent,则自动将其从 parent 的children()列表中删除;如果有孩子,则自动 delete 每一个孩子。Qt 保证没有QObject会被 delete 两次,这是由析构顺序决定的。栈上也是同样的行为,但是有可能会出现一些意想不到的错误,
    {
        QPushButton quit("Quit");
        QWidget window;
        quit.setParent(&window);
    }

    除了作用域之后,作为父对象的 window 会首先被析构,因为它是最后一个创建的对象。在析构过程中,它会调用子对象列表中每一个对象的析构函数,也就是说, quit 此时就被析构了。然后,代码继续执行,在 window 析构之后,quit 也会被析构,因为 quit 也是一个局部变量,在超出作用域的时候当然也需要析构。但是,这时候已经是第二次调用 quit 的析构函数了,C++ 不允许调用两次析构函数,因此,程序崩溃了。

  • 所以,我们最好从开始就养成良好习惯,在 Qt 中,尽量在构造的时候就指定 parent 对象,并且大胆在堆上创建。

6.命名规范

  1. 类名:单词首字母大小,单词和单词之间直接连接,无需连接字符 如:MyClass,QPushButton
  2. Qt中内置的类型,头文件和类命名同名。如:#include <QString>  QSring str;
  3. 函数名字,变量名:首字母小写,之后每个单词首字母大写,单词和单词之间直接连接,无需连接字符。如:void connectTheSignal();
  4. 类的成员变量设置函数用使用 set+成员变量名,如void setText(QString text);获取成员变量的函数直接用成员变量名(bool类型可用一些表示状态的术语,如isVisilble)

7.常见API

如果想设置按钮上显示的文字可以用setText,移动按钮位置用move。

按钮需要与窗口有父子关系,否则就会并列为顶级窗口,可以作为窗口类的成员变量。

对于窗口而言,我们可以修改左上角窗口的标题setWindowTitle,

重新指定窗口大小:resize,或者设置固定的窗口大小setFixedSize。

8.信号和槽机制

  • 信号:各种事件;: 响应信号的动作

        当某个事件发生后,如某个按钮被点击了一下,它就会发出一个被点击的信号(signal)。某 个对象接收到这个信号之后,就会做一些相关的处理动作(称为槽slot)。但是Qt对象不会无故收到某个信号,要想让一个对象收到另一个对象发出的信号,这时候需要建立连接(connect)

connect函数是建立信号发送者、信号、信号接收者、槽四者关系的函数:
connect(sender, signal, receiver, slot);

        connect的四个参数都是指针,信号和槽是函数指针

  • 自定义信号和槽

        自定义信号使用条件:声明在类的signals域下;没有返回值,void类型的函数只有函数声明,没有定义;可以有参数,可以重载;通过emit关键字来触发信号,形式:emit object->sig(参数);

        自定义槽函数使用条件:可以声明public下,同时还可以是静态的成员函数,全局函数,lambda表达式;没有返回值,void类型的函数;不仅有声明,还得要有实现;可以有参数,可以重载

//Teacher类
signals:
    void hungry();//预设信号

//Student类
public slots:
    void treat();//预设槽


//MyWidget类中,初始化pteacher指针和pstudent指针,并且需要提供触发信号函数
void MyWidget::ClassIsOver()
{
    emit pTeacher->hungry();//触发老师饿了的信号
}


connect(pTeacher, &Teacher::hungry, pStudent, &Student::treat);//绑定
this->ClassIsOver();//触发

9.事件

事件和信号槽的区别

事件(event)是由系统或者 Qt 应用程序本身在不同的时刻发出的。当用户按下鼠标、敲下键盘,或者是窗口需要重新绘制的时候,都会发出一个相应的事件。一些事件在对用户操作做出响应时发出,如键盘事件等;另一些事件则是由系统自动发出,如计时器事件。

在Qt中使用信号和槽替代回调技术当某个特定事件发生时发出一个信号。槽是响应特定信号的函数。

两者都是Qt中的通讯机制,但事件比信号槽更底层,一般Qt中的标准信号会是某些消息事件处理的结果,比如:鼠标移动到按钮上,按钮一直收到鼠标移动的事件,可是按钮没有做任何处理,但是只要当鼠标点击按钮,按钮就会收到一个鼠标点击的事件,他会处理这个事件并且主动去发送一个被点击的信号clicked,这时候相关联的槽函数就会被调用。(事件->信号)

实战:在窗口中点击任意位置,打印点击位置的坐标以及使用鼠标左键还是右键

//MyWidget类   
    //垂直布局
    QVBoxLayout* verticalLayout = new QVBoxLayout(this);
    verticalLayout->setSpacing(0);
    verticalLayout->setContentsMargins(0, 0, 0, 0);
    MyLabel* pMyLabel = new MyLabel(this);
    // 1. 添加一个自定义的标签 MyLabel
    MyLabel* lb = new MyLabel(this);
    lb->setText("");
    lb->setFrameShape(QFrame::Box);
    //lb->setFixedHeight(50);
    lb->setAlignment(Qt::AlignCenter);
    lb->setStyleSheet("background-color: blue;color: white;font-size: 25px");
    verticalLayout->addWidget(lb);//将标签控件加到布局中才可以实现将事件传到窗口中

//MyLabel类
    //重写mousePressEvent函数
    void MyLabel::mousePressEvent(QMouseEvent *ev)
    {
    	int x=ev->x();
	    int y = ev->y();
	    Qt::MouseButton btn = ev->button();
	    QString strButton = "";
	    if (btn == Qt::LeftButton) {
		    strButton = "leftButton";
	    }
	    else {
		    strButton = "rightButton";
	    }
	    QString str = QString("[%1,%2,%3]").arg(x).arg(y).arg(strButton);
	    this->setText(str);
    }

10.绘图

什么时候会画?

窗口需要重新显示的时候,就会收到一个绘图事件。收到后,窗口才重新显示。

//重写绘图事件的处理函数
void MyPushButton::paintEvent(QPaintEvent* ev)
{
	static int num = 1;
	qDebug() << num++;
	QPushButton::paintEvent(ev);//这行注释掉之后,窗口不会重新显示。
}

可以看到当窗口最大化,最小化的时候,num一直在增加。

绘图三要素

QPainter理解成画笔;

QPaintDevice理解成使用画笔的地方,比如纸张、屏幕等;

而对于纸张、屏幕而言,肯定要使用不同的画笔绘制,为了统一使用一种画笔,我们设计了QPaintEngine类,这个类让不同的纸张、屏幕都能使用一种画笔。

qpainter所在的widget有自己的坐标系:X轴向右,Y轴向下。qpainter自己也有坐标系,默认和widget是重合的。但是qpainter的坐标系可以做各种变换,如平移(translate),(scale)。

先说下scale。它的作用是改变qpainter的刻度长度。(默认qpainter的刻度和widget的刻度一样)
qp.scale(2,2),意味着qpainter的刻度已经变为原来2倍。前后同样绘制边长为100的正方形,后者的边长是前者的两倍。(都是100刻度,但是刻度已经变了)

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值