day47

 绘制事件


1>    对于QT窗口而言,最先接触的是绘制事件,整个窗口的内容都是有绘制事件绘制出来的
2>    触发条件:当窗口第一次展示出来、由最小化重新展示出来、窗口最大化、由最大化转变正常、改变窗口大小、使用updata函数进行更新界面时
3>    在绘制事件处理函数中,可以使用画家类对界面进行相关绘制工作
4>    实现实例
头文件
 

#ifndef WIDGET_H
#define WIDGET_H
 
 
#include <QWidget>
 
 
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
 
 
class Widget : public QWidget
{
    Q_OBJECT
 
 
public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
 
 
    //重写自己的绘制事件处理函数
    void paintEvent(QPaintEvent *event) override;
 
 
private:
    Ui::Widget *ui;
};
#endif // WIDGET_H
 
 
源文件
 

#include "widget.h"
#include "ui_widget.h"
#include<QDebug>
#include<QPainter>          //画家类
 
 
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
}
 
 
Widget::~Widget()
{
    delete ui;
}
 
 
//绘制事件处理函数的定义
void Widget::paintEvent(QPaintEvent *event)
{
    //static int num = 0;
    //qDebug()<<num++;
    QPainter painter(this);           //实例化一个画家
 
 
    //准备画笔
    QPen pen;
    pen.setStyle(Qt::DashDotLine);       //使用的是虚点线
    pen.setColor(QColor("red"));           //设置画笔颜色
    pen.setWidth(10);                   //设置画笔的粗细
 
 
    //准备字体
    QFont font;
    font.setFamily("楷体");        //设置字体族
    font.setStyle(QFont::StyleItalic);    //设置字体倾斜
    font.setPointSize(40);             //设置字号
 
 
    //给画家安排上画笔
    painter.setPen(pen);
    //给画家安排字体
    painter.setFont(font);
 
 
 
 
    //绘制文本
    painter.drawText(this->rect(),            //绘制的区域矩形框
                     Qt::AlignCenter,          //绘制的对齐方式
                     "好好学习,天天向上");      //绘制的文本内容
 
 
    //绘制矩形框
    painter.drawRect(50,50,this->width()-100, this->height()-100);
 
 
 
 
    //设置画家的坐标起点
    painter.translate(this->width()/2,this->height()/2);
 
 
    //设置绘制坐标正方向
    painter.rotate(45);      //参数 为旋转的坐标方向
 
 
    //绘制一个椭圆
    painter.drawEllipse(QPoint(0,0), 300, 200);
 
 
 
 
}
6>    使用绘制事件完成画图软件
头文件
 

#ifndef WIDGET_H
#define WIDGET_H
 
 
#include <QWidget>
#include<QMouseEvent>        //鼠标事件
#include<QPaintEvent>         //绘制事件
#include<QPainter>           //画家类
#include<QPixmap>
 
 
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
 
 
class Widget : public QWidget
{
    Q_OBJECT
 
 
public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
    //重写相关事件处理函数
    void mouseMoveEvent(QMouseEvent *event) override;        //鼠标移动事件
    void mousePressEvent(QMouseEvent *event) override;       //鼠标按下事件
    void paintEvent(QPaintEvent *event) override;            //绘制事件
 
 
 
 
private:
    Ui::Widget *ui;
    QPoint startPoint;      //绘制的起始点
    QPixmap *pix;           //膜
};
#endif // WIDGET_H
源文件
 

#include "widget.h"
#include "ui_widget.h"
 
 
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    //实例化屏幕膜
    pix = new QPixmap(this->size());      //实例化一个膜大小跟当前界面一致
    pix->fill(Qt::white);               //使用白色进行填充
 
 
 
 
}
 
 
Widget::~Widget()
{
    delete ui;
}
 
 
//鼠标移动事件
void Widget::mouseMoveEvent(QMouseEvent *event)
{
    //在该事件处理函数中,要在膜上绘制一条直线
    //1、实例化一个画家
    QPainter p1(pix);    //父组件应该是膜的地址
 
 
    //2、对画家进行属性设置
    QPen pen;
    pen.setStyle(Qt::DashDotLine);       //使用的是虚点线
    pen.setColor(QColor("green"));           //设置画笔颜色
    pen.setWidth(5);                   //设置画笔的粗细
 
    p1.setPen(pen);       //设置画笔
 
    //2、使用画家在两点之间画直线
    p1.drawLine(startPoint, event->pos());      //起始点到鼠标当前位置绘制直线
    startPoint = event->pos();             //更新起始点,以便于下一次的绘制
 
 
    //3、更新界面内容
    this->update();
}
 
 
//鼠标点击事件实现
void Widget::mousePressEvent(QMouseEvent *event)
{
    startPoint = event->pos();       //获取画笔的起始点
}
 
 
//绘制事件
void Widget::paintEvent(QPaintEvent *event)
{
    //在该事件处理函数中,将膜上面的内容绘制到界面上
    //1、准备一个画家,在界面上进行绘制
    QPainter p2(this);
 
 
    //2、将pix绘制到界面上
    p2.drawPixmap(QPoint(0,0), *pix);
}

一、回顾TCP网络通信步骤

 
二、QT中的TCP网络通信


2.1    服务器端(QTcpServer)


1>    使用QTcpServer类实例化一个对象,就得到了一个服务器端
2>    调用该类对象的成员函数 listen 将服务器启动监听,该函数会进行绑定ip和端口号
ip地址可以指定也可以由系统自动绑定,端口号也可以自己指定和由系统自动指定
3>    当有客户端发来连接请求后,该服务器就会自动发射一个newConnection的信号
我们可以将该信号绑定到自定义的槽函数中完成相关逻辑
4>    可以使用类中的成员函数 nextPenddingConnection 可以获取最新连接的客户端套接字
5>    可以使用该客户端套接字进行数据收发
read、readLine、readAll读取数据
write发送数据
6>    当服务器收到客户端的消息后,该服务器会自动发射一个readyRead的信号
可以将该信号连接到对应的槽函数中,处理客户端发来的消息
7>    调用成员函数close关闭监听
 
ui界面

头文件
 

#ifndef WIDGET_H
#define WIDGET_H
 
 
#include <QWidget>
#include<QTcpServer>        //tcp服务器类
#include<QTcpSocket>        //tcp客户端类
#include<QList>             //链表类
#include<QMessageBox>       //消息对话框类
#include<QDebug>            //信息调试类
 
 
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
 
 
class Widget : public QWidget
{
    Q_OBJECT
 
 
public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
 
 
private slots:
    void on_startSerBtn_clicked();
 
 
    void newConnection_slot();          //自定义处理newConnection信号的槽函数
    void readyRead_slot();               //自定义处理readyRead信号的槽函数
 
 
private:
    Ui::Widget *ui;
    QTcpServer *server;         //定义服务器指针
    QList<QTcpSocket *> socketList;     //定义存放客户端信息的容器
};
#endif // WIDGET_H
源文件
 

#include "widget.h"
#include "ui_widget.h"
 
 
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    //实例化一个服务器对象
    server = new QTcpServer(this);
 
 
 
 
}
 
 
Widget::~Widget()
{
    delete ui;
}
 
 
//启动服务器按钮对应的槽函数
void Widget::on_startSerBtn_clicked()
{
    if(ui->startSerBtn->text() == "启动服务器")
    {
        //执行启动服务器的动作
        //获取ui界面上的端口号
        quint16 port = ui->portEdit->text().toUInt();
 
 
        //启动监听:bool listen(const QHostAddress &address = QHostAddress::Any, quint16 port = 0);
        //参数1:要监听的ip地址,如果写Any,表示监听该主机上的所有网络接口
        //参数2:要监听的端口号,如果不指定,系统会默认给绑定一个随机端口号
        //返回值:成功监听返回真,失败返回假
        if(!server->listen(QHostAddress::Any, port))
        {
            QMessageBox::critical(this, "错误", "服务器启动失败");
            return;
        }
 
 
        //程序执行至此,表示服务器启动成功
        QMessageBox::information(this, "成功", "服务器启动成功");
 
 
        //将航编辑器设置为不可用
        ui->portEdit->setEnabled(false);
        //将按钮文本内容设置为关闭服务器
        ui->startSerBtn->setText("关闭服务器");
 
 
        //此时,如果有客户端发来连接请求,那么该服务器就会自动发射一个newConnection的信号
        //我们可以将该信号连接到自定义的槽函数中,处理后续操作
        connect(server, &QTcpServer::newConnection, this, &Widget::newConnection_slot);
 
 
    }else
    {
        //执行关闭服务器的动作
        server->close();
        
        //将行编辑器设置成可用状态
        ui->portEdit->setEnabled(true);
        //将按钮文本内容设置为启动服务器
        ui->startSerBtn->setText("启动服务器");
    }
}
 
 
//自定义处理newConnection信号的槽函数的实现
void Widget::newConnection_slot()
{
    qDebug()<<"有新的客户端发来连接请求了";
 
 
    //可以通过成员函数 nextPendingConnection函数获取最新连接的客户端套接字的地址
    //函数原型:QTcpSocket *nextPendingConnection();
    //无参函数
    //返回值:最新的一个连接的套接字地址
    QTcpSocket * s = server->nextPendingConnection();
 
 
    //将该套接字放入客户端链表中
    socketList.push_back(s);
 
 
    //程序执行至此,一个服务器可以对应多个客户端,已经建立了连接
    //此时,如果有某个客户端发来数据,那么该客户端套接字就会自动发射一个readyRead的信号
    //我们可以将该信号连接到自定义的槽函数中处理相关逻辑
    connect(s, &QTcpSocket::readyRead, this, &Widget::readyRead_slot);
}
 
 
//自定义处理readyRead信号的槽函数的实现
void Widget::readyRead_slot()
{
    //1、遍历链表中的所有客户端,如果客户端的状态为未连接,则直接移除出链表
    for(int i=0; i<socketList.size(); i++)
    {
        //判断当前套接字 socketList[i] 是否实效
        //函数原型:SocketState state() const;
        //功能:返回当前套接字的状态
        //返回结果为0时,表示该套接字是未连接状态
        if(socketList[i]->state()==0)
        {
            //将该套接字移除出链表
            socketList.removeAt(i);
        }
    }
 
 
    //2、遍历所有客户端,判断客户端中是否有数据可读,如果有数据可读,则表示是该客户端发来的消息、
    for(int i=0; i<socketList.count(); i++)
    {
        //判断当前 客户端中是否有数据可读
        //函数原型:qint64 bytesAvailable() const override;
        //参数无
        //返回值:返回当前客户端套接字中的待读数据,如果没有数据,则返回0
        if(socketList[i]->bytesAvailable() != 0)
        {
            //读取当前套接字的内容
            QByteArray msg = socketList[i]->readAll();
 
 
            //将接受的消息展示到ui界面上
            ui->msgListWidget->addItem( QString::fromLocal8Bit(msg) );
 
 
            //将收到的消息,全部发给其他客户端
            for(int j=0; j<socketList.length(); j++)
            {
                if(i!=j)          //防止自己发给自己
                {
                    socketList[j]->write(msg);
                }
            }
        }
    }
}
 
 
 


2.2    客户端(QTcpSocket)


1>    使用该类实例化一个对象,就创建了一个客户端
2>    使用该类对象的成员函数 connectToHost 向服务器发送连接请求
如果连接服务器成功,那么该客户端套接字就会自动发射一个 connected 的信号
可以将该信号连接到自定义的槽函数中处理相关逻辑
3>    可以使用该客户端套接字进行数据收发
read、readLine、readAll读取数据
write发送数据
4>    如果客户端收到服务器发来的消息后,该客户端就会自动发射一个readyRead的信号
可以将该信号连接到对应的槽函数中,处理客户端发来的消息
5>    调用成员函数 disconnectFromHost 断开跟服务器的连接
 
ui界面

头文件
 

#ifndef WIDGET_H
#define WIDGET_H
 
 
#include <QWidget>
#include<QTcpSocket>         //客户端套接字类
#include<QMessageBox>        //消息对话框类
 
 
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
 
 
class Widget : public QWidget
{
    Q_OBJECT
 
 
public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
 
 
private slots:
    void on_connectBtn_clicked();
    void connected_slot();           //自定义处理connected信号的槽函数
    void readyRead_slot();           //自定义处理readyRead信号的槽函数
    void disconnected_slot();        //自定义处理disconnected信号的槽函数
 
 
    void on_sendBtn_clicked();
 
 
    void on_disConnectBtn_clicked();
 
 
private:
    Ui::Widget *ui;
 
 
    //定义通信用的变量
    QTcpSocket *client;         //定义套接字指针
    QString userName;           //用户名
 
 
};
#endif // WIDGET_H
源文件
 

#include "widget.h"
#include "ui_widget.h"
 
 
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    //实例化客户端对象
    client = new QTcpSocket(this);
 
 
    //当客户端与服务器建立联系后,如果客户端接受到服务器发来的消息
    //客户端自身就会自动发射一个 readyRead的信号,我们可以将该信号连接到自定义的槽函数中执行相关逻辑
    connect(client, &QTcpSocket::readyRead, this, &Widget::readyRead_slot);
 
 
    //如果当前客户端成功连接的服务器,那么该客户端就会自动发射一个connected的信号
    //我们可以将该信号连接到自定义的槽函数中处理相关逻辑
    connect(client, &QTcpSocket::connected, this, &Widget::connected_slot);
 
 
 
 
    //当客户端断开了与服务器的连接后,该客户端就会自动发射一个disconnected的信号
    //我们可以将该信号连接到自定义的槽函数中处理相关逻辑
    connect(client, &QTcpSocket::disconnected, this, &Widget::disconnected_slot);
 
 
}
 
 
Widget::~Widget()
{
    delete ui;
}
 
 
//连接服务器按钮对应的槽函数
void Widget::on_connectBtn_clicked()
{
    //获取ui界面上的数据
    QString ip = ui->ipEdit->text();     //ip地址
    quint16 port = ui->portEdit->text().toUInt();    //端口号
    userName = ui->nameEdit->text();              //用户名
 
 
 
 
    //调用套接字成员函数,连接服务器
    //函数原型:void connectToHost(const QHostAddress &address, quint16 port, OpenMode mode = ReadWrite);
    //参数1:要被连接的服务器ip地址
    //参数2:服务器的端口号
    //参数3:默认为可读可写
    //返回值:无
    client->connectToHost(ip, port);
 
 
 
 
}
 
 
//处理connected信号的槽函数的定义
void Widget::connected_slot()
{
    QMessageBox::information(this,"成功","连接成功");
    //将相关组件禁用
    ui->ipEdit->setEnabled(false);
    ui->nameEdit->setEnabled(false);
    ui->portEdit->setEnabled(false);
    ui->connectBtn->setEnabled(false);
 
 
    //向服务器发送一条消息
    QString msg = userName + ": 进入聊天室";
    client->write( msg.toLocal8Bit() );
 
 
}
 
 
//自定义处理readyRead信号的槽函数
void Widget::readyRead_slot()
{
    //从套接字中读取数据
    QByteArray msg = client->readAll();
 
 
    //将读取下来的数据展示到ui界面上
    ui->msgListWidget->addItem( QString::fromLocal8Bit(msg) );
}
 
 
 
 
 
 
 
 
//消息发送按钮对应的槽函数
void Widget::on_sendBtn_clicked()
{
    //组织要发送的消息
    QString msg = userName + ": " + ui->msgEdit->text();
 
 
    //将消息发送给服务器
    client->write(msg.toLocal8Bit());
 
 
    //将消息展示到自己界面上
    //准备一个QListWidgetItem类的对象
    QListWidgetItem *item = new QListWidgetItem(msg);
    item->setTextAlignment(Qt::AlignRight);        //将文本右对齐
    ui->msgListWidget->addItem(item);
 
 
    //清空消息发送框的内容
    ui->msgEdit->clear();
 
 
}
//断开连接按钮对应的槽函数
void Widget::on_disConnectBtn_clicked()
{
    //执行断开连接的操作
    //准备发送消息给服务器
    QString msg = userName + ": 离开聊天室";
    client->write(msg.toLocal8Bit());
 
 
    //断开连接
    client->disconnectFromHost();
 
 
 
 
 
 
}
 
 
//自定义处理disconnected信号的槽函数的定义
void Widget::disconnected_slot()
{
    QMessageBox::information(this, "提示", "成功断开与服务器的连接");
 
 
    //将相关组件启用
    ui->ipEdit->setEnabled(true);
    ui->nameEdit->setEnabled(true);
    ui->portEdit->setEnabled(true);
    ui->connectBtn->setEnabled(true);
}

时钟

widget.h
#ifndef WIDGET_H
#define WIDGET_H
 
 
#include <QWidget>
#include <QPaintEvent>
#include <QTimer>
#include <QPainter>
#include <QPen>
#include <QBrush>
#include <QTime>
#include <QDebug>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
 
class Widget : public QWidget
{
    Q_OBJECT
 
public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
    //重写自己的绘制事件处理函数
    void paintEvent(QPaintEvent *event) override;
public slots:
 
    void slot();
private:
    Ui::Widget *ui;
    QTimer *timer;
    int hour;
    int minute;
    int second;
};
#endif // WIDGET_H
main.cpp
#include "widget.h"
 
#include <QApplication>
 
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
}
widget.cpp
#include "widget.h"
#include "ui_widget.h"
 
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    // 初始化定时器
       QTimer *timer = new QTimer(this);
       // 设置定时器每秒钟触发一次
       timer->setInterval(1000);
       // 将定时器的timeout信号连接到slot槽函数
       connect(timer, &QTimer::timeout, this, &Widget::slot);
       // 启动定时器
       timer->start();
}
Widget::~Widget()
{
    delete ui;
}
 
void Widget::paintEvent(QPaintEvent *event)
{
 
    QPainter painter(this);//实例化一个画家
    QPen pen;// 准备画笔
    pen.setStyle(Qt::SolidLine);// 设置画笔样式为直线
    pen.setColor(QColor("red"));// 设置画笔颜色为红色
    pen.setWidth(10);// 设置画笔粗细为10像素
    //准备字体
    QFont font;
    font.setFamily("楷体");        //设置字体族
    font.setStyle(QFont::StyleNormal);    //设置字体为正常
    font.setPointSize(40);             //设置字号
    //给画家安排上画笔
    painter.setPen(pen);
    //设置画家的坐标起点
    painter.translate(this->width()/2,this->height()/2);
    //绘制一个圆
    painter.drawEllipse(QPoint(0,0), 200, 200);
    pen.setColor(QColor("black"));
    painter.setPen(pen);
    for(int i=0;i<60;i++)           //绘制分钟线
    {
        painter.rotate(6);
        painter.drawLine(QPoint(200,0),QPoint(195,0));
    }
 
    pen.setWidth(10);
    painter.setPen(pen);
    for(int i=1;i<=12;i++)       //绘制时钟线
    {
        painter.drawLine(QPoint(200,0),QPoint(190,0));
        painter.rotate(30);
        painter.drawText(QPoint(0,-170),QString("%1").arg(i));
    }
 
    //时针
    pen.setWidth(15);
    pen.setColor(QColor("red"));
    painter.setPen(pen);
    painter.rotate(hour*30+30/60*minute+30/60/60*second);
    painter.drawLine(QPoint(0,-50),QPoint(0,5));
 
    //分针
    QPainter p1(this);
    p1.translate(this->width()/2,this->height()/2);
    pen.setWidth(10);
    pen.setColor(QColor("blue"));
    p1.setPen(pen);
    p1.rotate(minute*6+6*second/60);
    p1.drawLine(QPoint(0,-80),QPoint(0,8));
 
    //秒针
    QPainter p2(this);
    p2.translate(this->width()/2,this->height()/2);
    pen.setWidth(5);
    pen.setColor(QColor("green"));
    p2.setPen(pen);
    p2.rotate(6*second);
    p2.drawLine(QPoint(0,-120),QPoint(0,12));
}
 
void Widget::slot()
{
    QDateTime currentDateTime = QDateTime::currentDateTime();
    QString currentTimeStr = currentDateTime.toString("hh:mm:ss");
    hour=currentDateTime.time().hour();
    minute=currentDateTime.time().minute();
    second=currentDateTime.time().second();
 
    this->update();
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值