Qt-基础
Qt
- 1. 概念
- 其他概念
- 对话框
- 模态对话框与非模态对话框
- 事件
- 事件拦截/过滤
- 事件例子
- 鼠标/屏幕
- 使用
- 界面功能
- qt-designer工具
- debug
- 目录结构
- mainwindow
- 控件
- 窗口
- QMainWindow
- 事件
- 2. 项目概览
- QOBJECT tree 对象树
- 3. 信号和槽
- 信号函数
- 关联
- 自定义信号和槽函数
- 自定义信号和槽函数1
- 自定义信号和槽函数 例子2
- 一个信号触发另一个信号 -- 例子1的进阶
- 4. 控件
- QWidget
- QLabel
- 显示图片
- input相关控件
- QLineEdit
- Text Edit
- Plain Text Edit
- combo box
- spin box
- double spin box
- time edit
- date edit
- dial
- xxx scroll Bar
- xxx Slider
- button相关控件
- QPushButton
- toolbutton
- radiobutton
- checkbox
- list/tree/table-widgets
- item views/item widgets
- QListWidget
- QTreeWidget
- QTableWidget
- containers相关控件
- groupbox
- scroll area
- tool box
- tabWdiget
- stacked widget
- QMainWindow相关控件
- QMenuBar/QMenu -- QMainWindow
- addAction
- addAction 与 信号/槽 ???
- QToolBar -- QMainWindow
- 工具栏设置为图标
- QStatusBar -- QMainWindow
- QDockWidget -- QMainWindow
- QTextEdit -- QMainWindow
- 自定义控件
- qt-文件操作
- 文件对话框
- 字体对话框
- 输入对话框 -- 字符串\数字
- QMessageBox 消息对话框
- 进度对话框
- 文本文件
- 二进制文件
- 文件操作进阶
- QTextStream
- QDataStream
- QBuffer
- 定时器
- QPainter绘图
- 事件处理
- 事件处理进阶
- 绘制设置
- 坐标系变换
- 容器路径
- qt-图像操作
- QPixmap
- QLabel/QPixmap
- QPixmap/QImage
- QPixmap/imageReader
- QPixmap/QByteArray
- QPixmap/QDatastream/QFile
- QImage
- QImage/QLabel
- QImage/QPixmap
- QImage/imageReader
- QImage/QByteArray
- QImage/QDatastream/QFile
- QPicture
- QBitmap
- qt-socket
- ud p
- tcp
- 离线
- 在线
- 安装问题
1. 概念
- 项目
代码集合,代码互相之间有关联
项目文件:负责管理项目的文件,集成开发环境根据项目文件管理和构建项目
qt:.pro
文件;vs:vcproj
- make/makefile
g++等编译器可以直接编译程序
问题:代码文件太多,有些修改后要重新编译,有些没改就不需要编译,有些需要预处理或链接某些库文件,手动记住很麻烦
通过make程序(cmake或qmake)生成 生成脚本,Makefile,make程序不对程序进行编译,而是构建makefile(实际上是,自己编写makelist.txt的简单文件,然后make程序根据.txt生成makefile),进而利用g++等编译工具生成可执行文件或链接库
- debug/release
debuge:调试,
xxxd.file
release:发行,文件小,执行效率高,xxx.file
不带d
release 发布步骤
- 新建文件夹, 将release文件夹中的app.exe文件放入新建文件夹
使用 Qt/xxx/bin/windevelopqt.exe 工具
qt for desktop 命令行工具
> windevelopqt.exe PATH[app.exe]
- 动态连接/静态连接
动态链接库
内存中只需要一份被动态连接的库文件,其他程序使用该库的时候,只要链接过来就可以了,链接文件,只需要一些链接指针。(必须提前装好动态库文件,然后目标程序才能运行),
.dll
/.so
静态链接库
直接将链接库的代码和自己编写的源代码都编译链接到一起,因此运行时依赖的库文件比较少,(因为目标程序中内部继承了很多库代码),
.lib
/.a
- 显示链接/隐式链接
都是动态连接库的使用方法
隐式链接:最为常见,所有的编译环境默认都是采用隐式链接的方式使用动态库,隐式链接会在链接生成可执行程序时就确立依赖关系,而程序启动时,操作系统自动会检查依赖的动态库,并逐一加载到该程序的内存空间,程序什么时候加载动态链接库不用被过分关注,在.exe程序运行前系统会检查依赖的.dll文件,如果找不到某个动态库就会出现错误
其他概念
对话框
- 颜色对话框
- 文件对话框
- 字体对话框
- 输入对话框
- 消息对话框
- 进度对话框
- 错误信息对话框
- 向导对话框
模态对话框与非模态对话框
模态:同时只能操作一个窗口
非模态:同时可以操作多个窗口
#include <QDialog> // 创建对话框QDialog *dialog=new QDialog(this);
dialog->resize(200,100);
// 非模态对话框
// 可以同时操作多个窗口
//dialog->show();// version 1
// 阻塞方式,模态对话框
// 同时只能操作一个对话框
dialog->exec();// 模态对话框 version 2
dialog->setModal(true);
dialog->show();// 不用了就释放掉,这一句很重要
// 相当于释放不必要的内存空间!!!
dialog->setAttribute(Qt::WA_DeleteOnClose);
事件
- 事件产生
- 事件过滤
- 事件分发
- 事件处理
回调函数
作为函数的使用者,只需要指定实现函数的处理动作
关于函数是怎么调用的,并不需要关系
框架自动完成的,自动调用相应的方法
补充:函数f1调用函数f2的时候,函数f1通过参数给函数f2传递了另一个函数f3的指针,在函数f2执行的过程中,函数f2调用了函数f3,这个过程就叫做callback
这个先被当做指针传入,后面又被回调的函数f3就是回调函数
虚函数
父类当中定义该函数,但是具体的实现是在派生类中实现的
相当于函数的重新实现
下面一系列动作都是自动完成的
app.exec()
一直检测是否有事件产生
一旦有事件产生,qt会使用应用程序对象(QApplication的对象),调用notify
函数将事件发送到指定的窗口去(一般是默认的主窗体widget(ui文件创建的主窗口))
事件发生的过程中,(指定窗口)widget
会使用事件过滤器进行规律,调用QObject::eventFilter()
进行重新过滤 (如果在继承的子类中重载了某个函数,那么父类就要将其定义成虚函数)
(指定窗口)widget
接收到事件,event
事件分发器会对其进行分发,(调用event
函数),分发给某个事件类的对应的事件处理函数QWidget::someEvent
最后进行处理
注,绝大部分情况下,事件处理函数
event
不做任何处理,直接将其分发给对应的事件处理函数QWidget::someEvent
进行处理
如果自定义了event
函数,那么在分发过程中会先进入到该函数当中,起到事件拦截的作用
不建议做
// 仅修改一个事件,其他事件还是交给其他原先的处理函数
// 派生类的重写
bool myWidget::event(QEvent *event)
{// 相当于拦截鼠标按下事件if (event->type()==QEvent::MouseBottonPress){/*data*/}// 调用父类的方法return QWigdet::event(event);
}
例子
app.exec() ->
app(QApplication对象).notify()将事件发送到指定窗口 ->
指定窗口eventFilter事件过滤 ->
event() 事件分发与拦截 ->
QWidget::someEvent事件处理函数/*QPushButton*/
用户点击,分派QPushButton类的mousePressEvent()事件处理函数
mousePressEvent()函数内部会改变按钮的属性,提示用户成功按下了按钮
并调用clicked()函数发出‘用户点击按钮’的信号,
对于发出的信号,程序中调用connect()函数,
指定Qwidget类的close()函数接收clicked()信号,close()函数会关闭widget窗口!!!
本质上: 分派事件处理函数 --> 调用事件触发(信号触发)函数,并发出信号--> 对于发出的信号 通过connect函数指定接收信号的函数 --> 接收函数 接收发出的信号,并调用
事件拦截/过滤
定义
event
事件后,特定的事件处理函数则不被执行
不建议做
/*没有任何实现,则所有的特定事件处理函数都会被屏蔽,杜绝这样做必须写return!!!
*/
bool myWidget::event(QEvent *event)
{// 没有任何实现
}
// 仅修改一个事件,其他事件还是交给其他原先的处理函数
// 派生类的重写
bool myWidget::event(QEvent *event)
{// 相当于拦截鼠标按下事件if (event->type()==QEvent::MouseBottonPress){/*data*/}// 调用父类的方法,除了鼠标按下事件被拦截外,其他的特定的事件处理函数依然会被正常的捕获与执行// 必须写return// 对于没有修改的部分,交给父类去处理,交给父类里边的event函数去处理,而父类里边的event对其他函数没有做任何处理return QWigdet::event(event);
}
事件例子
例子1 鼠标点击
/* widget.h */
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();
private:Ui::Widget *ui;protected:void mousePressEvent(QMouseEvent *event);void mouseReleaseEvent(QMouseEvent *event);
};
#endif // WIDGET_H
/* widget.cpp */
#include "widget.h"
#include "ui_widget.h"void Widget::mousePressEvent(QMouseEvent *event)
{// button 返回一个捕获的一个事件if (event->button()==Qt::LeftButton){qDebug()<<"left mouse press";// 基于当前窗体的位置
// qDebug()<<"x:"<<event->position().x()<<" y:"<<event->position().y();qDebug()<<"x:"<<event->x()<<" y:"<<event->y();// 基于屏幕的位置
// qDebug()<<"x:"<<event->globalPosition().x()<<" y:"<<event->globalPosition().y();qDebug()<<"x:"<<event->globalX()<<" y:"<<event->globalY();}else if(event->button()==Qt::RightButton){qDebug()<<"right mouse press";
// qDebug()<<"x:"<<event->position().x()<<" y:"<<event->position().y();qDebug()<<"x:"<<event->x()<<" y:"<<event->y();
// qDebug()<<"x:"<<event->globalPosition().x()<<" y:"<<event->globalPosition().y();qDebug()<<"x:"<<event->globalX()<<" y:"<<event->globalY();}
}
鼠标/屏幕
- 当前窗体坐标
- 当前屏幕坐标
鼠标抬起
void Widget::mouseReleaseEvent(QMouseEvent *event)
{qDebug()<<"button is released";
}
鼠标双击
void Widget::mouseDoubleClickEvent(QMouseEvent *event)
{/*left mouse pressx: 465 y: 382x: 1025 y: 592button is releasedleft button double clickedbutton is released*/if (event->button()==Qt::LeftButton){qDebug()<<"left button double clicked";}else if(event->button()==Qt::RightButton){qDebug()<<"right button double clicked";}
}
滚轮操作
void Widget::wheelEvent(QWheelEvent *event)
{if (event->delta()>0){// 输入字体后,跟着放大和缩小ui->textEdit_2->zoomOut();}else{ui->textEdit_2->zoomIn();}
}
使用
- qt widget
桌面级
- qt quick
触控级,移动端
- qt creator
集成开发环境
- qt design studio
专门的UI设计
- essential
核心基础
- adds-on
附加组件
- qt widgets application
支持桌面平台的有图形用户界面的应用程序,桌面GUI,基于C++,qt提供的c++类库编写
- qt console application
控制台应用程序,无GUI,只需要简单的输入输出操作时,可以创建此类项目,基于c++
- qt quick application
移动设备、嵌入式设备应用程序,界面设计使用QML语言,其他使用C++
- QMainWindow
主窗口类,主窗口具有主菜单栏、工具栏、状态栏,类似一般的应用程序
- QWidget
所有具有可视界面类的基类,选择QWidget创建的界面 对各种界面组件都可以支持
- QDialog
对话框类,建立一个基于对话框的界面
- ui
如果不勾选自动创建ui界面,就需要用代码手动创建
- QApplication
标准应用程序类,任何一个QWidget一个程序都必须有一个QApplication
界面功能
qt-designer工具
组件面板(左),属性编辑器(右)
debug
对于使用MSVC编译的程序,在debug时必须使用windows软件开发工具包SDK
最好就是使用MinGW
目录结构
项目同级目录下有一个文件夹,是 编译后的文件目录(目录名称包含编译器信息),用于使用不同的编译器创建不同版本的可执行文件 <-- 勾选shadow build
项目目录下创建debuge / release 用于存放编译后的文件
mainwindow
mainwindow.h
主窗口类的头文件
mainwindow.cpp
主窗口类的实现文件
mainwindow.ui
主窗口的界面文件,界面文件时文本文件,xml
标记语言
控件
每个控件都由特定的类表示,每个控件类都直接或间接继承
QWidget类
QWidget类
是所有组件(可视)的基类
可以使用现成的,也可以通过继承QWidget类
或某个控件类,自定义一个新的控件
窗口
窗口:带有标题栏、关闭按钮的控件
常用的窗口类:QMainWindow
、QDialog
QMainWindow
类生成的窗口菜单栏、工具栏、状态栏,中央区域可添加多个控件,一般是应用程序的主窗口,QMainWindow
继承自QWdiget
QDialog
类生成的窗口比较简单,没有菜单栏、工具栏、状态栏,但是可以添加多个控件,常用作对话框
QWidget
既可以制作窗口,也可以作为某个窗口上的控件,QWidget
是QObject
的子类
继承关系
QObject --派生-> QWidget --派生-> QMainWindow
QMainWindow
QMainWindow
类生成的窗口菜单栏、工具栏、状态栏,中央区域可添加多个控件,一般是应用程序的主窗口,QMainWindow
继承自QWdiget
从上到下、从外到中心 :菜单栏(menu bar)、工具栏(too bar)、悬浮窗口(停靠窗口)(dock widget)、中心区域(center widget)、状态栏(status bar)
事件
事件:应用程序与用户之间的交互过程(输入、点击之类的)
main
函数中的exec()
函数:使程序能够持续不断的接受各种事件
每触发,并接收一个事件,Qt会分派给相应的事件处理函数来处理。
事件处理函数:普通的类成员函数,(按下QPushButten按钮,分派QPushButten类中的mousepressEvent()处理)修改控件的某些属性
运行信号和槽机制 处理事件
2. 项目概览
shadow build
编译生成的文件 与源代码在同一个文件
pro项目文件
https://blog.csdn.net/simonforfuture/article/details/78580510
作用:pro文件存储的配置信息是用来告诉编译器如何编译当前项目的
项目管理
项目中用到了哪些模块
项目中包含了哪些源文件、哪些头文件,存储的路径是什么
项目中使用哪个图片作为应用程序的图标
项目最终生成的可执行文件的名称
qt编译源文件的方法
先由qmake工具根据pro文件记录的配置信息生成相应的makefile文件,然后执行make命令完成对整个项目的编译
// 工程项目中,使用的类库(模块)
QT += core gui // core gui 核心模块和可视模块
QT += network // 使用网络
QT +=sql# QT 版本>4
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets // 版本控制,默认写上就行CONFIG += c++17 # 启用新的标准# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
# TARGET = 最终生成的可执行文件的名字.exe
# TAMPLATE = app #告诉 告诉qmake为这个应用程序生成那种makefile# 源文件
SOURCES += \main.cpp \mainwindow.cpp
# 头文件
HEADERS += \mainwindow.h# ui文件
FORMS += \mainwindow.ui# 更改图标 设置程序图标
RC_ICONS+=\path\file.ico# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target# 应用程序所需的额外的包含路径的列表
# $$PWD的意思为当前目录 pro文件的当前目录
INCLUDEPATH+=$$PWD/include/ # 指定链接到项目中的库列表 表示链接哪些动态库
LIBS += -L$$PWD/lib/
// main.cpp
#include <QApplication>
#include <QWidget>
#include <QPushButton>int main(int argc, char *argv[])
{// 标准应用程序类QApplication a(argc, argv);// 添加窗口QWidget widget;// 定义按钮,位于widget窗口中QPushButton But("按钮控件",&widget);// 设置按钮的位置和尺寸But.setGeometry(10,10,100,50);//信号与槽,实现当用户点击按钮时,widget窗口关闭/*用户点击,分派QPushButton类的mousePressEvent()事件处理函数mousePressEvent()函数内部会改变按钮的属性,提示用户成功按下了按钮并调用clicked()函数发出‘用户点击按钮’的信号,对于发出的信号,程序中调用connect()函数,指定Qwidget类的close()函数接收clicked()信号,close()函数会关闭widget窗口!!!本质上: 分派事件处理函数 --> 调用事件触发(信号触发)函数,并发出信号--> 对于发出的信号 通过connect函数指定接收信号的函数 --> 接收函数 接收发出的信号,并调用*/// 控件,触发行为,所在窗口,执行动作// 信号发送者,信号触发的机制(行为,通过什么行为触发),信号接收者,执行动作// 信号发送者,信号,信号接受者,槽 <-- 最终通过connect进行关联// QObject::connect(&a,&signal,&b,&slot)QObject::connect(&But,&QPushButton::clicked,&widget,&QWidget::close);widget.show();return a.exec(); // 执行消息循环和事件处理
}
// widget.h
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; } // 定义一个名称空间,使用了一个名称空间中的widget类 对应于文件夹中的ui_widget.h 不会出现在工程目录中
// 注意这里的widgt 和下面定义的 继承自QWidget的Widget不是一个东西
QT_END_NAMESPACEclass Widget : public QWidget
{// Q_OBJECT 是一个已经定义好的宏,所有需要'信号和槽'功能的组件将Q_OBJECT作为private属性成员引入到类中// 如果设计的界面程序用不到信号和槽,就可以删除Q_OBJECTQ_OBJECT // 这是一个宏,信号与槽机制必须的宏public:// nullptr 是一个控制指针// 等价于 MainWindow(QWidget *parent=0)Widget(QWidget *parent = nullptr); ~Widget();private:Ui::Widget *ui; // 使用ui名称空间中的widgt类定义一个ui对象
};
#endif // WIDGET_H
// widget.cpp
#include "widget.h"
#include "ui_widget.h" // 对应ui名称空间// 定义构造函数
// Widget是QWidget的派生类
// 一个派生类在初始化的时候,要调用基类的构造函数进行初始化
Widget::Widget(QWidget *parent): QWidget(parent) // Wdiget 派生自Qwidget,派生类的构造函数要先调用基类QWdiget的构造函数 进行初始化 , ui(new Ui::Widget) // 对Wdiget成员变量进行初始化 使用成员初始化列表方式
{// 调用的是Ui::Widget命名空间下的setupUi函数ui->setupUi(this); // 实现对窗口的生成、窗口、信号与槽 // setupUi,对窗口及其窗口内的控件进行初始化
}Widget::~Widget()
{delete ui;
}
ui_widget.h
Ui_widget
类实现 窗口与控件的设置,信号与槽的关联
/*编译之后生成一个ui_widget.h的文件该文件定义了一个Ui_Widget的类 (Ui_Wdiget这个类时通过编译.ui界面文件生成的)并定义了一个名称空间,该名称空间内定义了一个类Widget 公有继承自Ui_Widget最终在widget.h下private 私有成员中定义了一个 Ui::Widget *ui; // Ui命名空间下的对象指针 ui ui公有继承自ui_widget.h中的Ui_Widget类 说白了ui-> some控件都是Ui_widget中的控件
*/class Ui_Widget
{/*code*/
};namespace Ui{class Widget: public Ui_Widget {} ;
}
资源文件
资源管理器的方式进行管理:项目目录-右键新建-qt::qt resource file 得到一个.qrc资源文件
资源目录下面有一个.qrc文件 -> 右键open in edit -> 添加前缀:(前缀相当于文件夹分类 images videos等)/Image -> 再 添加文件,选择文件(文件夹)
一般是添加icon文件等
// 通过代码方式 添加qt资源文件
// 格式 ": + 前缀 + 文件名"
ui->actionNew->setIcon(QIcon(":/Image/images/a.png")); // /Image是前缀
QOBJECT tree 对象树
new 控件,不需要手动进行delete,因为对象树的机制,主窗口销毁后,内部的控件会自动销毁
“视频第二遍没看”
3. 信号和槽
http://c.biancheng.net/uploads/allimg/211028/2-21102QG3143O.gif
信号和槽是消息传输机制,关联独立的控件
每次触发一个事件,都会发出一个信号
所有控件都具有接受信号的能力,一个控件可以接收多个不同的信号,接收后都会做出相应的响应动作
关联信号信号函数和槽函数,需要借助QObject
类中的connect
函数
Q_OBJECT
是一个宏,添加它才能正常使用qt的信号和槽机制
Q_OBJECT 是一个已经定义好的宏,所有需要’信号和槽’功能的组件将Q_OBJECT作为private属性成员引入到类中
如果设计的界面程序用不到信号和槽,就可以删除Q_OBJECT
//例子
// 控件,触发行为,所在窗口,执行动作
// 信号发送者,信号触发的机制(行为,通过什么行为触发),信号接收者,执行动作
// 信号发送者,信号,信号接受者,槽 <-- 最终通过connect进行关联// &QPushButton::cliked 非静态成员函数,取函数的地址必须使用&,而不能想普通函数一样使用函数名
QObject::connect(&But,&QPushButton::clicked,&widget,&QWidget::close);
信号用 信号函数表示,用
slots
关键字修饰
槽用 槽函数表示,用public slots,protected slots,private slots
关键字修饰
本质上:槽函数调用信号函数(的返回值)(并执行动作)(信号函数没有返回值)
信号函数值需要声明,不需要定义;槽函数需要定义
信号函数
定义在某个类中,该类直接或间接继承自
QObject
类
用signals
关键字修饰
函数只需要声明,不需要定义
函数的返回值类型为void,参数的类型和个数不限
关联
connect()
是QObject
类中的静态成员函数,用来关联信号函数和槽函数
QObject::connect(const QObject *sender, PointerToMemberFunction signal, const QObject *receiver, PointerToMemberFunction method, Qt::ConnectionType type = Qt::AutoConnection)
QObject::connect(&a,&signal,&b,&slot)
取消关联
QObject::disconnect(&a,&signal,&b,&slot)
下面的例子中:
QObject::connect(&But,&QPushButton::clicked,&widget,&QWidget::close);
信号发送者:
But
对象
信号函数(发送信号):QPushButton
类中的clicked
信号接收者:widget
主窗口对象
槽函数(指定动作):Qwidget
类中的close
函数
从上面和下面的例子可以看出,信号函数和槽函数的组件对象是不同的
注意:还有一个分派事件处理函数的问题 (先修改控件属性,然后再运行信号-槽机制)???
#include <QApplication>
#include <QWidget>
#include <QPushButton>int main(int argc, char *argv[])
{QApplication a(argc, argv);// 添加窗口QWidget widget;// 定义按钮,位于widget窗口中QPushButton But("按钮控件",&widget); // 构造函数的重载// 设置按钮的位置和尺寸But.setGeometry(10,10,100,50);//信号与槽,实现当用户点击按钮时,widget窗口关闭/*用户点击,分派QPushButton类的mousePressEvent()事件处理函数mousePressEvent()函数内部会改变按钮的属性,提示用户成功按下了按钮并调用clicked()函数发出‘用户点击按钮’的信号,对于发出的信号,程序中调用connect()函数,指定Qwidget类的close()函数接收clicked()信号,close()函数会关闭widget窗口!!!本质上: 分派事件处理函数 --> 调用事件触发(信号触发)函数,并发出信号--> 对于发出的信号 通过connect函数指定接收信号的函数 --> 接收函数 接收发出的信号,并调用*/// 控件,触发行为,所在窗口,执行动作// 信号发送者,信号触发的机制(行为,通过什么行为触发),信号接收者,执行动作// 信号发送者,信号,信号接受者,槽 <-- 最终通过connect进行关联QObject::connect(&But,&QPushButton::clicked,&widget,&QWidget::close);widget.show();return a.exec();
}
一个connect只能关联一个信号函数和槽函数
一个信号函数可以关联多个槽函数,信号发出后,与之关联的槽函数会 随机 执行,无法指定先后顺序???
多个信号函数可以关联同一个槽函数,哪个信号发出,槽函数都会执行
信号函数与信号函数之间也可以关联,信号发出,另一个信号也会发出 – 暂时没有例子???
自定义信号和槽函数
信号函数
class MyWidget:public QWidget{//Q_OBJECT是一个宏,添加它才能正常使用qt的信号和槽机制Q_OBJECT// 修饰信号函数的关键字
signals://自定义信号函数// 没有返回值、没有定义,仅有一个参数// 程序不会主动调用,而是通过调用connet() 函数,将其与某个槽函数连接// 一旦connect连接,当信号函数发出信号后,与之相连的槽函数就会被执行// 如何发出信号函数/* 对于内置的信号函数,底层已经设置好了信号发出的时机,点击鼠标或按回车对于自定义的信号,需要手动指定信号发出的时机,这就需要emit关键字emit:发出、发射每一个自定义的信号函数,程序都应该提供发射该信号的方法这样的方法可以有多个*/void MySignal(QString mess);
public:// 定义一个发射信号方法和一个message属性// emitSignal函数里面又有一个函数(这个函数是特殊的信号函数,不需要实现)// 当程序执行该方法时,就会发出MySignal信号,message属性的值也随信号一同发出// 发出后的message,对应槽函数可以接收到的message的值void emitSignal(){// 发射Mysignal函数// 类内可以访问私有属性emit MySignal(message);}
private: // 相当于一个类外不可访问的属性// 一个QString类的对象QString message;
};
槽函数
/*槽函数即可以是普通的全局函数,也可以是类的成员函数、静态成员函数、友元函数、虚函数,或lambda表达式槽函数必须手动实现槽函数可以在程序中直接调用,而不通过connet方法,但通常来讲,主要是为了响应某个信号槽函数的返回值必须与信号函数相同,** 由于信号函数的返回值一定是void,所以槽函数的返回值也必须是void **对于带参数的信号函数,槽函数可以选择接收所有参数,则参数的类型、顺序、个数都必须与信号函数相同,还可以选择接收前几个参数,这些参数的类型、顺序都必须与信号函数相同还可以选择不接受任何参数槽函数的参数个数只能比信号函数少,不能比信号函数多槽函数的参数不能有默认值slots关键字可以与public,protected,private关键字搭配使用plublic slots 可以在当前类及其子类的成员函数中被调用,也可以在类外的其他函数中调用protected slots 仅允许在当前类及其子类的成员函数中调用,不能再类外被其他函数调用private slots 只允许在当前类的成员函数中使用,不能在子类中调用,也不能在类外部被其他函数调用*/
例子
/*== QMysignalSlot.h ==*/
#ifndef QMYSIGNALSLOT_H
#define QMYSIGNALSLOT_H
#include <QWidget>
#include <QApplication>
#include <QDebug>
class MyWidget:public QWidget{Q_OBJECTsignals:void MySignal(QString mess1,QString mess2);public:void emitSignal(){emit MySignal(message1,message2);}// 类的成员函数// 位于类的内部,可以当做槽函数void recSlot1(QString mess){qDebug()<<"执行recSlot1() 函数,输出"<<mess;}// 指定定义的槽函数
// slots 用于修饰槽函数
public slots:void recSlot2(QString mess1,QString mess2){qDebug()<<"指定recSlot2s()槽函数,输出"<<mess1<<" "<<mess2;}public:QString message1;QString message2;
};
#endif // QMYSIGNALSLOT_H
/*== main.cpp ==*/
#include "QMysignalSlot.h"
void recSlot3(){qDebug()<<"执行recSlot3()全局函数";
}
int main(int argc,char* argv[]){QApplication a(argc,argv);MyWidget mywidget;mywidget.message1="ex1";mywidget.message2="ex2";// 将类的成员函数作为槽函数QObject::connect(&mywidget,&MyWidget::MySignal,&mywidget,&MyWidget::recSlot1);// 信号函数和槽函数关联QObject::connect(&mywidget,&MyWidget::MySignal,&mywidget,&MyWidget::recSlot2);// 全局函数作为槽函数QObject::connect(&mywidget,&MyWidget::MySignal,&recSlot3); // 全局函数不用写接收对象???mywidget.show();// 发送signal函数mywidget.emitSignal();return a.exec();
}
自定义信号和槽函数1
信号类
/*== mysignal.h ==*/
#ifndef MYSIGNAL_H
#define MYSIGNAL_H#include <QObject>class Mysignal : public QObject
{Q_OBJECT
public:explicit Mysignal(QObject *parent = nullptr);signals:void my_signal(void);void my_signal2(int value); // 信号函数传递参数
};#endif // MYSIGNAL_H/*== mysignal.cpp ==*/
#include "mysignal.h"Mysignal::Mysignal(QObject *parent): QObject{parent}
{}
槽类
/*== myslot.h ==*/
#ifndef MYSLOT_H
#define MYSLOT_H#include <QObject>class MySlot : public QObject
{Q_OBJECT
public:explicit MySlot(QObject *parent = nullptr);void my_multiSlot(void); // 普通成员函数 作为槽函数signals:public slots:void my_slot(void); // 关键字修饰的成员函数 作为槽函数void my_slot2(int value); // 槽函数接收参数};#endif // MYSLOT_H/*== myslot.cpp ==*/
#include "myslot.h"
#include <QDebug>MySlot::MySlot(QObject *parent): QObject{parent}
{}void MySlot::my_slot(void)
{qDebug()<<"slot function";
}void MySlot::my_slot2(int value)
{qDebug()<<"slot function value: "<<value;
}void MySlot::my_multiSlot(void)
{qDebug()<<"multi slot functon";
}
窗口函数
/*== widget.h ==*/
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include "mysignal.h"
#include "myslot.h"QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private slots:
// void on_emit_mysignal_clicked();void on_emitButton_clicked(); // 不带参发射void on_emit2Button_clicked(); // 带参发射private:Ui::Widget *ui;MySlot *mSlot; // 信号类对象Mysignal *mSignal; // 槽类对象int num;
};
#endif // WIDGET_H/*== widget.cpp ==*/
#include "widget.h"
#include "ui_widget.h"
#include <QLabel>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);this->setFixedSize(500,500); // 设置固定的框高,不可更改this->setWindowTitle("main window"); // 设置窗口名mSignal=new Mysignal(this);mSlot=new MySlot(this);this->num=1;// 关联信号函数和槽函数1connect(mSignal,&Mysignal::my_signal,mSlot,&MySlot::my_slot);// 利用按键触发自定义的信号函数// 使用代码的方式 不通过右键转到槽定义// 不通过 void Widget::on_emitButton_clicked() void Widget::on_emit2Button_clicked()// connect(ui->emitButton,&QPushButton::clicked,mSignal,&Mysignal::my_signal);// connect(ui->emit2Button,&QPushButton::clicked,mSignal,&Mysignal::my_signal);// 关联信号函数和槽函数2connect(mSignal,&Mysignal::my_signal,mSlot,&MySlot::my_multiSlot);connect(mSignal,&Mysignal::my_signal2,mSlot,&MySlot::my_slot2);// 取消关联
// disconnect(ui->emit2Button,&QPushButton::clicked,mSignal,&Mysignal::my_signal);
}Widget::~Widget()
{delete ui;
}// 定义button 不带参发射
void Widget::on_emitButton_clicked()
{emit mSignal->my_signal();
}// 定义button 带参发射
void Widget::on_emit2Button_clicked()
{emit mSignal->my_signal2(num);
}
自定义信号和槽函数 例子2
主函数和窗口函数
/* === main.cpp === */
#include "widget.h"#include <QApplication>
#include <QLabel>int main(int argc, char *argv[])
{QApplication a(argc, argv);Widget w;w.show();return a.exec();
}/* === wight.h === */
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include "mysignal.h"
#include "myslot.h"QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private slots:void on_emit_mysignal_clicked();private:Ui::Widget *ui;MySlot *mSlot;Mysignal *mSignal;
};
#endif // WIDGET_H/* === wight.cpp === */
#include "widget.h"
#include "ui_widget.h"
#include <QLabel>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);this->setFixedSize(500,500); // 设置固定的框高,不可更改this->setWindowTitle("main window"); // 设置窗口名// 实例化 信号函数mSlot=new MySlot(this);// 实例化 槽函数mSignal=new Mysignal(this);// 关联信号和槽函数connect(mSignal,&Mysignal::my_signal,mSlot,&MySlot::my_slot);}Widget::~Widget()
{delete ui;
}// 利用button点击来发送、触发信号函数 -- ui设计button
void Widget::on_emit_mysignal_clicked()
{// 发送信号// 触发信号emit mSignal->my_signal(); // 私有函数访问私有成员的公有信号函数
}
信号函数
/* === mysingal.h === */
#ifndef MYSIGNAL_H
#define MYSIGNAL_H#include <QObject>class Mysignal : public QObject
{Q_OBJECT
public:explicit Mysignal(QObject *parent = nullptr);signals:void my_signal(void);
};#endif // MYSIGNAL_H/* === mysignal.cpp === */
#include "mysignal.h"Mysignal::Mysignal(QObject *parent): QObject{parent}
{// 可以不写任何东西
}// 不用对void my_signal(void) 函数进行定义
槽函数
/* === myslot.h === */
#ifndef MYSLOT_H
#define MYSLOT_H#include <QObject>class MySlot : public QObject
{Q_OBJECT
public:explicit MySlot(QObject *parent = nullptr);signals:public:void my_slot(void);
};#endif // MYSLOT_H/* === myslot.cpp === */
#include "myslot.h"
#include <QDebug>MySlot::MySlot(QObject *parent): QObject{parent}
{}void MySlot::my_slot(void)
{qDebug()<<"slot function";
}
一个信号触发另一个信号 – 例子1的进阶
/*== widget.cpp ==*/
// 在ui文件中定义一个pushbutton3
// 在该文件中直接关联一个button的点击信号和自定义的信号
// 点击时候触发自定义的信号函数,进而触发自定义的槽函数
connet(ui-> pushbutton3,&QPushButton::click,mSignal,&MySignal::my_signal)
4. 控件
QWidget
// 当前窗体的状态
QWdiget::windowState()
Qt::WindowNoState
Qt::WindowFullScreen
// 设置状态
QWidget::setWindowState
MyWdiget::MyWdiget(QWidget *parent): QWidget(parent),ui(new Ui::Wiget)
{ui->setuoUi(this);this->resieze(); // 设置窗口状态this->setFixedSize(); // 窗口不可缩放this->setWindowTitle(); // 窗口名字 }
QLabel
文本控件,甚至是图片、超链接、动画
继承关系: QWidget -> QFrame -> QLabel
parent
用于指定文本框的父窗口
属性
pixmap
图片,没有图片则为0 ; 对应的方法pixmap() setPixmap()
方法
setGeometry
设置文本框位置
信号
…
槽
setPicture
清空QLabel
控件内的所有内容,改为显示经QPicture
类处理的图像
setPixmap
清空QLabel控件内的所有内容,改为显示经QPixmap
类处理的图像
// 不是正经的超链接,而只是显示内容的改变
int main(int argc,char *argv[]){QApplication a(argc,argv);//创建文本框QLabel lab;//设置文本框位置lab.setAlignment(Qt::AlignCenter);//设置坐标和尺寸lab.setGeometry(100,100,400,400);//设置外观lab.setStyleSheet("QLabel{font:30px;color:red;background-color:rgb(f9,f9,f9);}");//设置显示的超链接内容lab.setText("<a href=\"http://c.biancheng.net\">Cccc");//设置显示提示内容lab.setToolTip("点击超链接显示URL");//提示显示1秒lab.setToolTipDuration(1000);// 设置信号和槽QObject::connect(&lab,&QLabel::linkActivated,&lab,&QLabel::setText);lab.show(); //此时没有主窗口 默认lab不属于任何一个窗体return a.exec();}
#include "widget.h"#include <QApplication>
#include <QLabel>int main(int argc, char *argv[])
{QApplication a(argc, argv);Widget w;QLabel *label=new QLabel; // 单独一个窗体label->setParent(&w); // 设置parent父窗口 // 利用指针创建,就要利用new开辟一个QLabel(这个类对象)大小的内存空间QLabel *label=new QLabel(&w); // 设置parent父窗口label->setText("hello qt");w.show();return a.exec();
}
#include "widget.h"
#include "ui_widget.h"
#include <QLabel>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this); QLabel *label1=new QLabel(this); // this 相当于是Widget对象 等价于labe.setParent(&w)label1->setText("hello qt1");label1->move(10,10); // 设置位置QLabel *label2=new QLabel;label2->setParent(this);label2->setText("hello qt2");
}Widget::~Widget()
{delete ui;
}
显示图片
不能选择setpicture
#include <QPixmap>
// version1
ui->label_2->setPixmap(QPixmap(":/icon/icon/Application.ico")); //setPixmap() 要添加一个QPixmap的对象 这里直接创建一个匿名对象// version2
QPixmap img=QPixmap(":/icon/icon/Application.ico");
ui->label_2->setPixmap(img);
// 图片根据控件进行缩放
ui->label_2->setScaledContents(true);// 添加动图
QMovie *mv=new QMOvie("path")
ui->label_3->setMovie(mv); // 添加的是一个指针
mv->start();
ui->label_3->setScaledContents(true);
input相关控件
edit类型:输入并显示 相当于输入并读取
widget类型:仅显示
QLineEdit
单行输入框
输入一行文本
QLineEdit(QWidget*parent)
QLineEdit(const QString &contents,QWidget *parent) // contents 指定文本框中的文本内容
// 限定长度、格式、文本内容
#include <QLineEdit>//创建账号输入框
QLineEdit lineEdit(&widget);
//指定输入框位于父窗口中的位置
lineEdit.move(100,100);
//设置提示信息
lineEdit.setPlaceholderText("请输入账号...");
//让输入框显示“一键清除”按钮
lineEdit.setClearButtonEnabled(true);
Text Edit
输入多行文本,可编辑的
可以设置字体格式
Plain Text Edit
输入多行文本,不可编辑的
相比Text edit 没有字体格式的设置
combo box
列表选项卡(下拉菜单有多个选项)
tab widget相当于水平选项卡
ui->comboBox->addItem("博士");
ui->comboBox->addItem("硕士");
ui->comboBox->addItem("本科");
spin box
设置数字(上下键选择)
double spin box
设置浮点数(上下键选择)
time edit
设置时间
#include <QTime>
#include <QDateTime>
QDateTime curDateTime= QDateTime::currentDateTime();
ui->timeEdit->setTime(curDateTime.time());
ui->dateTimeEdit->setDateTime(curDateTime);
date edit
设置日期
dial
旋钮变化
xxx scroll Bar
滚动条
xxx Slider
滑动条
粗调整,没有数值调整的细
button相关控件
QPushButton
按钮控件,按钮控件除了可以放置一串文本,文本左侧还可以防止图标,或在按钮上防止图片(Qpushbutton按钮可以作为一个独立的窗口,但是很少这么用)
继承关系:QPushButton --> QAbstractButton --> QWidget
QAbstractButton
是所有 按钮类 控件的基类
信号
clicked()
点击并释放,触发信号
pressed()
点击,触发信号
released
松开,触发信号
槽
click
单击指定按钮
setMenu
弹出与按钮关联的菜单
#include <QApplication>
#include <QWidget>
#include <QPushButton>int main(int argc, char *argv[]){QApplication a(argc,argv);// 添加窗口QWidget widget;widget.setWindowTitle("ex窗口");// 创建按钮,嵌入到窗口中QPushButton But("ex button",&widget);// 设置按钮位置But.move(100,100);//设置格式But.setStyleSheet("ex button{font:20px}");//调整按钮尺寸But.resize(200,200);QObject::connect(&But,&QPushButton::clicked,&But,&QPushButton::hide);widget.show();return a.exec();
}
toolbutton
图标 悬浮显示文字
点击高亮
autoraise
先添加资源文件
设置 toolbuttonstyle
radiobutton
选项按钮(圆点) – 单选
可以结合groupbox使用
// radiobutton
ui->radioButton->setChecked(true); // 设置默认选项 只是默认项但是并不等于clickedmySlot_item=new mySlot(this);
connect(ui->radioButton_2,&QRadioButton::clicked, mySlot_item,&mySlot::my_slot);
connect(ui->radioButton_3,&QRadioButton::clicked, this,&Widget::signal_func);
checkbox
选项按钮(方框) – 多选
设置tristate 选项的状态:方块、对钩、不选
list/tree/table-widgets
相当于输出显示
item views/item widgets
item views 一般用于复杂数据,**数据库 **
item wdigets 一般用于简单数据
QListWidget
列表控件 (不等于表格控件) ,只能有一列
QListWidgetItem
列表项,用于创建列表项
/* QMyLabel.h */
#ifndef QMYLABEL_H
#define QMYLABEL_H#include <QLabel>
#include <QListWidgetItem>class QMyLabel:public QLabel{Q_OBJECT
public slots: // 设置一个槽函数// 声明一个槽函数void rsetText(QListWidgetItem* item);
}; // 定义类的时候必须加分号#endif // QMYLABEL_H
/* main.cpp */#include <QApplication>
#include <QWidget>
#include <QListWidget> // 列表控件
//#include <QLabel>
//#include <QListWidgetItem> // 列表项控件,用于创建列表项#include "QMyLabel.h"using namespace std;//class QMyLabel:public QLabel{
// Q_OBJECT
//public slots: // 设置一个槽函数
// // 声明一个槽函数
// void rsetText(QListWidgetItem* item);
//}; // 定义类的时候必须加分号// 对类中声明的槽函数,实现
void QMyLabel::rsetText(QListWidgetItem* item){this->setText(item->text()); // 继承的应该是QLabel的setText/*个人理解:QMyLabel print; //实例化一个对象print.certain_method(); // 搜索机制,当前对象所属类中的方法,如果没有就从被继承的父类中寻找*/
}int main(int argc,char* argv[]){QApplication a(argc,argv);QWidget widget;widget.setWindowTitle("ex窗口");widget.resize(500,500);QListWidget listWidget(&widget);listWidget.resize(500,400);listWidget.setFont(QFont("宋体",14));listWidget.addItem("ex1");listWidget.addItem("ex2"); // 可以直接传文本listWidget.addItem(new QListWidgetItem("ex3")); // 可以直接传一个列表项QMyLabel print;print.setText("选中内容");print.setParent(&widget);print.resize(500,100);print.move(0,400);print.setAlignment(Qt::AlignCenter);// 虽然信号函数的发送者是list,即多个列表项组成的列表框// 但是信号函数表示的是,itemCliked 点击某个列表项的时候// 槽函数的形参也是一个列表项指针QObject::connect(&listWidget,&QListWidget::itemClicked,&print,&QMyLabel::rsetText);widget.show();return a.exec();
}
例子2
#include <QListWidgetItem> // 列表项
#include <QStringList> // 字符串容器// 添加一个元素
ui->listWidget->addItem("hello");
ui->listWidget->addItem("word");QListWidgetItem *listitem=new QListWidgetItem("qt");
ui->listWidget->addItem(listitem);
// 设置对齐方式
listitem->setTextAlignment(Qt::AlignHCenter);// 添加多个元素
QStringList list2;
list2<<"abcd"<<"efgh"<<"ijk";
ui->listWidget_2->addItems(list2);
QTreeWidget
树型控件
QTreeWidgetItem
树型结构中的节点(节点控件),用于创建节点
可以创建多个顶层节点(顶层节点也是节点,QTreeWidgetItem
类的对象)
在不创建表头的时候,默认表头是列的序号,从1开始
#include <QApplication>
#include <QTreeWidget>
#include <QTreeWidgetItem>int main(int argc,char* argv[]){QApplication a(argc,argv);// 在主窗口上定义树形窗口QWidget widget;QTreeWidget treeWidget(&widget);// 调用构造函数,直接将节点作为树形空间的顶层节点QTreeWidgetItem topItem(&treeWidget);// 调用树形空间的方法创建顶层节点QTreeWidgetItem topItem2;treeWidget.addTopLevelItem(&topItem2);widget.show();return a.exec();}
进阶
/*QMyTree.h*/
#ifndef QMYTREE_H
#define QMYTREE_H#include <QWidget>
#include <QTreeWidgetItem>class MyWidget:public QWidget{Q_OBJECTpublic slots: // 定义槽函数void treeWidgetClicked(QTreeWidgetItem* item);
};//void MyWidget::treeWidgetClicked(QTreeWidgetItem* item){
// // 遍历item节点所有的子节点
// for(int i=0;i<item->childCount();i++){
// //找到每个子节点
// QTreeWidgetItem* childItem=item->child(i);
// //将子节点的选中状态调整和父节点相同
// childItem->setCheckState(0,item->checkState(0));
// }
//}
#endif // QMYTREE_H
/*main.cpp*/
#include <QApplication>
#include <QTreeWidget>
#include <QStringList>#include "QMyTree.h"using namespace std;void MyWidget::treeWidgetClicked(QTreeWidgetItem* item){// 遍历item节点所有的子节点for(int i=0;i<item->childCount();i++){//找到每个子节点QTreeWidgetItem* childItem=item->child(i);//将子节点的选中状态调整和父节点相同childItem->setCheckState(0,item->checkState(0));}
}int main(int argc,char* argv[]){QApplication a(argc,argv);MyWidget widget;// 因为存在继承关系widget.setWindowTitle("tree控件");widget.resize(600,300);// 嵌入在窗口上QTreeWidget treeWidget(&widget);// 设置列数treeWidget.setColumnCount(3);treeWidget.resize(600,300);// 创建节点QTreeWidgetItem topItem;topItem.setText(0,"教程");// 设置第0列的状态,unchecked表示未选中状态// 默认是未选中的状态topItem.setCheckState(0,Qt::Unchecked);// 创建顶层节点treeWidget.addTopLevelItem(&topItem);//添加子节点QStringList c;c<<"ex"<<"ex2"<<"ex3";QTreeWidgetItem childItem1(&topItem,c);childItem1.setCheckState(0,Qt::Unchecked);QStringList c2;c2<<"ex"<<"ex2"<<"ex3";QTreeWidgetItem childItem2(&topItem,c2);// 设置节点状态childItem2.setCheckState(0,Qt::Unchecked);// 这里的接收方 是自定义的MyWidget 实例对象,只不过继承自QWidget// void treeWidgetClicked(QTreeWidgetItem* item);// 可以看出信号函数 发送,具体来说,槽函数接收到的是一个QTreeWidgetItem类的指针// 下面根据设定,只是将所有子节点的选中状态进行调整QObject::connect(&treeWidget,&QTreeWidget::itemClicked,&widget,&MyWidget::treeWidgetClicked);// 这里 发送方是内置类,及其槽函数,expandItem表示展开该节点的所有子节点QObject::connect(&treeWidget,&QTreeWidget::itemClicked,&treeWidget,&QTreeWidget::expandItem);widget.show();return a.exec();
}
例子2
// treewidget
// 设置一列标签(表头)
QStringList list3;
list3<<"name"<<"address";
ui->treeWidget->setHeaderLabels(list3); // 添加多个列的表头
// version2 以匿名对象的方式创建
// ui->treeWidget->setHeaderLabels(QStringList()<<"name"<<"address");// 添加节点控件
QTreeWidgetItem *treeItem1=new QTreeWidgetItem(QStringList()<<"name1"); // 以匿名方式创建
ui->treeWidget->addTopLevelItem(treeItem1);
QTreeWidgetItem *treeItem2=new QTreeWidgetItem(QStringList()<<"name2"); // 以匿名方式创建
ui->treeWidget->addTopLevelItem(treeItem2);
treeItem1.setIcon(0,QIcon(":/Images/resource")); // 设置图标// 以子节点的方式添加节点控件
QTreeWidgetItem *childitem1=new QTreeWidgetItem(QStringList()<<"childname1"<<"childAddress1"); // 注意这里边 可以添加两个列表的内容
// QTreeWidgetItem *childitem1=new QTreeWidgetItem(QStringList()<<"childname1"<<"childAddress1"<<"3"); // error!!!超过范围添加列表的内容,不会报错,但是不会显示
treeItem1->addChild(childitem1);QTreeWidgetItem *childitem2=new QTreeWidgetItem(QStringList()<<"childname2"<<"childAddress2");
treeItem2->addChild(childitem2);
QTableWidget
表格控件
// 设置行、列
ui->tableWidget->setColumnCount(3);
ui->tableWidget->setRowCount(3);
ui->tableWidget->setHorizontalHeaderLabels(QStringList()<<"name"<<"sex"<<"age");
// ui->tableWidget->setItem(0,0,new QTableWidgetItem("zhangsan"));QStringList namelist;
namelist<<"张三"<<"李四"<<"王五";
QStringList sexlist;
sexlist<<"男"<<"女"<<"男";for (int row=0;row<3;row++)
{int col=0;// 访问容器的方法和访问数组的方法是一样的ui->tableWidget->setItem(row,col++,new QTableWidgetItem(namelist[row]));ui->tableWidget->setItem(row,col++,new QTableWidgetItem(sexlist[row]));ui->tableWidget->setItem(row,col++,new QTableWidgetItem(QString::number(20))); // 设置类型转换
}
containers相关控件
groupbox
分组关联 (将几个控件作为一组)
隔离某些控件
scroll area
相当于滚动布局,可以添加任意控件
tool box
相当于弹力滚动
tabWdiget
相当于页面(窗口)选项卡
内置隐藏功能
注意与tablewidget的区别
stacked widget
相当于栈 (类似于选项卡的功能)
内置隐藏功能,相当于隐藏切换功能,常与button结合使用
感觉不常用
ui->stackedWidget->setindex()
QMainWindow相关控件
QMenuBar/QMenu – QMainWindow
菜单栏,一个窗体只能有一个菜单栏
#include "mainwindow.h"
#include "ui_mainwindow.h"#include <QMenuBar> // 菜单栏
#include <QMenu> // 菜单MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);// 添加菜单栏QMenuBar *menubar=new QMenuBar(this);setMenuBar(menubar); // 等价于this->setMenuBar()// qmeua 是一个文件QMenu *filename=menubar->addMenu("文件");// QMenu *filename=menubar->addMenu("文件(&F)"); // 添加快捷键,使用ctrl+F// ‘文件’下面是一个选项卡// 添加一个选项卡// 添加一个动作filename->addAction("新建文件");filename->addAction("打开文件");filename->addAction("关闭文件");}MainWindow::~MainWindow()
{delete ui;
}
addAction
相当于选项卡
// 添加菜单栏
QMenuBar *menubar=new QMenuBar(this);
setMenuBar(menubar);// qmeua 是一个文件
QMenu *filename=menubar->addMenu("文件");// ‘文件’下面是一个选项卡
// 添加一个选项卡
// 添加一个动作
filename->addAction("新建文件");
filename->addAction("打开文件");
filename->addAction("关闭文件");
addAction 与 信号/槽 ???
QToolBar – QMainWindow
工具栏 一个窗体,可以有多个工具栏 (一个窗体只能有一个菜单栏)
#include <QToolBar> // 工具栏QToolBar * toolbar=new QToolBar(this);
this->addToolBar(Qt::TopToolBarArea,toolbar); // 向窗体添加工具栏toolbar->addAction("新建");
toolbar->addAction("打开");
toolbar->addSeparator(); // 添加分割竖线
toolbar->addAction("关闭");
工具栏设置为图标
exp3
- 直接在ui 的属性栏icon进行选择
- 使用代码的方式
// versoion1
ui->actionNew->setIcon(QIcon("filePath_fileName")); // filepath:\\ 或filepath:/// version2
// 通过代码方式 添加qt资源文件
// 格式 ": + 前缀 + 文件名"
ui->actionNew->setIcon(QIcon(":/Image/images/a.png")); // /Image是前缀
QStatusBar – QMainWindow
状态栏,一个窗口只能有一个状态栏
#include <QStatusBar> // 状态栏
#include <QLabel>QStatusBar *statusbur=new QStatusBar(this);
setStatusBar(statusbur); // 等价于 this->setStatusBar
QLabel *label=new QLabel(this);
label->setText("状态栏"); // 显示文字
statusbur->addWidget(label); // 一个控件内添加一个控件 使用addwidget
QDockWidget – QMainWindow
浮动窗口,浮动窗口可以有多个
位置是相对于 中心区域 的
#include <QDockWidget> // 浮动窗口QDockWidget *docWidget=new QDockWidget(this);
addDockWidget(Qt::LeftDockWidgetArea,docWidget); QDockWidget *docWidget=new QDockWidget("浮动窗口",this);
addDockWidget(Qt::LeftDockWidgetArea,docWidget);
QTextEdit – QMainWindow
文本编辑器,也可以当做中心区域(中心区域通常是文本编辑器)
一个窗口只能有一个中心组件
#include <QTextEdit>/* 中心区域 */
QTextEdit *edit=new QTextEdit("编辑区",this);
setCentralWidget(edit);
自定义控件
见视频
-
- 新建qt designer类
-
- 在ui文件中,基于基本控件创建ui文件
-
- 在主ui文件中添加 containers – widget控件
-
- 右键提升为 -> 1.中新建的类名 -> 确定提升(勾选不勾选全局都可以)(提升为类了,就可以直接利用该类里边的成员函数)
两个控件之间的关联
// C++ 函数指针与函数重载的匹配
void (QSpinBox:: *spin)(int)=&QSpinBox::valueChanged;
// 这里valueChanged 是一个重载函数
connect(ui->spinBox,spin,ui->horizontalSlider,&QSlider::setValue);
connect(ui->horizontalSlider,&QSlider::valueChanged,ui->spinBox,&QSpinBox::setValue);
qt-文件操作
文件读写、创建、删除、重命名、拷贝
可操作:文本文件、二进制文件
文件对话框
#include <QFileDialog>
#include <QString>
#include <QDebug>/*静态数据成员:类的一部分,为类的所有实例共享,处在静态区类名::静态成员访问非静态数据成员:实例的一部分,类的每个实例都有一份拷贝,处在动态区静态函数成员与非静态函数成员,都为类所有,实例对象不存在函数的拷贝静态函数成员:类名::方法 或者 实例对象.方法编译器不向函数传递this指针,不识别实例对象个体,经常用来操作静态数据成员(要访问类的非静态成员可以通过对象来实现)非静态函数成员:实例对象.方法 或者 实例对象->方法调用时编译器向函数传递this指针
*/// 使用静态成员函数的方法调用
QString filename=QFileDialog::getOpenFileName(this,"open file","f:\\",tr("images(*.png *.jpg)")); // tr是字体兼容性的问题
qDebug()<<filename;
字体对话框
#include <QFontDialog>
#include <QString>
#include <QDebug>bool ok; // 标志是否选择一个字体
QFont font=QFontDialog::getFont(&ok,this); // 返回一个字体if (ok)
{ui->FontButton->setFont(font);
}
else
{qDebug()<<"not font be choiced!";
}
输入对话框 – 字符串\数字
void MainWindow::on_InputButton_clicked()
{bool flag; // 是否有输入// QLineEdit:: 显示的模式 // 关键参数是LineEdit::Normal lineEidt::password// password 默认提示字符QString input=QInputDialog::getText(this,"输入对话框","请输入用户名",QLineEdit::Normal,"password",&flag);if (flag){qDebug()<<input;}bool flag_val;int val=QInputDialog::getInt(this,"输入对话框","0-100",0,0,256,1,&flag_val);if (flag){qDebug()<<val;}
}
QMessageBox 消息对话框
// 问题对话框
int ret=QMessageBox::question(this,"question", // 对话框的标题"ues Qt T or F", // 对话框的内容QMessageBox::Yes, // 可选择的模式QMessageBox::No);
if (ret==QMessageBox::yes)
{qDebug()<<"yes";
}// 提示对话框
QMessageBox::information(this,"notice","best to ues qt",QMessageBox::Ok);//警告对话框
QMessageBox::warning(this,"warning","warning...",QMessageBox::Ok);// 关于对话框...
进度对话框
#include <QProgressBox>// 静态成员函数 可以利用 类名::静态成员函数
// 非静态成员函数 可以利用 类名 对象的方式创建
/*静态数据成员:类的一部分,为类的所有实例共享,处在静态区类名::静态成员访问非静态数据成员:实例的一部分,类的每个实例都有一份拷贝,处在动态区静态函数成员与非静态函数成员,都为类所有,实例对象不存在函数的拷贝静态函数成员:类名::方法 或者 实例对象.方法编译器不向函数传递this指针,不识别实例对象个体,经常用来操作静态数据成员(要访问类的非静态成员可以通过对象来实现)非静态函数成员:实例对象.方法 或者 实例对象->方法调用时编译器向函数传递this指针
*/// 该类没有静态成员函数,所以只能通过创建对象来实现// 堆中 全局,不释放
// 由于没有delete 加上对象树的概念,会一直消耗内存
// QProgressDialog *prodlg=new QProgressDialog(this);// 栈中 局部,释放
QProgressDialog prodlg("copy progress","stop",0,50000,this);// 设置模态
prodlg.setWindowModality(Qt::WindowModal);
prodlg.setWindowTitle("copy file");
prodlg.show();for (int i=0;i<50000;i++)
{prodlg.setValue(i);// 类似并发 多线程 强制每隔一段时间还有没有其他时间没做完// copy的同时 检测还有没有其他的事情要做QCoreApplication::processEvents();if (prodlg.wasCanceled()) // 当点击取消的时候{qDebug()<<"stop copy...";
// break;return ;}prodlg.setValue(50000);}
qDebug()<<"copy done...";
文本文件
#include <QApplication>
#include <QDebug>
#include <QFile>int main(int argc, char *argv[])
{QApplication a(argc, argv);// 创建QFile对象,同时指定要操作的文件// 注意这个文件(在使用相对路径的时候)会与可执行文件exe处于同一个路径文件夹下QFile file("./demo.txt");if (!file.open(QIODevice::WriteOnly|QIODevice::Text)){qDebug()<<"文件打开失败"; // 相当于cout,qDebug还有更高级的用法}// 向文件中写入字符串file.write("ex\n");file.write("ex2\n");//关闭文件file.close();//重新打开文件,对文件进行读操作if (!file.open(QIODevice::ReadOnly|QIODevice::Text)){qDebug()<<"文件打开失败";}// 每次都读取一行// 创建一个字符串(字符串数组)char* str=new char[100];// 每次从文件中读取一行数据或读取最多maxSize-1个字节,存储到data中// 返回读取到的字节数qint64 readNum=file.readLine(str,100);// 当读取出现错误 (返回为-1)或者读取到字符数为0时,结束读取while ((readNum!=0)&&(readNum!=-1)){qDebug()<<str;readNum=file.readLine(str,100); // 会覆盖}file.close();return 0;
}
二进制文件
int main(int argc, char *argv[])
{QApplication a(argc, argv);// 指定要写入文件的数据qint32 nums[5]={1,2,3,4,5};// 写入文件之前,将数据转换成字节数组QByteArray byteArr;byteArr .resize(sizeof(nums));for (int i=0;i<5;i++){// 借助指针,将每个整数拷贝到字节数组中memcpy(byteArr.data()+i*sizeof(qint32),&(nums[i]),sizeof(qint32));}// 将byteArr 字节数组存储到文件中QFile file("./demo_byte.dat");file.open(QIODevice::WriteOnly);file.write(byteArr);file.close();// 再次打开文件,读取二进制数据file.open(QIODevice::ReadOnly);QByteArray resArr=file.readAll();qDebug()<<"resArr:"<<resArr;//将二进制转换为整数char* data=resArr.data();while(*data){qDebug()<<*(qint32*)data;data+=sizeof(qint32);}return 0;
}
文件操作进阶
QTextStream
/*QTextStream 类 提供了很多读写文件相关方法
*/
#include <QFile>
#include <QDebug>
#include <QString>
#include <QTextStream>int main(int argc,char* argv[]){// 创建QFile对象QFile file("./demo2.txt");// 对文件进行写操作if (!file.open(QIODevice::WriteOnly|QIODevice::Text)){qDebug()<<"文件打开失败";}QTextStream out(&file);//QTextStream类重载了运算符<< >>out<<(QString)"ex1\n"<<(QString)"ex2";file.close();if (!file.open(QIODevice::ReadOnly|QIODevice::Text)){qDebug()<<"文件打开失败";}QTextStream in(&file);while (!in.atEnd()){QString str;// 从文件中读取一个字符串in>>str;qDebug()<<str;}file.close();return 0;
}
QDataStream
https://blog.csdn.net/qq_38832450/article/details/102587454
- QDataStream 与QByteArray
https://blog.csdn.net/qq_40206060/article/details/111614662
借助QDataStream 实现数据与QByteArray的关联,输入与输出
- QDataStream 与QBuffer
https://blog.csdn.net/qq_44519484/article/details/108010891
QBuffer
- QBuffer与QByteArray
https://blog.csdn.net/qq_44519484/article/details/108010891
QBuffer 是操作QByteArray的接口类
QDataStream 是一个操作QBuffer的接口类
定时器
// 创建一个定时器
// version1 建立信号和槽函数
QTimer *timer=new QTimer(this);
timer->start(1000); // 毫秒为单位
connect(timer,&QTimer::timeout,this,&Widget::change_labelValue);
// connect(timer,&QTimer::timeout,this,SLOT(change_labelValue())); // 错误写法
// connect(timer,&QTimer::timeout,this,&(this->change_labelValue)); // 错误写法// version2 重写定时器事件
timerId1=startTimer(1000); // 直接启动定时器
timerId2=startTimer(1000); // 直接启动定时器
// 对应version1 信号和槽函数
void Widget::change_labelValue(void)
{static int var=1;ui->label_3->setText(QString::number(var++));
}
// 重写定时器事件
int timerId1;
int timerId2;// version2 重写定时器事件
timerId1=startTimer(1000); // 直接启动定时器
timerId2=startTimer(1000); // 直接启动定时器// 对应version2 定时器事件
void Widget::timerEvent(QTimerEvent *event)
{// version1
// static int num=1;
// ui->label_4->setText(QString::number(num++));// version2if (event->timerId()==timerId1){static int num1=1;ui->label_3->setText(QString::number(num1++));}else if (event->timerId()==timerId2){static int num2=2;ui->label_4->setText(QString::number(num2++));}
}
QPainter绘图
QPaintEvent
绘图事件 – >paintEvent
绘图事件处理函数
当发生QPaintEvent
绘图事件时,就自动调用paintEvent
绘图事件处理函数
对于
QPainterEvent
绘图事件处理函数,当程序运行后,窗体自动调用QPainterEvent
绘图事件处理函数
事件处理
void Widget::paintEvent(QPaintEvent *)
{QPainter painter(this); // 创建一个QPainter类对象 调用构造函数 this指针指向的是当前Widget这个窗体painter.setPen(Qt::blue);painter.setFont(QFont("Arial",30));painter.drawText(rect(),Qt::AlignCenter,"Qt"); // rect表示在一个矩形的区域里绘制文字// 绘制文字QFont font("楷体",20,QFont::Bold,true); // 字体、字号、加速、斜体font.setUnderline(true); // 设置下划线painter.setFont(font);painter.setPen(Qt::blue);painter.drawText(50,50,"hello world"); // 50,50表示左上角坐标// 指定使用绘图工具QPen pen(QColor(255,0,0)); // 创建一个画笔pen.setWidth(3); // 设置粗细pen.setStyle(Qt::DashDotDotLine);painter.setPen(pen); // 使用绘笔// 画线painter.drawLine(QPoint(0,0),QPoint(100,100)); // 创建QPoint的匿名对象// 画圆painter.drawEllipse(QPoint(100,100),20,20);// 椭圆painter.drawEllipse(QPoint(100,100),50,30);// 矩形painter.drawRect(100,100,30,50); // (100,100)是左上角的坐标// 正方形painter.drawRect(100,100,80,80);// QPen 画笔// QBrush 画刷QBrush brush(Qt::green,Qt::Dense1Pattern);painter.setBrush(brush);
// painter.setPen(pen); // 加不加setPen都行好像painter.drawRect(200,200,80,80);
}
事件处理进阶
#include "widget.h"
#include "ui_widget.h"
#include <QPainter>
#include <QPen>
#include <QPoint>
#include <QTimer>
Widget::Widget(QWidget *parent) :QWidget(parent),ui(new Ui::Widget)
{ui->setupUi(this);angle=0;// 创建定时器QTimer *timer=new QTimer(this);timer->start(1000);// QWidget::update 会自动调用paintEvent函数!!!void (QWidget:: *widget_update)()=&QWidget::update;connect(timer,&QTimer::timeout,this,widget_update); // 因为存储在函数重载
// connect(timer,&QTimer::timeout,this,&QWidget::repaint);
}void Widget::paintEvent(QPaintEvent*)
{QPainter painter(this);// 更新angleangle+=10;if (angle==360) angle=0;// 抗锯齿painter.setRenderHint(QPainter::Antialiasing);// 将坐标系平移到当前窗体的中心,其始终是跟随状态// this->width(),this->height()painter.translate(this->width()/2,this->height()/2);painter.drawEllipse(QPoint(0,0),120,120);painter.rotate(angle);painter.drawLine(QPoint(0,0),QPoint(100,0));}
绘制设置
锥形渐变
void Widget::paintEvent(QPaintEvent *)
{QPainter painter(this); // 创建一个QPainter类对象 调用构造函数 this指针指向的是当前Widget这个窗体// 锥形渐变// 默认逆时针旋转,0表示实际的三点钟方向QConicalGradient conicalGradient(QPointF(200,100),0); // 创建一个对象 0表示angleconicalGradient.setColorAt(0.2,Qt::cyan); // 设置渐变色 0-1 0到360*0.2=72度逐渐变为Qt::cyanconicalGradient.setColorAt(0.4,Qt::black); // 设置渐变色 0-1 从72度到72+72度逐渐变为黑色conicalGradient.setColorAt(0.7,Qt::red); // 设置渐变色 0-1 黑色渐变位红色conicalGradient.setColorAt(0.7,Qt::yellow); // 设置渐变色 0-1painter.setBrush(conicalGradient); // 利用锥形渐变作为画刷painter.drawEllipse(QPointF(200,100),50,50);
}
抗锯齿
void Widget::paintEvent(QPaintEvent*)
{QPainter painter(this);// version 1
// QPen pen(QColor(255,0,0));
// painter.setPen(pen);// version 2 创建匿名画笔painter.setPen(QPen(Qt::red,15));painter.drawEllipse(QPoint(200,200),100,100);// 抗锯齿painter.setRenderHints(QPainter::Antialiasing);painter.translate(200,0); // 向右平移,相当于坐标系平移painter.drawEllipse(QPoint(200,200),100,100);
}
坐标系变换
void Widget::paintEvent(QPaintEvent*)
{QPainter painter(this); /* 坐标系旋转平移 */painter.setPen(QPen(Qt::red,10));// 直线painter.drawLine(QPoint(10,10),QPoint(100,100));painter.save(); // 保存当前坐标系(此时是初始状态)painter.translate(200,0); // 坐标系平移200painter.rotate(90); // 顺时针旋转90/*A --> A'\ /\ /\/B/B'*/painter.setPen(QPen(Qt::blue,10));painter.drawLine(QPoint(10,10),QPoint(100,100));/* 恢复坐标系 */painter.restore();painter.setPen(QPen(Qt::black,3));painter.drawLine(QPoint(11,11),QPoint(200,200));/* 坐标系旋转缩放 */painter.setPen(QPen(Qt::red,3));painter.setBrush(Qt::yellow); // 设置画刷用于填充painter.drawRect(50,50,50,50); // 正方形painter.save();painter.scale(1.5,2);painter.setBrush(Qt::green); // 设置画刷用于填充painter.drawRect(50,50,50,50); // 正方形
}
容器路径
QPainterPath 表示一个容器,可以放置之前绘制的各种各样的图形
目标就是要重复绘制
void Widget::paintEvent(QPaintEvent*)
{QPainter painter(this);// 准备一个容器,设置容器内的内容QPainterPath painterPath;painterPath.moveTo(50,250); // 移动起始位置painterPath.lineTo(50,200);painterPath.lineTo(100,100);painterPath.addEllipse(QPoint(100,100),30,30);// 指定painter进行绘制painter.setPen(Qt::red);painter.drawPath(painterPath);// 容器移动坐标系painterPath.translate(200,0);painter.setPen(Qt::blue);painter.drawPath(painterPath);
}
qt-图像操作
https://blog.csdn.net/iriczhao/article/details/123265538
https://blog.csdn.net/weixin_44116061/article/details/106412187!!!
https://blog.csdn.net/qq_45662588/article/details/120366824
- QPixmap
- QImage
- QBitmap
- QPicture
QPixmap
图片类,用于显示图片
对于图片的显示做了优化处理
在平台有关,不同平台在内部的存储形式有区别
只能在主线程中使用
构建/保存
// 相当于一个画布,不依赖与Widget
QPixmap pix(400,300); // 像素是400,300
pix.fill(Qt::white);
QPainter painter(&pix);
painter.setPen(Qt::red);
painter.drawEllipse(QPoint(100,100),50,50);
pix.save("./mypix.jpg"); // 保存到本地磁盘
void Widget::paintEvent(QPaintEvent *)
{QPainter painter(this);QPixmap pix;pix.load("mypix.jpg");painter.drawPixmap(0,0,50,50,pix); //在(0,0)点起始的宽高均为50的句型中显示图片painter.translate(50,50); //将起始点改为(50,50)painter.drawPixmap(0,0,50,50,pix); //在(50,50)起始的宽高为50的矩形中显示图片
}
QLabel/QPixmap
QPixmap pix("/path");
QLabel label;
label.setPixmap(pix);
label.show();
QPixmap/QImage
通常,QImage 类用于加载图像文件,并操作图像数据。然后将 QImage 对象转成 QPixmap 对象在屏幕上显示
QImage --> QPixmap
QPixmap::fromImage
QPixmap --> QImage
QPixmap::toImage
QPixmap/imageReader
fromImagereader
从直接从 imageReader 读取的图像创建 QPixmap
QPixmap/QByteArray
loadFromData
uchar* 或 QByteArray --> QPixmap
从直接从 imageReader 读取的图像创建 QPixmap
QPixmap/QDatastream/QFile
写入
将给定的像素图作为 PNG 图像写入给定的流。
注意,将流写入文件不会产生有效的图像文件
QFile file("file.dat");
QDataStream stream(&file);
file.open(QIODevice::WriteOnly);QPixmap pixmap("D://eee.jpg");
stream << pixmap;
file.close();
读取
从给定的流中读取图像到给定的像素图
QFile file("file.dat");
file.open(QIODevice::ReadOnly);
QDataStream stream(&file);
QPixmap pixmap;
stream >> pixmap;
file.close();QLabel label;
label.setPixmap(pixmap);
label.show();
QImage
图片类,不依赖于平台,任何平台在内部的存储形式都是一样的
可以用于多线程中
多用于图片的传输,可以做像素级的修改
构建/保存
QImage img(400,300,QImage::Format_RGB32);
img.fill(Qt::white);
QPainter painter(&img);
painter.setPen(Qt::red);
painter.drawEllipse(QPoint(100,100),50,50);
img.save("./myimg.jpg"); // 保存到本地磁盘
加载/像素级修改
void Widget::paintEvent(QPaintEvent*)
{QPainter painter(this);QImage img;img.load(":/images/images/bus.jpg");for (int i=50;i<100;i++){for (int j=50;j<100;j++){img.setPixel(i,j,qRgb(255,0,0));}}painter.drawImage(0,0,img);
}
QImage/QLabel
QImage/QPixmap
QImage/imageReader
QImage/QByteArray
QImage/QDatastream/QFile
QPicture
可以理解为一个绘图的工具,保存有绘图的记录(类比QPainterPath)和重绘制的指令
存储的形式是二进制形式
Widget::Widget(QWidget *parent) :QWidget(parent),ui(new Ui::Widget)
{ui->setupUi(this);QPicture pic;// version1
// QPainter painter(&pic);
// painter.setPen(Qt::red);
// painter.drawEllipse(QPoint(100,100),50,50);
// painter.end();// version2QPainter painter;painter.begin(&pic);painter.setPen(Qt::red);painter.drawEllipse(QPoint(100,100),50,50);painter.end();// pic.save("./mypic.dat"); //二进制的形式}
加载
void Widget::paintEvent(QPaintEvent*)
{QPainter painter(this);QPicture pic;pic.load("./mypic.dat");painter.drawPicture(0,0,pic);
}
QBitmap
只能是黑白图像 不能是彩色图像
QBitmap bm(400,300);
QPainter painter(&bm);
painter.setPen(Qt::red);
painter.drawEllipse(QPoint(100,100),50,50);
bm.save("./bm.jpg");
qt-socket
ud p
#include <QUdpSocket>
#include <QHostAddress>QUdpSocket* udpSocket;udpSocket = new QUdpSocket(this);/*服务端
*/
udpSocket->bind(ui->listenPort->text().toUInt()// readyRead() 内置的信号函数
QObject::connect(udpSocket,SIGNAL(readyRead()),this,SLOT(socket_readData_slot()));// 槽函数
void Widget::socket_readData_slot(){QByteArray datagarm;QHostAddress target_ipAddress;quint16 target_port;while (udpSocket->hasPendingDatagrams()){datagarm.resize(udpSocket->pendingDatagramSize());udpSocket->readDatagram(datagarm.data(),datagarm.size(),&target_ipAddress,&target_port);}
}/*客户端
*/
void Widget::on_pushButton_sendData_clicked()
{QHostAddress target_ipAddress;quint16 target_port;QString sendBuff;target_ipAddress.setAddress(ui->targetIp->text());target_port=ui->targetPort->text().toInt();sendBuff=ui->dataInputed->text();udpSocket_client->writeDatagram(sendBuff.toUtf8().data(),sendBuff.length(),target_ipAddress,target_port);
// ui->plainTextEdit->appendPlainText("send datagram to "+target_ipAddress.toString()+":"+QString::number(target_port));
// ui->plainTextEdit->appendPlainText("datagram content: \n"+sendBuff);
}
tcp
https://blog.csdn.net/qq_40876689/article/details/113952635
https://blog.csdn.net/mitongxue/article/details/124622386
https://blog.csdn.net/object__/article/details/122821061
/*服务端
*/
#include <QTcpServer>
#include <QTcpSocket>QTcpServer *tcpServer;
tcpServer = new QTcpServer(this); tcpServer->listen(QHostAddress::Any,6666)//连接信号和相应槽函数,有新的连接进入是需处理
// 有新的连接接过来,会触发newConnection()信号函数,触发槽函数NewConnection()
connect(tcpServer,SIGNAL(newConnection()),this,SLOT(NewConnection())); // 信号与槽函数// 槽函数
void Widget::NewConnection()
{//初始化为0;//blockSize=0;// inBlock.resize(0);//新连接进入的显示处理// 取出连接号的套接字currentClient = tcpServer->nextPendingConnection();// QString ip=tcpsocket->peerAddress().toString();//获取连接的 ip地址// quint16 port=tcpsocket->peerPort();//获取连接的 端口号ui->statuslab->setText(tr("%1:%2").arg(currentClient->peerAddress().toString().split("::ffff:")[1]).arg(currentClient->peerPort()));//客户端发来数据就会触发readyRead信号connect(currentClient, SIGNAL(readyRead()), this, SLOT(recMessage()));//对方断开连接后就会触发disconnected信号connect(currentClient, SIGNAL(disconnected()), this, SLOT(disconnect()));//当有数据发送成功时,继续发送???connect(currentClient,SIGNAL(bytesWritten(qint64)),this, SLOT(continueSend(qint64)));ui->sendButton->setEnabled(true);
}
离线
QFileDialog
QFile file(filename)
file.open(write/read)
QDataStream in(&file)
QByteArray data
in >> data// coding...setPixmap(QPixmap::fromImage(image))
在线
QDataStream in(client)client->bytesAvailable()in >> data >> stringQByteArray imagedata
imagedata +=client->readAll()QBuffer buffer(&imagedata)
buffer.open(readtype)
QImageReader reader(&buffer,'jpg')
QImage image=reader.read()image=image.scaled()
setPixmap(QPixmap::fromImage(image))
安装问题
https://blog.csdn.net/qimo601/article/details/120197947
https://blog.csdn.net/husky66/article/details/117221693 !!! --这个无敌了
相关文章:
Qt-基础
Qt1. 概念其他概念对话框模态对话框与非模态对话框事件事件拦截/过滤事件例子鼠标/屏幕使用界面功能qt-designer工具debug目录结构mainwindow控件窗口QMainWindow事件2. 项目概览QOBJECT tree 对象树3. 信号和槽信号函数关联自定义信号和槽函数自定义信号和槽函数1自定义信号和…...
ABB机器人将实时坐标发送给西门子PLC的具体方法示例
ABB机器人将实时坐标发送给西门子PLC的具体方法示例 本次以PROFINET通信为例进行说明,演示ABB机器人将实时坐标发送给西门子PLC的具体方法。 首先,要保证ABB机器人和PLC的信号地址分配已经完成,具体的内容可参考以下链接: S7-1200PLC与ABB机器人进行PROFINET通信的具体方法…...
反向传播与梯度下降详解
一,前向传播与反向传播 1.1,神经网络训练过程 神经网络训练过程是: 先通过随机参数“猜“一个结果(模型前向传播过程),这里称为预测结果 a a a;然后计算 a a a 与样本标签值...
Skywalking ui页面功能介绍
菜单栏 仪表盘:查看被监控服务的运行状态; 拓扑图:以拓扑图的方式展现服务之间的关系,并以此为入口查看相关信息; 追踪:以接口列表的方式展现,追踪接口内部调用过程; 性能剖析&am…...
哪里可以找到免费的 PDF 阅读编辑器?7 个免费 PDF 阅读编辑器分享
如果您曾经需要编辑 PDF,您可能会发现很难找到免费的 PDF 编辑器。幸运的是,您可以使用在线资源来编辑该文档,而无需为软件付费。 在本文中,我将介绍七种不同的 PDF 编辑器,它们至少可以让您免费编辑几个文件。我通过…...
使用梯度下降的线性回归(Matlab代码实现)
目录 💥1 概述 📚2 运行结果 🎉3 参考文献 👨💻4 Matlab代码 💥1 概述 梯度下降法,是一种基于搜索的最优化方法,最用是最小化一个损失函数。梯度下降是迭代法的一种,可以用于求…...
在Ubuntu上设置MySQL可以远程登录
在Ubuntu上设置MySQL可以远程登录一.设置数据库二.设置防火墙由于Ubuntu查看修改MySQL不是很方便,想着在虚拟机安装的Windows系统或者局域网中的其他电脑上去查看Ubuntu系统上的数据库,这样省事一些,我电脑安装的数据库是MySQL8。一.设置数据…...
清风1.层次分析法
一.流程1.建立评价体系2.建立判断矩阵2.1 A-C-C矩阵从准则层对目标层的特征向量上看,花费的权重最大算术平均法求权重的结果为:0.26230.47440.05450.09850.1103几何平均法求权重的结果为:0.26360.47730.05310.09880.1072特征值法求权重的结果…...
「首席架构师推荐」免费数据可视化软件你喜欢哪一个?
数据可视化,是关于数据视觉表现形式的科学技术研究。其中,这种数据的视觉表现形式被定义为,一种以某种概要形式抽提出来的信息,包括相应信息单位的各种属性和变量。它是一个处于不断演变之中的概念,其边界在不断地扩大…...
深度学习术语解释:backbone、head、neck,etc
backbone:翻译为主干网络的意思,既然说是主干网络,就代表其是网络的一部分,那么是哪部分呢?这个主干网络大多时候指的是提取特征的网络,其作用就是提取图片中的信息,共后面的网络使用。这些网络…...
基础篇—CSS margin(外边距)解析
什么是CSS margin(外边距)? CSS margin(外边距)属性定义元素周围的空间。 属性描述margin简写属性。在一个声明中设置所有外边距属性。margin-bottom设置元素的下外边距。margin-left设置元素的左外边距。margin-right设置元素的右外边距。margin-top设置元素的上外边距。mar…...
ChatGPT或将引发新一轮失业潮?是真的吗?
最近,要说有什么热度不减的话题,那ChatGPT必然榜上有名。据悉是这是由美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类…...
【Selenium学习】Selenium 中特殊元素操作
1.鼠标定位操作鼠标悬停,即当光标与其名称表示的元素重叠时触发的事件,在 Selenium 中将键盘鼠标操作封装在 Action Chains 类中。Action Chains 类的主要应用场景为单击鼠标、双击鼠标、鼠标拖曳等。部分常用的方法使用分类如下:• click(on…...
Spark相关的依赖冲突,后期持续更新总结
Spark相关的依赖冲突持续更新总结 Spark-Hive_2.11依赖报错 这个依赖是Spark开启支持hive SQL解析,其中2.11是Spark对应的Scala版本,如Spark2.4.7,对应的Scala版本是2.11.12;这个依赖会由于Spark内部调用的依赖guava的版本问题出…...
【每日一题Day122】LC1237找出给定方程的正整数解 | 双指针 二分查找
找出给定方程的正整数解【LC1237】 给你一个函数 f(x, y) 和一个目标结果 z,函数公式未知,请你计算方程 f(x,y) z 所有可能的正整数 数对 x 和 y。满足条件的结果数对可以按任意顺序返回。 尽管函数的具体式子未知,但它是单调递增函数&#…...
笔记本加装固态和内存条教程(超详细)
由于笔记本是几年前买的了,当时是4000,现在用起来感到卡顿,启动、运行速度特别慢,就决定换个固态硬盘,加个内存条,再给笔记本续命几年。先说一下加固态硬盘SSD的好处:1.启动快 2.读取延迟小 3.写…...
【Python】字典 - Dictionary
字典 - Dictionarykeys()values()items()get()获取文件中指定字符的个数进阶版:获取所有单词的频数进阶版:获取所有字符的频数函数内容keys()输出字典中的所有键values()输出字典中的所有值items()以元组的形式输出键值对get()获取字典中指定键的值 keys…...
LeetCode分类刷题----二叉树
二叉树1.二叉树的递归遍历144.二叉树的前序遍历145.二叉树的后序遍历94.二叉树的中序遍历2.二叉树的迭代遍历144.二叉树的前序遍历145.二叉树的后序遍历94.二叉树的中序遍历3.二叉树的层序遍历102.二叉树的层序遍历107.二叉树的层序遍历||199.二叉树的右视图637.二叉树的层平均…...
Zipkin : Golang 微服务全链路监控(三)
Zipkin : Golang 微服务全链路监控(三) Golang 微服务全链路监控实现 broker-service -> auth-service -> postgres dbzipkin 监控:需代码入侵 使用 zipkin 库的 serverMiddleware,其通过 Http 跟踪(trace&am…...
5.3 BGP路由黑洞
5.2.3实验3:BGP路由黑洞 1. 实验目的 熟悉BGP路由黑洞的应用场景掌握BGP水平分割的配置方法2. 实验拓扑 实验拓扑如图5-3所示: 图5-3:BGP路由黑洞 3. 实验步骤 配置IP地址 R1的配置 <Huawei>syst...
STM32 DFU模式烧录代码
什么是DFU? dfu的本质是isp,usb接口的isp,在系统编程,进入isp的方式我们先了解 如下图 boot0为高电平 boot1为低电平即可进入isp模式。 熟悉的场景 在我们使用flymcu软件下载代码时,本质也是isp 串口接口的isp。 傻瓜使用方式…...
松下PLC通过fpwin上传写入MRTC模块方法
目录 PLC程序上传方法 加密模块使用 PLC程序上传方法 手动将PLC模式设置为prog模式查看PLC是否设置为禁止上传查询指示灯是否变蓝,变蓝则需要将PLC禁止上传功能取消。 3.当上述动作操作完成后,将PLC程序导入到PLC中。为了配合加密程序使用,…...
就业大山之下的网络安全:安逸的安服仔
从去年开始,各个互联网大厂就接二连三的放出了裁员消息,整个互联网行业好像都处于寒冬状态。微博、小米、滴滴、知乎、拼多多等在内的一大批互联网知名企业,也相继传出“人员优化”的消息。 除了国内市场的萧条,国外市场也是不容…...
JavaWeb3-线程的3种创建方式7种写法
目录 1.方式一:继承Thread(2种写法) 写法①(常规): a.使用jconsole观察线程 b.启动线程——start方法 PS:(常见面试题)start 方法与 run 方法的区别: 写…...
驱动调试手段
文章目录 前言一、通过sysfs调试LCD查看电源:查看 pwm 信息查看管脚信息总结前言 本文记录在驱动中常用的调试手段 提示:以下是本篇文章正文内容,下面案例可供参考 一、通过sysfs 系统起来之后可以读取 sysfs 一些信息,来协助调试 示例: 调试LCD 输入如下命令 cat /…...
[RK3568 Android12] 音频及路由
1:概述(耳机 ,hdmiin ,板载喇叭) 在开发板上面,系统注册了三个音频输出通道,如下: [ 2.280612] ALSA device list: [ 2.280622] #0: rockchip,rk809-codec [ 2.280630] #1: ROCKCHIP,SPDIF [ 2.280638] #2: rockchip,hdmi console:/proc/asound # cat pcm …...
C++——C++11 第一篇
目录 统一的列表初始化 {}初始化 decltype 编辑 nullptr STL中一些变化 右值引用和移动语义 左值引用和右值引用 总结 左值引用优缺点 右值引用(将亡值) 拷贝赋值和移动赋值 万能引用|完美转发 移动构造和移动赋值注意…...
Spring Data JPA 中 CrudRepository 和 JpaRepository 的区别
1 问题描述Spring Data JPA 中,CrudRepository 和 JpaRepository 有何区别?当我在网上找例子的时候,发现它们可以互相替换使用。它们有什么不同呢?为什么你习惯用其中的一个而不是另一个呢?2 CrudRepository 和 JpaRep…...
推荐几款好用的数据库管理工具
本文主要介绍几款常用的数据库管理软件(客户端),包括开源/免费的、商用收费的,其中有一些是专用于 MySQL 数据库的,例如 MySQL Workbench、phpMyAdmin,有一些是支持多种 SQL、NoSQL 数据库的,例…...
DPDK — 性能优化手段
目录 文章目录 目录硬件布局层面的优化操作系统层面的优化Linux 操作系统版本应用程序层面的优化Cache 优化内存对齐内存预取SIMD 报文批处理DDIO使用高级 CPU 指令集硬件布局层面的优化 DPDK 在硬件布局层面的优化,主要体现在以下几个方面: CPU 频率的高低:CPU 频率越高,…...
wordpress4.0.x 下载/搜索引擎有哪些?
来源:ConsenSys由 ConsenSys 推出的 Infura 提供了世界领先的区块链开发工具套件,其用户基数已经在不到一年的时间里增加了 250%,从 10 万人增加到 35 万人。Infura 平台提供 API 服务,可以快速连接到以太坊和其他网络 (如 IPFS、…...
手机做网站多少钱/国外免费网站服务器
作者:Derek 简介 Github地址:https://github.com/Bytom/bytom Gitee地址:https://gitee.com/BytomBlockc... 本章介绍Derek解读-Bytom源码分析-创世区块 作者使用MacOS操作系统,其他平台也大同小异Golang Version: 1.8 创世区块介…...
wordpress 新建页面 所有文章/优化推广什么意思
题目描述 【问题描述】 Gardon 昨天给小希布置了一道作业,即根据一张由不超过 5000 的 N(3<N<100)个正整数组成的数表两两相加得到 N*(N-1)/2 个和,然后再将它们排序。例如,如果数表里含有四个数 1,3,4&#x…...
网站建设服务开税率多少的票/搜索关键词怎么让排名靠前
考虑以下代码: int x; void someFunc() {double x;std::cin >> x; };读取数据的语句涉的是局部变量x,而不是全局变量x,因为内层作用域的名称会遮掩外围作用域的名称。 考虑以下的类: class Base { private:int x; public:virtual vo…...
网站怎么防k/三台网站seo
有没有一种,情况: 1. 程序A打开了文件管理器; 2. 程序B又打开了文件管理器; 导致开了两个文件管理器,太不舒服了; 搜索下 kubuntu dolphin single instance,果然找到了解决方法: 文件…...
做网站banner是什么意思/百度指数官网入口
开发的项目多种多样,有时候程序员也会遇到瓶颈不知如何往下操作,今天爱站技术频道小编为大家编写了iOS开发之如何给View添加指定位置的边框线详解,希望对大家有所帮助!示例代码封装一:直接封装成了一个方法/// 边框类型…...