一、QPainter绘图
1.整个绘图系统基于Qpainter,QPianterDevice和QPainEngine三个类
2.QPainter用来执行绘制的操作,QPaintDevice是一个二维空间的抽象,这个二维空间允许QPainter在上面进行绘制,也就是QPainter的工作空间。
3.QPiantEngine提供了画笔(QPianter)在不同设备上绘制统一的接口。QPaintEngine类应用于QPainter和QPaintDevice之间,使用人员不必了解其细节。
可以将QPianter理解成一个画家,将QPainterDevice理解为纸张或者是屏幕。
4.Qt的绘图系统实际上就是使用QPianter在QPainterDevice上进行绘制,它们之间使用QPainEngine进行通讯(也就是翻译QPainter的指令)。
rectangular :矩形结构
rectangle:区域
brush:笔刷
ellipse:椭圆
setPen:设置画笔画出的边框的颜色
setBrush:设置画笔画出的区域的颜色
5.QPainter有很多以draw开头的函数,用于各种图形的绘制,比如:drawLine()、drawRect()、drawEllipse()等
6.QPainter绘图主要属性
Qpen:画笔,用来控制线条的颜色和宽度等
QBrush:画刷,用来填充颜色、渐变特性等
QFont:字体的属性,用来绘制文字时,设置文字的样式和大小等等
练习一:在窗口中设置背景图片
第一步:widget.h文件中重写绘图事件
#ifndef WIDGET_H
#define WIDGET_H
#include
#include
#include
#include
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
protected:
void paintEvent(QPaintEvent *);
//重写绘图事件 虚函数
//如果在窗口绘图,必须放在放在绘图事件里实现
//窗口需要重绘时(窗口放大缩小时),绘图事件自动调用(背景图片也作出相应的变化)
private:
Ui::Widget *ui;
};
#endif // WIDGET_H
第二步:在widget.cpp中实现绘图事件
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
}
void Widget::paintEvent(QPaintEvent *)
{
QPainter p(this);
//实例化一个画家,并将此窗口作为他的画图设备
QPixmap pix;
pix.load("../image/picture.png");
//图片放在和项目同级的文件夹中
p.drawPixmap(0,0,width(),height(),pix);
//p.darwPixmap(0.0.width(),height(),Qpixmap("../image/picture.png"));
//从原点出发,指定高度为窗口的高度,指定宽度为窗口的宽度
}
Widget::~Widget()
{
delete ui;
}
第三步:结果显示
练习二:在窗口中绘制直线、圆形和矩形、显示文字等
#ifndef WIDGET_H
#define WIDGET_H
#include
#include
#include
#include
#include
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
protected:
void paintEvent(QPaintEvent *);
private:
Ui::Widget *ui;
};
#endif // WIDGET_H
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
}
void Widget::paintEvent(QPaintEvent *)
{
QPainter p(this);
p.drawPixmap(0,0,width(),height(),QPixmap("../image/p.png"));
QPen pen;
//定义画笔
pen.setWidth(5);
pen.setColor(Qt::red);//设置颜色
//pen.setColor(QColor(14,9,23));
//rgb设置颜色
p.setPen(pen);
p.drawEllipse(40,40,100,100);
p.drawEllipse(80,80,100,100);
p.drawLine(50,80,90,40);
//从坐标点(50,80)到坐标点(90,40)
p.drawRect(180,180,50,80);
p.drawLine(500,500,80,90);
QBrush bursh;
bursh.setColor(Qt::blue);
bursh.setStyle(Qt::SolidPattern);
p.setBrush(bursh);
p.drawRect(500,500,80,90);
QFont font;
font.setPointSize(40);
font.setBold(true);
p.setFont(font);
p.drawText(600,600,QString("多云"));
}
Widget::~Widget()
{
delete ui;
}
二、绘图设备(QPixmap、QImage、QBitmap、QPicture)
1.绘图设备是指继承QPainterDevice的子类。Qt一共提供了四个这样的类,分别是QPixmap、QBitmap、QImage和QPicture。
2.QPixmap专门为图像在屏幕上的显示做优化,因此他与底层显示设备息息相关,这里指的底层显示设备并不是硬件,而是操作系统所提供的原生的绘图引擎。
3.QBitmap是QPixmap的一个子类,它的色深限定为1,可以使用QPixmap的isQBitmap()函数来确定这个QPixmap是不是一个QBitmap。
4.QImage专门为图像的像素级访问做了优化,是独立于硬件的绘制系统,实际上就是自己绘制自己。
5.QPicture可以记录和重现QPainter的各条命令。
三、文件操作
(QFile,QFileInfo、QDataStream、QTextStream、QBuffter)
1.Qt作为通用开发库,提供了跨平台的文件操作能力。
2.Qt通过QIODevice提供了对 I/O 设备的抽象,这些设备具有读写字节块的能力。
QIODevice:所有 I/O 设备类的父类,提供了字节块读写的通用操作以及基本接口;
QFileDevice:Qt5新增加的类,提供了有关文件操作的通用实现。
QFlie:访问本地文件或者嵌入资源;
QTemporaryFile:创建和访问本地文件系统的临时文件;
QBuffer:读写QbyteArray, 内存文件;
QProcess:运行外部程序,处理进程间通讯;
QAbstractSocket:所有套接字类的父类;
QTcpSocket:TCP协议网络数据传输;
QUdpSocket:传输 UDP 报文;
QSslSocket:使用 SSL/TLS 传输数据;
四、文件系统分类
1.顺序设备
指它们的数据只能访问一遍:从头走到尾,从第一个字节开始访问,直到最后一个字节,中途不能返回去读取上一个字节。这其中QProcess、QTcpSocket、QUdpSocket和QSslScoket是顺序访问设备。
2.随机访问设备
可以访问任意位置任意次数,还可以使用QIODevice::seek()函数来重新定位文件访问位置指针,QFile、QTemporaryFile和QBuffer是随机访问设备。
五、基本的文件操作
1.QFile提供了从文件中读取和写入的能力。通常将文件路径作为参数传给QFile的构造函数。也可以创建好对象之后,使用setFileName来修改。QFile需要使用 / 作为文件分隔符,不过,它会自动将其转换成操作系统所需要的形式。例如 C:/windows 这样的路径在 Windows 平台下同样是可以的。
QFile主要提供了有关文件的各种操作,比如打开文件、关闭文件、刷新文件等。我们可以使用QDataStream或QTextStream类来读写文件,也可以使用QIODevice类提供的read()、readLine()、readAll()以及write()这样的函数。值得注意的是,有关文件本身的信息,比如文件名、文件所在目录的名字等,则是通过QFileInfo获取,而不是自己分析文件路径字符串。
QFile提供了各种有关的文件操作,比如打开文件、关闭文件、刷新文件内等。可以使用QDataStream和QTextStream来读写文件,也可以使用QIODevice类提供的read(),readline(),readAll(),write()这样的函数。但是有关文件本身的信息,需要使用QFileInfo获取,而不是自己分析文件路径字符串。
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QFile file("in.txt");
//使用QFile创建一个文件对象,文件名为in.txt
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
qDebug() << "Open file failed.";
return -1;
//使用open函数打开这个文件,打开方式为只读
} else {
while (!file.atEnd()) {
qDebug() << file.readLine();
}
}
QFileInfo info(file);
qDebug() << info.isDir();
//该文件是否为目录
qDebug() << info.isExecutable();
//该文件是否为可执行文件
qDebug() << info.baseName();
//直接获得文件名
qDebug() << info.completeBaseName();
//获取完整的文件名
qDebug() << info.suffix();
//获取文件后缀名
qDebug() << info.completeSuffix();
//获取完整的文件后缀名
return app.exec();
}
练习三:选择文件,在QLineEdit和TextEdit中输入字符串,点击提交按钮写入到选择的文件中
//MainWindow.h文件
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
public slots:
void onFileClicked();
//选择相应的文件
void onSubmitTextClicked();
void onSubmitSerialClicked();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
//logger.h文件
#ifndef LOGGER_H
#define LOGGER_H
void SetLogFile(const char *name);
void LogInit();
#endif // LOGGER_H
//logger.cpp文件
#include "qdebug.h"
#include
#include
#include
#include
#include
#include
#include "mainwindow.h"
using namespace std;
static char *logfile_name = NULL;
QMutex logMutex;
void SetLogFile(const char *name)
{
logMutex.lock();
logfile_name = (char *)name;
printf("name=%s\n", logfile_name);
logMutex.unlock();
}
void outputMessage(QtMsgType type, const QMessageLogContext &context, const QString &msg)
//const QString &msg
{
if (logfile_name == NULL)
return;
QString text;
switch(type)
{
case QtDebugMsg:
text = QString("Debug:");
break;
case QtWarningMsg:
text = QString("Warning:");
break;
case QtCriticalMsg:
text = QString("Critical:");
break;
case QtFatalMsg:
text = QString("Fatal:");
break;
case QtInfoMsg:
text = QString("Info:");
}
QString context_info= QString("File:(%1) Line:(%2)").arg(QString(context.file)).arg(context.line);
QString current_date_time = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
QString current_date = QString("(%1)").arg(current_date_time);
QString message = QString("%1 %2 %3 %4").arg(current_date).arg(context_info).arg(text).arg(msg);
logMutex.lock();
QFile file(logfile_name);
file.open(QIODevice::WriteOnly | QIODevice::Append);
QTextStream text_stream(&file);
text_stream.setCodec(QTextCodec::codecForName("utf-8"));
// QTextCodec *codec =QTextCodec::codecForName("utf-8");
// QTextCodec::setCodecForLocale(codec);
text_stream << message << "\r\n";
file.flush();
file.close();
logMutex.unlock();
}
void LogInit()
{
qInstallMessageHandler(outputMessage);
}
//mainwidow.cpp文件
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "logger.h"
#include
#include
#include
#include
#include
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
QTextCodec *codec = QTextCodec::codecForName("GDK");
ui->lineEdit_file->setEnabled(false);
//关闭写功能,只能选择文件
connect(ui->pushButton_file, &QPushButton::clicked, this, &MainWindow::onFileClicked);
connect(ui->pushButton_serial, &QPushButton::clicked, this, &MainWindow::onSubmitSerialClicked);
connect(ui->pushButton_text, &QPushButton::clicked, this, &MainWindow::onSubmitTextClicked);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::onFileClicked()
{
QString fileName = QFileDialog::getOpenFileName(
this,
tr("打开文件"),
"D:/",
tr("*.txt;;*.log"));
if (fileName.isEmpty()) {
QMessageBox::warning(this, "Warning!", "Failed to open the file!");
}
else {
ui->lineEdit_file->setText(fileName);
char *ch=fileName.toLatin1().data();
SetLogFile(ch);
// QByteArray byte = fileName.toLatin1();
// SetLogFile(byte.data());
}
}
void MainWindow::onSubmitSerialClicked()
{
QString ser = ui->lineEdit_serial->text();
qInfo("Serial = %s",qPrintable(ser));
}
void MainWindow::onSubmitTextClicked()
{
QString text = ui->textEdit_text->toPlainText();
qInfo("text = %s",qPrintable(text));
ui->textEdit_text->clear();
}
//main.cpp文件
#include "mainwindow.h"
#include
#include "logger.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
LogInit();
SetLogFile("d://xxx.txt");
//设置默认的日志文件为xxx.txt
qDebug("test log");
qWarning("test log warnig");
w.show();
return a.exec();
}
//实现将输入的内容通过按钮添加到文本文件中
//写入到文本文件中出现乱码
//试着能不能从文件中读取到信息再添加到这个文本文件中
结果显示:
存在的问题:写入中文字符 出现乱码,还未解决
练习四:输入ip地址,测试能否ping通
//widget.h 文件
#ifndef WIDGET_H
#define WIDGET_H
#include
#include
#include
#include
#include
#include
#include
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
public slots:
void Myping();
private:
Ui::Widget *ui;
};
#endif // WIDGET_H
//widget.cpp文件
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//使用正则表达式限制输入
ui->lineEdit_ip->setValidator(new QRegExpValidator(QRegExp("\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\b")));
connect(ui->pushButton_ip,&QPushButton::clicked,this,&Widget::Myping);
}
void Widget::Myping()
{
qDebug()<<QStringLiteral("开始点击");
ui->textBrowser->clear();
ui->textBrowser->setText(QStringLiteral("请等待"));
ui->textBrowser->update();
QProcess myProcess(this);
QString program = "C:/Windows/System32/cmd.exe";
QStringList arguments;
QString ipaddr;
// 正则表达式限制输入
ipaddr = ui->lineEdit_ip->text();
//用户输入的内容
QString message = "ping " + ipaddr;
//和ping命令拼接,字符串的拼接直接+链接就可
qDebug()<<message;
//将拼接后的结果在应用程序输出的位置打印一下
// 用于占位
//arguments=ui->lineEdit_ip->setInputMask("000.000.000.000; ");
//arguments <<"/c" <<"ping www.baidu.com";
arguments <<"/c" <<message;
myProcess.start(program,arguments);
while (myProcess.waitForFinished(100) == false) {
QByteArray qByteRead = myProcess.readAllStandardOutput();
if (!qByteRead.isEmpty()) {
ui->textBrowser->append(QString::fromLocal8Bit(qByteRead));
repaint();
}
}
QByteArray qByteRead = myProcess.readAllStandardOutput();
ui->textBrowser->append(QString::fromLocal8Bit(qByteRead));
qDebug()<<QString::fromLocal8Bit(qByteRead);
//输出应用程序输出上
qDebug()<<"结束点击";
}
Widget::~Widget()
{
delete ui;
}
结果显示:
练习五:选择文件,然后将文件中的内容读出到文本框中
//widge.h 文件
#ifndef WIDGET_H
#define WIDGET_H
#include
#include
#include
#include
#include
#include
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
void SetLogFile(const char *name);
private:
Ui::Widget *ui;
};
#endif // WIDGET_H
#include "widget.h"
#include "ui_widget.h"
static char *filename = NULL;
QMutex logMutex;
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
ui->lineEdit->setEnabled(false);
connect(ui->pushButton,&QPushButton::clicked,this,
[=]()
{
QString fileName = QFileDialog::getOpenFileName(
this,
tr("打开文件"),
"D:/",
tr("*.txt;;*.log"));
if (fileName.isEmpty()) {
QMessageBox::warning(this, "Warning!", "Failed to open the file!");
}
else {
ui->lineEdit->setText(fileName);
char *ch=fileName.toLatin1().data();
SetLogFile(ch);
}
}
);
connect(ui->pushButton_r,&QPushButton::pressed,this,
[=]()
{
QFile file(filename);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
qDebug() << "Open file failed.";
return ;
} else {
while (!file.atEnd()) {
ui->textBrowser->setText(file.readAll());
}
}
});
}
void Widget::SetLogFile(const char *name)
{
logMutex.lock();
filename = (char *)name;
printf("name=%s\n", filename);
logMutex.unlock();
}
Widget::~Widget()
{
delete ui;
}
六、二进制文件的读写
1.QDataStream提供了基于QIODevice的二进制数据的序列化。数据流是一种二进制流。数据流是一种二进制流,这种流完全不依赖于底层操作系统、CPU
或者字节顺序(大端或小端)。