通过图形化界面输出helloworld
既然学习了QT,那么自然要做经典的输出helloworld字符串的实验。
QT有两好几种方案输出helloworld,一种是通过图形化界面输出,一种是通过代码实现。
这里先了解图形化界面的方案。
创建项目后,点击 .ui 文件进入到QTdesigner界面。
然后在左边的控件中,选择一个标签控件,拖拽到画布上后。
然后双击该标签,即可输入文本字符串。
这样运行后的窗口就自带一个 helloworld 字符串了。
然后再点击编辑查看 .ui 文件的本体,可以发现 xml 格式中出现了一个字符串,其值是 ''helloworld''
通过纯代码输出helloworld
首先在 mainwindow.cpp 中,找到 MainWindow 的构造函数。
然后包含头文件 QLabel,之后创建一个 QLabel 对象,并且设置字符串 'hello world' 即可。
不过这里没有设置标签的位置,因此默认在左上角。
这里的 QLabel 对象是通过 new 得到的,但是我这里并没有通过其他函数来将该对象的内存释放
这会不会造成内存泄漏呢?实际上是不会的。
对象树
在QT中有一个新概念——对象树。
对象树是一种多叉树,树的节点都是一个个new出来的对象。
在对象 new 的时候可以指定它的 parent ,通过该 parent 指针来将对象挂在对象树上。
这样一个对象的生命周期就由对象树管理起来了。
而如果没有挂在对象树上,就需要手动释放了
在QTdesigner中可以看到对象树的结构。
这里的 label 对象就是挂在一个 QWidget 类对象下面,而这棵树就是 MainWindow。
验证对象树是否会释放节点
首先我们需要自己定义一个新类。
在左上角点击新建文件或项目。
选择文件和类中的 C++,并且选择C++Class
然后设定该类的名称,最好类名和头文件的名称相同。
然后设定添加到哪个项目中,点击确定就完成了。
这样就成功创建一个头文件和cpp文件了。
#ifndef MYLABEL_H
#define MYLABEL_H
#include <QMainWindow>
#include <QLabel>
class MyLabel : public QLabel
{
Q_OBJECT
public:
MyLabel(QWidget * parent);
~MyLabel();
};
#endif // MYLABEL_H
因为是需要挂在 QWidget 下的,因此需要在构造函数时将传入 QWidget 指针用以挂在对象树上。
而且这个 MyLabel 是直接继承自 QLabel 的,因此可以直接使用 QLabel 的函数。
其次 QT 有一个小技巧。
如果一个类有声明了但是没有定义的函数,可以将光标移到该函数,然后通过 alt + enter 后即可在 .cpp 文件中直接定义。
#include "mylabel.h"
#include<iostream>
using namespace std;
MyLabel::MyLabel(QWidget * parent) : QLabel(parent)
{
}
MyLabel::~MyLabel()
{
cout<<"MyLabel 被析构了!"<<endl;
}
定义完后我们直接定义好 .cpp 函数的实现。
接着在 MainWindow 中使用 MyLabel 来挂在对象树上,然后运行。
可以发现成功输出了,然后关闭窗口。
即可在 应用输出窗口 中看到输出的析构函数的内容,不过有乱码。
这是因为中文具有两种不同的字符编码集,如果文件的编码集和工具的编码集不同,就会出现这种乱码问题。
虽然 Windows 上有这个问题,不过 linux 上的QT就没有问题。
这里我们可以使用QT提供的 QDebug 类来输出,它会自动处理字符编码集的转换问题。
QDebug 的使用方式和 cout 类似,不过不需要手动换行,它会自动换行。
并且 QDebug 正如名字所说,是用于调试的工具,它输出的内容只有在 Debug 版本下才能看到,可以通过编译开关一键关闭。
通过按钮输出helloworld
图形化方式
在 QTDesigner 中还有很多其他的控件可以实现输出 helloworld 的功能。
我们可以通过图形化界面的方式来输出 hello world。
比如这样就能够直接输出,不过只是单纯的输出实在是无聊了。
那么我们设置成按下这个按钮后,按钮的文本就会改变应该如何做呢?
当我们为画布添加了一个控件时,点击这个控件可以看到它的名字,我们能够手动修改,这里按钮的名字就是 pushButton 。
而当我们在界面下用鼠标对 pushButton 按下去后,会对这个界面发送一个信号——clicked。
我们可以通过 connect 函数来将这个信号和一个函数进行连接,这样按下这个按钮后就会自动执行这个函数。
这一部分是信号与槽的内容,不过可以先了解一下。
这个信号是 ui 界面中的 pushButton 发出的,发出的信号是 QPushButton 中的 clicked 信号,接受信号的是 this ,也就是 MainWindow 对象来处理,其处理动作是 clickHandler,也就是用户自己设置的函数或是QT自定义的其他函数,这里是我自己设置的函数。
这个函数的动作就是 : 如果按钮的文本是 "hello world" 就把文本替换成 "hello qt",否则替换成"hello world"。
可以看到成功替换了文本。
代码方式
首先在 MainWidos.h 中设置 QPushButton 成员变量。
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QPushButton>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
void clickHandle();
private:
Ui::MainWindow *ui;
QPushButton* myButton;
};
#endif // MAINWINDOW_H
然后在 MainWindow.cpp 中自己设置和 connect 即可。
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
myButton = new QPushButton(this);
myButton->setText("hello world");
connect(myButton,&QPushButton::clicked,this,&MainWindow::clickHandle);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::clickHandle()
{
if(myButton->text() == "hello world")
{
myButton->setText("hello qt");
}
else
{
myButton->setText("hello world");
}
}
可以看到确实实现了。
QT的坐标系
QT的坐标系并不是以左下角为(0,0)的,而是以左上角为 (0,0) 的,也就是左手坐标系。
这也是为什么我们使用代码的方式来使用控件的时候,它们的位置默认在左上角。
我们可以通过 move 函数来移动它们的位置。
我们将 myButton 按钮移动到距离 MainWindow 的 (0,0) 位置 为 (200,500) 的位置。
发现按钮的位置不在左上角了!
而 MainWindow 此时是 myButton 这个对象的父节点,那么 MainWindow 呢?它的父节点呢?
其实 MainWindow 的父节点就是显示器,也就是说如果我们调用 MainWindow 的 move 函数,就能修改窗口的位置!
我们在 main.cpp 中调用 move 函数。
发现位置改变了。
而 move 函数移动的单位是什么呢?实际上就是电脑显示器的像素点。
总结
通过本文我们了解了 QT 能够通过图形化界面简单快速的实现一个页面,也能够通过代码直接使用控件。
并且了解到 QT 开辟的内存可以通过挂在对象树的方式来控制生命周期,而不用手动释放。并且了解到一些前置的信号与槽的见到应用,以及QT的坐标系。相信对大家一定会有所帮助。