Qt的学习笔记

QT

QT概述

Qt是一个跨平台的C++图形用户界面应用程序框架。

QT下载用清华的镜像,速度快。

QT优点

  • 跨平台
  • 接口简单
  • 简化了内存回收机制
  • 开发效率高
  • 有很好的社区氛围
  • 可以进行嵌入式开发

创建项目

Qwidget为父类 QMainWindow QDialog为子类 QMainWindow比父类多菜单栏、状态栏 QDialog对话框

main.cpp

#include "mywidget.h"
#include <QApplication>//包含一个应用程序类的头文件
//命令行变量的数量 命令行变量的数组
int main(int argc, char *argv[])
{
    //a为应用程序对象,在QT中有且仅有一个
    QApplication a(argc, argv);
    //窗口对象
    myWidget w;
    //调用show显示窗口
    w.show();
	 //让应用程序对象进入消息循环,代码阻塞到当前行,不会一闪而过
    return a.exec();
}

.por文件解释

QT       += core gui //QT包含的模块

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets//大于4版本以上包含QT的widgets模块

TARGET = 01_project//目标 生成的.exe程序的名称
TEMPLATE = app //模板 应用程序模板 Application


DEFINES += QT_DEPRECATED_WARNINGS



SOURCES += \   //源文件
        main.cpp \
        mywidget.cpp

HEADERS += \  //头文件
        mywidget.h

.h头文件

#ifndef MYWIDGET_H
#define MYWIDGET_H
//命名规范
//类名 首字母大写 单词和单词之间首字母大写
//函数名 变量名称 首字母小写,单词和单词之间首字母大写
//快捷键
//注释 ctrl+/
//运行 ctrl+r
//编译 ctrl+b
//字体缩放 ctrl+滚轮
//查找 ctrl+f
//整行 ctrl+shift+↑或者↓
//帮助文档F1
//自动对齐 ctrl+i
//同名之间的.h与.cpp 快速切换 F4
#include <QWidget> //包含头文件 窗口类

class myWidget : public QWidget //继承
{
    Q_OBJECT //宏,允许类中使用信号和槽的机制

public:
    myWidget(QWidget *parent = 0);  //构造函数
    ~myWidget();//析构函数
};

#endif // MYWIDGET_H

.cpp文件

#include "mywidget.h"

myWidget::myWidget(QWidget *parent)
    : QWidget(parent)//初始化列表 如果不指定构造函数,则派生类会调用基类的默认构造函数,派生类构造函数的初始化列表只能初始化派生类成员,不能直接初始化继承成员,如果想 要调用基类的有参构造函数,则可以在派生类的初始化列表中显示指定
{
	//一般自己写的代码
}

myWidget::~myWidget()
{

}

帮助文档

QPushButton Class
The QPushButton widget provides a command button. More...
//需要包含的头文件
    Header:
#include <QPushButton> 
//需要添加的模块
qmake:
QT += widgets
//父类
    Inherits:
QAbstractButton
    //子类
Inherited By:
QCommandLinkButton

List of all members, including inherited members 

QPushButton 按钮的基本使用

 //创建一个按钮
    QPushButton *btn=new QPushButton;
    //btn.show();//show以顶层的方式弹出窗口
    //让btn对象出现在mywidget窗口中
    btn->setParent(this);
    //设置文本
    btn->setText("第一个按钮");
    //设置控件大小
    btn->resize(50,50);
    //创建第二个按钮,按照控件大小创建窗口
    QPushButton *btn1=new QPushButton("第二个按钮",this);
    //两个按钮会在一块所以要移动
    btn1->move(100,0);
    //重置窗口大小
    resize(600,400);
    //设置固定窗口大小不可以移动
    setFixedSize(600,400);
    //设置窗口标题
    setWindowTitle("第一个窗口");

对象树

概念

当常见的对象再堆区时,如果指定的父亲是QObject派生下来的类或者QObject的子类派剩下来的类,可以不用管理释放的操作,将对象放入对象树中

例子:new Teacher(this)

窗口不能再放入窗口的对象树中

作用

一定程度上简化了回收机制

综上所述 在QT中创建对象时就指定父类对象

坐标系

左上角为(0,0)X向右 y向下

信号和槽

connect(信号发送者,发送的信号(函数地址 siginal),信号接收者,信号处理(槽 slot 函数的地址,信号的地址)) 第五个参数多线程时才有意义,默认使用队列 如果是单线程默认直接 队列槽函数所在的线程和接收者一样 直接 槽函数所在的线程和发送者一样

例子:

     connect(myBtn,&QPushButton::clicked,this,&myWidget::close);

信号槽的优点,松散耦合,信号发送端和接受段本身是没有关联的,通过connect连接将两端连接起来

自定义信号:

signals:
    //自定义信号写在此处
    //没有返回值 void 在信号里面只需要声明,不需要实现
    //可以有参数,可以重载
    void hungry();

自定义槽:

public slots:
    //早期QT版本 必须要写到public slots,高级版本可以写到public下或者全局下
    //返回值void 需要声明也需要实现
    //可以有参数,可以发生重载
    void treat();

自定义的连接

 //创建一个老师的对象,学生的对象
    this->zt=new Teacher(this);
    this->st=new Student(this);
   //先连接 connect(zt,&Teacher::hungry,st,&Student::treat);
//再触发
    classIsOver();

自定义触发

void Widget::classIsOver(){
    emit zt->hungry();
}

自定义的信号发送者,接收者 以及触发函数均需写在窗口类Widget的private中:

private:
    Ui::Widget *ui;
    Teacher *zt;
    Student *st;
    void classIsOver();

重载时

//重载
void hungry(QString foodName);
void Student::treat(QString foodName){
    qDebug()<<"请老师吃"+foodName;
}
//connect(zt,&Teacher::hungry,st,&Student::treat);
    //有多个信号和槽重载时用函数指针 函数类型(类名::参数名)(参数列表)=信号/槽
    void(Teacher::*teacherSignal)(QString)=&Teacher::hungry;
    void(Student::*studentSlot)(QString)=&Student::treat;
    connect(zt,teacherSignal,st,studentSlot);
    classIsOver();
//触发
void Widget::classIsOver(){
    emit zt->hungry("宫保鸡丁");
}

信号连接信号

void(Teacher::*teacherSignal)(void)=&Teacher::hungry;
void(Student::*studentSlot)(void)=&Student::treat;
connect(zt,teacherSignal,st,studentSlot);
connect(btn,&QPushButton::clicked,zt,teacherSignal);

断开信号

disconnect(zt,teacherSignal,st,studentSlot);
参数为 信号发送者,发送的信号(函数地址 siginal),信号接收者,信号处理(槽 slot 函数的地址,信号的地址)
    //信号是可以连接信号
    //一个信号可以连接多个槽函数
    //多个信号可以连接同一个槽函数
    //信号和槽函数的参数一一对应
    //信号的参数个数可以多余槽函数的个数,其余的类型也要一一对应  若出现信号参数少于槽函数参数个数 可以在槽函数用lambda
    connect(btn,&QPushButton::clicked,this,[=](){
        emit zt->hungry("宫爆鸡丁");
    });

lambda表达式

/*[标志着一个lambda的开始](参数)mutable->返回值类型{函数体};
	[] 
		空表示没有任何函数对象参数
		=表示lambda所在作用范围内所有可见的局部变量,为值传递方式
		&表示lambda所在作用范围内所有可见的局部变量,为引用传递方式 不建议
		this 类似于=
		a 只允许看到a
		&a 引用方式只允许看到a
		a,&b a按照值传递,b按照引用传递
		=,&a,&b 除a和b按引用进行传递外,其他都按照值传递
		&,a,b 除a,b按照值传递其他都按照引用传递
	()
	mutable 可以省略 按值传递对象参数时,加上mutable修饰符后可以修改按值传递进来的拷贝(只能修改拷贝,不能修改值本身)
	->返回值类型 有返回值时使用
*/

MainWindow

QMenuBar *bar=menuBar();//菜单栏最多只有一个
    //将菜单栏放入到窗口中
    setMenuBar(bar);
    //创建菜单
    QMenu * fileMenu=bar->addMenu("文件");
    QMenu * editMenu=bar->addMenu("编辑");

    //在文件下创建一个菜单项
    QAction * newAction=fileMenu->addAction("新建");
    //在新建和打开之间添加分隔符
    fileMenu->addSeparator();
    QAction * openAction=fileMenu->addAction("打开");


    //工具栏 可以有多个
    QToolBar * toolBar=new QToolBar(this);
    addToolBar(Qt::LeftToolBarArea,toolBar);
    //后期设置只允许工具栏左右停靠
    toolBar->setAllowedAreas(Qt::LeftToolBarArea | Qt::RightToolBarArea);
    //设置浮动
    toolBar->setFloatable(false);
    //设置移动 false之后工具栏不允许移动
    toolBar->setMovable(false);
    //在工具栏中添加内容
    toolBar->addAction(newAction);
    //工具栏添加分割线
    toolBar->addSeparator();
    toolBar->addAction(openAction);
    //在工具栏中添加控件
    QPushButton *btn=new QPushButton("aa",this);
    toolBar->addWidget(btn);//状态栏 最多只有一个
    QStatusBar * stBar=statusBar();
    setStatusBar(stBar);
    //标签控件
    QLabel * lable=new QLabel("提示信息",this);
    stBar->addWidget(lable);
    //右侧
    QLabel * lable2=new QLabel("提示信息",this);
    stBar->addPermanentWidget(lable2);


    //铆接窗口 (浮动窗口) 可以有多个
    QDockWidget * dockWidget=new QDockWidget("浮动",this);
    addDockWidget(Qt::BottomDockWidgetArea,dockWidget);
    //设置后期停靠区域,只允许上下
    dockWidget->setAllowedAreas(Qt::TopDockWidgetArea|Qt::BottomDockWidgetArea);

    //设置中心部件 只能有一个
    QTextEdit * edit=new QTextEdit(this);
    setCentralWidget(edit);

使用ui设计时十分方便,若要在代码中获得某个部件 可使用 ui->部件名字

添加资源文件

    //1.将要使用的文件添加到当前项目中2.在项目中添加新文件QtResource File 给资源文件起名字 res 生成res.qrc 打开方式右键open in editor 3.下方添加前缀 添加文件 4.使用“:+资源名+文件名”

对话框

connect(ui->actionnew,&QAction::triggered,this,[=](){
        //对话框 分类
        //模态对话框(不可以对其他窗口进行操作) 非模态对话框(可以对其他窗口进行操作)
        //模态创建 阻塞 的功能 即对话框不点关闭就不会执行后续代码
        QDialog *dlg=new QDialog(this);
        dlg->resize(200,100);
        dlg->exec();
        qDebug()<<"模态框弹出来";

        //非模态对话框
//        QDialog *dlg2= new QDialog(this);//防止不会一闪而过
//        dlg2->show();
//        dlg2->setAttribute(Qt::WA_DeleteOnClose);//防止内存爆,关闭时释放掉
//        dlg2->resize(200,100);
//        qDebug()<<"非模态框弹出来";
    });

标准对话框 QMessageBox

//消息对话框  模态
        //错误对话框
        //QMessageBox::critical(this,"critical","错误");
        //信息对话框
        //QMessageBox::information(this,"1","2");
        //提问对话框
        //参数1 父亲 参数2 标题 参数3 提示内容 参数4 按键类型 参数5 默认关联回车的按键
        //QMessageBox::question(this,"1","2",QMessageBox::Save|QMessageBox::Cancel,QMessageBox::Cancel);
        //进行按键点击判断
//        if(QMessageBox::Save==QMessageBox::question(this,"1","2",QMessageBox::Save|QMessageBox::Cancel,QMessageBox::Cancel)){
//            qDebug()<<"保存";
//        }else{
//            qDebug()<<"取消";
//        }
        //警告对话框
        QMessageBox::warning(this,"warning","警告");
    });

其他对话框

//其他对话框
        //颜色对话框
//        QColor color= QColorDialog::getColor(QColor(155,0,0));
//        qDebug()<<color.blue();

        //文件对话框 返回路径
        //参数1 父亲 参数2 标题 参数3 路径 参数4 过滤的文件格式
//       QString s=QFileDialog::getOpenFileName(this,"打开文件","E:/");
//       qDebug()<<s;

        //字体对话框
        bool flag;
        QFont q=QFontDialog::getFont(&flag,QFont("华文彩云",36));
        qDebug()<<q;

页面布局

利用布局方式,给窗口进行美化

选取widget 进行布局 水平 垂直 栅格

默认窗口和控件之间有9间隙 ,选中窗口在 layout margin中调整

内部的间隙可以用弹簧分割 horizontal space

窗口默认特别大在sizePolicy中垂直策略改为fixed

文本款格式在echoMode中设置 需要密码框则选择为password

控件

按钮组

  • QPushButton 常用按钮

  • QToolButton 工具按钮用于显示 图片,如果想显示文字,修改风格 toolButtonStyle 凸起的风格 autoRaise

  • radiaButton 单选按钮,设置默认 setchecked

  • checkbox 多选按钮,2是选中 1是半选中 0是未选 状态代码

     connect(ui->checkBox,&QCheckBox::stateChanged,this,[=](int state){
            qDebug()<<state;
        });
    

    列表容器

    QListWidget列表容器

    //利用listWidget 写诗
    //    QListWidgetItem *item=new QListWidgetItem("锄禾日当午"); //一行
    //    ui->listWidget->addItem(item);
    //    item->setTextAlignment(Qt::AlignCenter); //位置
    //全部直接添加
        QStringList list;
        list<<"锄禾日当午"<<"汗滴禾下锄";
        ui->listWidget->addItems(list);
    

树控件

QTreeWidget 树控件

//设置水平头
    ui->treeWidget->setHeaderLabels(QStringList()<<"英雄"<<"英雄介绍");
    //每一行
    QTreeWidgetItem * item=new QTreeWidgetItem(QStringList()<<"力量");
    QTreeWidgetItem * item1=new QTreeWidgetItem(QStringList()<<"敏捷");
    QTreeWidgetItem * item2=new QTreeWidgetItem(QStringList()<<"智力");
    //加载顶层节点
    ui->treeWidget->addTopLevelItem(item);
    ui->treeWidget->addTopLevelItem(item1);
    ui->treeWidget->addTopLevelItem(item2);
    //追加子节点
    QTreeWidgetItem * heroL1=new QTreeWidgetItem(QStringList()<<"刚被猪"<<"前排坦克,能在吸收伤害的同时造成客观的范围输出");
    QTreeWidgetItem * heroL2=new QTreeWidgetItem(QStringList()<<"刚被猪"<<"前排坦克,能在吸收伤害的同时造成客观的范围输出");
    item->addChild(heroL1);
    item1->addChild(heroL2);
    item2->addChild(heroL1);

QTableWidget表格控件

//tableWidget 控件
//设置列
    ui->tableWidget->setColumnCount(3);
//设置表头
    ui->tableWidget->setHorizontalHeaderLabels(QStringList()<<"姓名"<<"性别"<<"年龄");
//设置行数
    ui->tableWidget->setRowCount(5);
    QStringList nameList=QStringList()<<"亚瑟"<<"1"<<"2"<<"3"<<"4";
    QStringList sex=QStringList()<<"亚瑟"<<"1"<<"2"<<"3"<<"4";
    //设置正文
    for(int i=0;i<5;i++){
        int col=0;
        ui->tableWidget->setItem(i,col++,new QTableWidgetItem(nameList[i]));
        ui->tableWidget->setItem(i,col++,new QTableWidgetItem(sex.at(i)));
        ui->tableWidget->setItem(i,col++,new QTableWidgetItem(QString::number(i)));
    }

其他控件

栈控件 stackedWidget

下拉框 comboBox

QLable 显示图片、动图

 //栈控件的使用
    //ScrollArea 按钮
    connect(ui->btn_scrollArea,&QPushButton::clicked,this,[=](){
        ui->stackedWidget->setCurrentIndex(0);
    });
    //toolBox按钮
    connect(ui->btn_ToolBox,&QPushButton::clicked,this,[=](){
        ui->stackedWidget->setCurrentIndex(1);
    });
    //tabWidget按钮
    connect(ui->btn_TabWidget,&QPushButton::clicked,this,[=](){
        ui->stackedWidget->setCurrentIndex(2);
    });

    //下拉框
    ui->comboBox->addItem("奔驰");
    ui->comboBox->addItem("宝马");
    ui->comboBox->addItem("兰博基尼");

    connect(ui->pushButton_6,&QPushButton::clicked,this,[=](){
        //ui->comboBox->setCurrentIndex(2);
        ui->comboBox->setCurrentText("兰博基尼");
    });

    //利用QLable显示资源 可以显示动图
    ui->label->setPixmap(QPixmap(":/image/la.jpg"));
    //可以显示动图
    //QMovie *movie=new QMovie();
    //ui->label->setMovie(movie);
    //movie->start();

自定义控件

  • 添加新文件 ->Qt->设计师界面类(.h .cpp .ui)
  • ui中设计QspinBox和QSlider 两个控件
  • Widget 使用自定义控件 首先拖拽 Widget 控件 其次提升为 写入类名 全局包含 添加
  • 信号和槽的监听 提供对外接口
  • 在主控制中使用

占位符

QString str=QString("鼠标点击了 x=%1  y=%2 ").arg(ev->x()).arg(ev->y());
%数字代表第几个arg的参数

事件 均需要在函数中进行重写

在ui中拖入后,提升为自己所写的类然后进行事件编辑

鼠标事件

name::name(QWidget *parent) : QLabel(parent)
{
    //设置鼠标追踪 只要鼠标一移动就触发不用鼠标点击着移动
    setMouseTracking(true);
}
void name::enterEvent(QEvent *event){
    qDebug()<<"鼠标进入了";
}
void name::leaveEvent(QEvent *event){
    qDebug()<<"鼠标离开了";
}
void name::mouseMoveEvent(QMouseEvent *ev){
    //鼠标点击着移动
    //移动的判断和点击不一样
//    if(ev->buttons()&Qt::LeftButton){
//    qDebug()<<"鼠标移动了";
//    }
    qDebug()<<"鼠标移动了";
}
void name::mousePressEvent(QMouseEvent *ev){
    if(ev->button()==Qt::LeftButton){
    QString str=QString("鼠标点击了 x=%1  y=%2 ").arg(ev->x()).arg(ev->y());
    qDebug()<<str;}
}
void name::mouseReleaseEvent(QMouseEvent *ev){
    qDebug()<<"鼠标松开了";
}

定时器1

利用时间timerevent

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    //启动定时器 单位毫秒
   id1=startTimer(1000);
   id2=startTimer(2000);
}

MainWindow::~MainWindow()
{
    delete ui;
}
void MainWindow::timerEvent(QTimerEvent *event){
    if(event->timerId()==id1){
    static int num=1;
    ui->label_2->setText(QString::number(num++));
    }else if(event->timerId()==id2){
        static int num2=1;
        ui->label_3->setText(QString::number(num2++));
        }
}

//定时器第二种方式
   QTimer * timer=new QTimer(this);
   timer->start(500);
   connect(timer,&QTimer::timeout,this,[=](){
       static int num=1;
       ui->label_4->setText(QString::number(num++));
   });
 //点击暂停
   connect(ui->pushButton,&QPushButton::clicked,this,[=](){
       timer->stop();
   });

event事件

用于事件分发,也可以做拦截操作,不建议

bool name::event(QEvent *e){
    //如果是鼠标按下,在event 事件分发来拦截
    if(e->type()==QEvent::MouseButtonPress){
        //类型转换
        QMouseEvent * ev= static_cast<QMouseEvent *>(e);
        QString str=QString("鼠标点击了 x=%1  y=%2 ").arg(ev->x()).arg(ev->y());
        qDebug()<<str;
        //true 表示用户自己处理这个事件,不向下分发
        return true;
    }
    //其他事件交给父类处理
    return QLabel::event(e);
}

事件过滤器

在事件分发前进行过滤

  • 给控件安装事件过滤器

  • 重写eventfilter事件

  • //安装事件过滤器
       ui->label->installEventFilter(this);
       //重写eventFilter事件
    bool MainWindow::eventFilter(QObject *watched, QEvent *event){
        if(watched==ui->label){
            if(event->type()==QEvent::MouseButtonPress){
                return true;
            }
        }
        return QWidget::eventFilter(watched,event);
    }
    

绘图事件

void MainWindow::paintEvent(QPaintEvent *){
    //实例化画家
    QPainter *painter=new QPainter(this);//指明绘图设备
    //设置画笔
    QPen *pen=new QPen(QColor(0,255,0));
    pen->setWidth(3);
    pen->setStyle(Qt::DotLine);
    painter->setPen(*pen);
    //设置画刷
    QBrush *brush=new QBrush(QColor(0,0,255));
    brush->setStyle(Qt::Dense7Pattern);
    painter->setBrush(*brush);
    //线
    painter->drawLine(QPoint(0,0),QPoint(100,100));
    //圆
    painter->drawEllipse(QPoint(100,100),50,50);
    //矩形
    painter->drawRect(QRect(QPoint(100,100),QPoint(200,200)));
    //字
    painter->drawText(QRect(10,200,100,50),"好好学习");
    
    
    ---------高级设置---------
     QPainter painter(this);
//    painter.drawEllipse(QPoint(100,50),50,50);
//    //设置抗锯齿效率比较低
//    painter.setRenderHint(QPainter::Antialiasing);
//    painter.drawEllipse(QPoint(200,50),50,50);

    painter.drawRect(QRect(20,20,50,50));
    //让画家移动100
    painter.translate(100,0);

    //保存画家状态
    painter.save();
    painter.drawRect(QRect(20,20,50,50));
    //还原画家的状态
    painter.restore();
    painter.drawRect(QRect(20,20,50,50));
}
 //利用画家 画资源文件
        QPainter painter(this);
        painter.drawPixmap(x,20,100,100,QPixmap(":/image/la.jpg"));
        //超过屏幕宽度就返回
        if(x>this->width()){
            x=0;
        }

绘图设备

Qpixmap QImage QBitmap(黑白色) Qpicture QWidget

    ui->setupUi(this);
//    //绘图设备
//    QPixmap pix(300,300);
//    //设置设备的背景
//    pix.fill(Qt::white);
//    QPainter painter(&pix);
//    painter.setPen(QPen(Qt::green));
//    painter.drawEllipse(QPoint(50,50),50,50);
//    //保存
//    pix.save("E://1.jpg");

//    //可以对每一个像素进行访问
//    QImage image(300,300,QImage::Format_RGB666);
//    image.fill(Qt::white);
//    QPainter painter(&image);
//    painter.drawEllipse(QPoint(50,50),50,50);
//    image.save("E:/1.jpg");
    //QPicture 绘图设备 可以记录和重新绘图指令
    QPicture pic;
    QPainter painter;
    painter.begin(&pic);
    painter.setBrush(QBrush(QColor(Qt::blue)));
    painter.drawEllipse(QPoint(50,50),50,50);
    painter.end();
    pic.save("E:/pic.zt");
void MainWindow::paintEvent(QPaintEvent *event){
    //利用Qimage对像素进行修改
    QPainter painter(this);
//    QImage img;
//    img.load(":/image/la.jpg");
//    for(int i=50;i<100;i++){
//        for(int j=50;j<100;j++){
//            img.setPixel(QPoint(i,j),qRgb(255,0,0));
//        }
//    }
//    painter.drawImage(0,0,img);

    //重现QPicture 的绘图指令
    QPicture pic;
    pic.load("E:/pic.zt");
    painter.drawPicture(0,0,pic);
}

文件操作

文件读写

//编码格式
        //QTextCodec *code=QTextCodec::codecForName("gbk");
        //读文件 默认支持的格式为utf-8
        QFile file(s);
        //设置打开方式
        file.open(QIODevice::ReadOnly);
        //全读
        QByteArray array=file.readAll();
        //一行一行
        QByteArray a;
        //判断是否读到文件尾部
        while(!file.atEnd()){
            a+=file.readLine();
        }
        ui->textEdit->setText(array);
        //ui->textEdit->setText(code->toUnicode(array));
        //关闭文件
        file.close();

        //追加的方式写文件
        file.open(QIODevice::Append);
        file.write("111");
        file.close();

文件信息读取

 //文件的信息
        QFileInfo info(s);
        qDebug()<<info.suffix();
        //想读取哪些信息看帮助文档

网络通信

tcp

在pro文件中加入network 模块

QT       += core gui network

服务器端

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QTcpServer> //监听套接字
#include <QTcpSocket> //通信套接字
namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();

private slots:
    void on_btn_send_clicked();

    void on_btn_close_clicked();

private:
    Ui::Widget *ui;
    QTcpServer *tcpServer;
    QTcpSocket *tcpSocket;
};

#endif // WIDGET_H




#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    tcpServer=NULL;
    tcpSocket=NULL;
    //监听套接字
    tcpServer=new QTcpServer(this);
    //监听任意ip 端口为8888
    tcpServer->listen(QHostAddress::Any,8888);
    setWindowTitle("服务器8888");
    //建立连接
    connect(tcpServer,&QTcpServer::newConnection,this,[=](){
        //取出建立好的套接字
        tcpSocket=tcpServer->nextPendingConnection();
        //获取对方的ip和端口
        QString ip=tcpSocket->peerAddress().toString();
        qint16 port=tcpSocket->peerPort();

        QString temp=QString("[%1:%2]:成功连接").arg(ip).arg(port);
        ui->text_read->setText(temp);


        connect(tcpSocket,&QTcpSocket::readyRead,this,[=](){
            //从通信套接字中取出内容
            QByteArray array=tcpSocket->readAll();
            ui->text_read->append(array);
        });
    });


}

Widget::~Widget()
{
    delete ui;
}

void Widget::on_btn_send_clicked()
{
    if(NULL==tcpSocket){
        return;
    }
    //获取编辑区内容
    QString str=ui->text_write->toPlainText();
    //给对方发送数据 使用tcpSocket套接字
    tcpSocket->write(str.toUtf8().data());
}

void Widget::on_btn_close_clicked()
{
    if(NULL==tcpSocket){
        return;
    }
    //主动和客户端断开连接
    tcpSocket->disconnectFromHost();
    tcpSocket->close();
    tcpSocket=NULL;
}

客户端

#ifndef CLIENTWIDGET_H
#define CLIENTWIDGET_H

#include <QWidget>
#include <QTcpSocket>
namespace Ui {
class ClientWidget;
}

class ClientWidget : public QWidget
{
    Q_OBJECT

public:
    explicit ClientWidget(QWidget *parent = 0);
    ~ClientWidget();

private slots:
    void on_connect_clicked();

    void on_send_clicked();

    void on_close_clicked();

private:
    Ui::ClientWidget *ui;
    QTcpSocket *tcpSocket;//通信套接字
};

#endif // CLIENTWIDGET_H



#include "clientwidget.h"
#include "ui_clientwidget.h"
#include <QHostAddress>
ClientWidget::ClientWidget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::ClientWidget)
{
    ui->setupUi(this);
    setWindowTitle("客户端");
    tcpSocket=NULL;
    //分配空间指定父对象
    tcpSocket=new QTcpSocket(this);
    connect(tcpSocket,&QTcpSocket::connected,[=](){
       ui->textEdit_read->setText("成功和服务器建立");
    });
    connect(tcpSocket,&QTcpSocket::readyRead,[=](){
        QByteArray array=tcpSocket->readAll();
       ui->textEdit_read->append(array);
    });
}

ClientWidget::~ClientWidget()
{
    delete ui;
}

void ClientWidget::on_connect_clicked()
{
    if(NULL==tcpSocket){
        return;
    }
    QString ip=ui->lineEdit_ip->text();
    qint16 port=ui->lineEdit_port->text().toInt();
    tcpSocket->connectToHost(QHostAddress(ip),port);

}

void ClientWidget::on_send_clicked()
{
    if(NULL==tcpSocket){
        return;
    }
    //获取编辑框内容
    QString str=ui->textEdit_2->toPlainText();
    tcpSocket->write(str.toUtf8().data());
}

void ClientWidget::on_close_clicked()
{
    //主动和对方断开连接
    tcpSocket->disconnectFromHost();
    tcpSocket->close();
}

udp

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(int i,QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    udpSocket=new QUdpSocket(this);
    //绑定端口
    udpSocket->bind(i);
    setWindowTitle(QString("服务器端口为%1").arg(i));
    //当对方成功发送数据过来 自动触发readyRead
    connect(udpSocket,&QUdpSocket::readyRead,this,&Widget::dealMsg);
}

Widget::~Widget()
{
    delete ui;
}
void Widget::dealMsg(){
    QHostAddress cliAddr;//对方地址
    quint16 port;//对方地址
    //读取对方发送的数据
    char buf[1024]={0};
    qint64 len=udpSocket->readDatagram(buf,sizeof(buf),&cliAddr,&port);
    if(len>0){
        QString str=QString("[%1:%2]%3").arg(cliAddr.toString()).arg(port).arg(buf);
        ui->textEdit->setText(str);
    }
}

void Widget::on_btn_send_clicked()
{
    //获取对方的ip和端口
    QString ip=ui->lineEdit_ip->text();
    qint16 port=ui->lineEdit_port->text().toInt();
    //获取编辑区内容
    QString str=ui->textEdit->toPlainText();
    //给ip发送内容
    udpSocket->writeDatagram(str.toUtf8(),QHostAddress(ip),port);
}

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QUdpSocket>//UDP套接字
namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(int i=8888,QWidget *parent = 0);
    ~Widget();
    void dealMsg();//处理对方发过来的数据
private slots:
    void on_btn_send_clicked();

private:
    Ui::Widget *ui;
    QUdpSocket *udpSocket;
};

#endif // WIDGET_H

组播

//绑定端口
    //使用组播时不能这样写
    //udpSocket->bind(i);
    udpSocket->bind(QHostAddress::AnyIPv4,i);
    //加入某个组播 QQ群 组播地址必须为D类
    udpSocket->joinMulticastGroup(QHostAddress("224.0.0.2"));
    //退出组播 udpSocket->leaveMulticastGroup(QHostAddress(""))
    setWindowTitle(QString("服务器端口为%1").arg(i));
    //当对方成功发送数据过来 自动触发readyRead
    connect(udpSocket,&QUdpSocket::readyRead,this,&Widget::dealMsg);

发文件

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QFileDialog>
#include <QDebug>
#include <QFileInfo>
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    //监听套接字
    tcpServer=new QTcpServer(this);
    //监听
    tcpServer->listen(QHostAddress::Any,8888);
    setWindowTitle("服务器端口为8888");
    //两个按钮默认不能点击
    ui->btn_select->setEnabled(false);
    ui->btn_send->setEnabled(false);
    //连接成功 触发newconnect
    connect(tcpServer,&QTcpServer::newConnection,this,[=](){
       //取出套接字
        tcpSocket=tcpServer->nextPendingConnection();
        //获取对方ip和端口
        QString ip=tcpSocket->peerAddress().toString();
        quint16 port=tcpSocket->peerPort();
        QString str=QString("[%1:%2]成功连接").arg(ip).arg(port);
        ui->textEdit->setText(str);
        //按钮可以
        ui->btn_select->setEnabled(true);
    });

    connect(&timer,&QTimer::timeout,this,[=](){
        timer.stop();
        sendData();
    });
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_btn_select_clicked()
{
    QString path=QFileDialog::getOpenFileName(this,"open","../");
    if(false== path.isEmpty()){
        //获取文件信息
        fileName.clear();
        fileSize=0;
        sendSize=0;
        QFileInfo info(path);
        fileName=info.fileName();
        fileSize=info.size();
        file.setFileName(path);
        bool isOk=file.open(QIODevice::ReadOnly);
        if(!isOk){
            qDebug()<<"打开失败";
        }
        ui->textEdit->append(path);
        ui->btn_select->setEnabled(false);
        ui->btn_send->setEnabled(true);
    }else{
        qDebug()<<"选择文件路径出错";
    }
}

void MainWindow::on_btn_send_clicked()
{
    //先发送文件头
    QString head=QString("%1##%2").arg(fileName).arg(fileSize);
    qint64 len=tcpSocket->write(head.toUtf8());
    if(len>0){//头部发送成功
        //防止Tcp黏包问题 ,需要延时20ms
        timer.start(20);
    }else{
        qDebug()<<"头部信息发送失败";
        file.close();
        ui->btn_select->setEnabled(true);
        ui->btn_send->setEnabled(false);
    }
}
void MainWindow::sendData(){
    qint64 len=0;
    do{
        //每次发送4k
        char buf[4*1024]={0};
        len=0;
        len=file.read(buf,sizeof(buf));
        //发送数据 都多少发多少
        len=tcpSocket->write(buf,len);
        //发送数据要累加
        sendSize+=len;
    }while(len>0);
    if(sendSize==fileSize){
        ui->textEdit->append("文件发送完毕");
        file.close();
        tcpSocket->disconnectFromHost();
        tcpSocket->close();
    }
}

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QTcpServer> //监听套接字
#include <QTcpSocket> //通信套接字
#include <QFile>
#include <QTimer>
namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:
    void on_btn_select_clicked();

    void on_btn_send_clicked();
    void sendData();
private:
    Ui::MainWindow *ui;
    QTcpServer *tcpServer;//监听套接字
    QTcpSocket *tcpSocket;//通信套接字
    QFile file;
    QString fileName;
    qint64 fileSize;
    qint64 sendSize;
    QTimer timer;
};

#endif // MAINWINDOW_H

#ifndef CLIENTWIDGET_H
#define CLIENTWIDGET_H

#include <QWidget>
#include <QTcpSocket>
#include <QFile>
namespace Ui {
class ClientWidget;
}

class ClientWidget : public QWidget
{
    Q_OBJECT

public:
    explicit ClientWidget(QWidget *parent = 0);
    ~ClientWidget();

private slots:
    void on_btn_connect_clicked();

private:
    Ui::ClientWidget *ui;
    QTcpSocket *tcpSocket;
    QFile file;
    QString fileName;
    qint64 fileSize;
    qint64 recvSize;
    bool isStrat;
};

#endif // CLIENTWIDGET_H

#include "clientwidget.h"
#include "ui_clientwidget.h"
#include <QDebug>
#include <QMessageBox>
#include <QHostAddress>
ClientWidget::ClientWidget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::ClientWidget)
{
    ui->setupUi(this);
    isStrat=true;
    tcpSocket=new QTcpSocket(this);
    connect(tcpSocket,&QTcpSocket::readyRead,[=](){
        //取出接收的内容
        QByteArray array=tcpSocket->readAll();
        if(isStrat==true){
            //头信息
            isStrat=false;
            fileName=QString(array).section("##",0,0);
            fileSize=QString(array).section("##",1,1).toInt();
            recvSize=0;

            file.setFileName(fileName);
            bool isOk=file.open(QIODevice::WriteOnly);
            if(isOk==false){
                qDebug()<<"写失败";
            }
        }else{
            //文件信息
            qint64 len=file.write(array);
            recvSize+=len;
            if(recvSize==fileSize){
                file.close();
                QMessageBox::information(this,"完成","文件接收完成");
                tcpSocket->disconnectFromHost();
                tcpSocket->close();
            }
        }
    });
}

ClientWidget::~ClientWidget()
{
    delete ui;
}

void ClientWidget::on_btn_connect_clicked()
{
    //获取服务器ip和端口
    QString ip=ui->ip->text();
    qint64 port=ui->port->text().toInt();
    tcpSocket->connectToHost(QHostAddress(ip),port);
}

线程

#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QThread>

class Mythread : public QThread
{
    Q_OBJECT
public:
    explicit Mythread(QThread *parent = nullptr);
protected:
    //QThread的虚函数
    //线程处理函数
    //不能直接调用需要通过start()间接调用
    void run();
signals:
    void isDone();
public slots:
};

#endif // MYTHREAD_H

#include "mythread.h"

Mythread::Mythread(QThread *parent) : QThread(parent)
{

}
void Mythread::run(){
    //很复杂的下数据处理需要耗时
    sleep(5);
    emit isDone();
}

 thread->quit();
        //等待线程处理完毕
        thread->wait();
 thread->start();//开启线程

第二种方式见MyWidget项目

数据库

将libmysql.dll文件放到QT/bin下

 QSqlDatabase db=QSqlDatabase::addDatabase("QMYSQL");
    db.setHostName("localhost");
    db.setUserName("root");
    db.setPassword("123456");
    db.setDatabaseName("student");
 //打开数据库
    if(!db.open()){
        qDebug()<<db.lastError().text();
        return;
    }
 QSqlQuery query;
    //创建数据库 插入 删除
    //query.exec("INSERT INTO student (xueHao) VALUES ('181451081115');");
    //预处理 占位符 批量插入 odbc风格
//    query.prepare("INSERT INTO student (xueHao) VALUES (?);");
//    QVariantList xueHao;
//    xueHao<<"181451081113"<<"181451081139";
//    query.addBindValue(xueHao);
//    query.execBatch();
    //预处理 占位符 批量插入 oracle风格
//    query.prepare("INSERT INTO student (xueHao) VALUES (:xueHao);");
//    QVariantList xueHao;
//    xueHao<<"181451081110"<<"181451081130";
//    query.bindValue(":xueHao",xueHao);
//    query.execBatch();
    //开启事务
//    QSqlDatabase::database().transaction();
//    QSqlQuery query1;
//    query1.exec("delete from student where xuehao = '181451081110'");
//    //执行事务
//    QSqlDatabase::database().commit();
//    //回滚事务
//    QSqlDatabase::database().rollback();
    query.exec("select * from student");
    while(query.next()){//遍历
        qDebug()<<query.value(0).toString()<<query.value("xueHao").toString();
    }
//修改
    qDebug()<<query.exec("update student set zhuanYeBanJi='11' where xueHao = '181451081111'");
//数据库操作执行成功返回true失败返回false

数据库控件直接操作数据库不需要命令

//设置模型
    QSqlTableModel *model = new QSqlTableModel(this);
    model->setTable("student");//制定使用哪个表
    //把model放到View
    ui->tableView->setModel(model);
    //显示数据
    model->select();
    //将表头第几个变为什么标题
   // model->setHeaderData(0,Qt::Horizontal,"学号");
    //设置手动提交修改
    //model->setEditStrategy(QSqlTableModel::OnManualSubmit);
    //执行手动提交
    //model->submitAll();
    //取消所有动作
    //model->revertAll();
    //设置不允许修改
    //ui->tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);

    //增加数据
    //添加空记录
//    QSqlRecord record=model->record();
//    //获取行号
//    int row=model->rowCount();
//    model->insertRecord(row,record);

    //取出选中的模型
    QItemSelectionModel *sModel=ui->tableView->selectionModel();
    //取出选中的索引
    QModelIndexList list=sModel->selectedRows();
    for(int i=0;i<list.size();i++)
    {
        model->removeRow(list.at(i).row());
    }


    //查找
    //取出where后面的关键字符串放入下面函数的参数中
    model->setFilter();
    model->select();
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值