当前位置: 首页 > news >正文

重庆大渡口营销型网站建设公司推荐推广引流渠道平台

重庆大渡口营销型网站建设公司推荐,推广引流渠道平台,潍坊网站开发,无锡做网站优化哪家好Qt1. 概念其他概念对话框模态对话框与非模态对话框事件事件拦截/过滤事件例子鼠标/屏幕使用界面功能qt-designer工具debug目录结构mainwindow控件窗口QMainWindow事件2. 项目概览QOBJECT tree 对象树3. 信号和槽信号函数关联自定义信号和槽函数自定义信号和槽函数1自定义信号和… Qt1. 概念其他概念对话框模态对话框与非模态对话框事件事件拦截/过滤事件例子鼠标/屏幕使用界面功能qt-designer工具debug目录结构mainwindow控件窗口QMainWindow事件2. 项目概览QOBJECT tree 对象树3. 信号和槽信号函数关联自定义信号和槽函数自定义信号和槽函数1自定义信号和槽函数 例子2一个信号触发另一个信号 -- 例子1的进阶4. 控件QWidgetQLabel显示图片input相关控件QLineEditText EditPlain Text Editcombo boxspin boxdouble spin boxtime editdate editdialxxx scroll Barxxx Sliderbutton相关控件QPushButtontoolbuttonradiobuttoncheckboxlist/tree/table-widgetsitem views/item widgetsQListWidgetQTreeWidgetQTableWidgetcontainers相关控件groupboxscroll areatool boxtabWdigetstacked widgetQMainWindow相关控件QMenuBar/QMenu -- QMainWindowaddActionaddAction 与 信号/槽 QToolBar -- QMainWindow工具栏设置为图标QStatusBar -- QMainWindowQDockWidget -- QMainWindowQTextEdit -- QMainWindow自定义控件qt-文件操作文件对话框字体对话框输入对话框 -- 字符串\数字QMessageBox 消息对话框进度对话框文本文件二进制文件文件操作进阶QTextStreamQDataStreamQBuffer定时器QPainter绘图事件处理事件处理进阶绘制设置坐标系变换容器路径qt-图像操作QPixmapQLabel/QPixmapQPixmap/QImageQPixmap/imageReaderQPixmap/QByteArrayQPixmap/QDatastream/QFileQImageQImage/QLabelQImage/QPixmapQImage/imageReaderQImage/QByteArrayQImage/QDatastream/QFileQPictureQBitmapqt-socketud ptcp离线在线安装问题1. 概念 项目 代码集合代码互相之间有关联 项目文件负责管理项目的文件集成开发环境根据项目文件管理和构建项目 qt.pro文件vsvcproj 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 *dialognew 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 QWidgetQT_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.hvoid 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基于Cqt提供的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 --派生- QMainWindowQMainWindow 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 c17 # 启用新的标准# 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_BEFORE0x060000 # 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 QPushButtonint 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 QWidgetQT_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 *parent0)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 slotsprotected slotsprivate 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 QPushButtonint 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.message1ex1;mywidget.message2ex2;// 将类的成员函数作为槽函数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 QObjectclass 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.hMysignal::Mysignal(QObject *parent): QObject{parent} {}槽类 /* myslot.h */ #ifndef MYSLOT_H #define MYSLOT_H#include QObjectclass 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 QDebugMySlot::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.hQT_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 QLabelWidget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui-setupUi(this);this-setFixedSize(500,500); // 设置固定的框高不可更改this-setWindowTitle(main window); // 设置窗口名mSignalnew Mysignal(this);mSlotnew MySlot(this);this-num1;// 关联信号函数和槽函数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 QLabelint 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.hQT_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 QLabelWidget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui-setupUi(this);this-setFixedSize(500,500); // 设置固定的框高不可更改this-setWindowTitle(main window); // 设置窗口名// 实例化 信号函数mSlotnew MySlot(this);// 实例化 槽函数mSignalnew 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 QObjectclass Mysignal : public QObject {Q_OBJECT public:explicit Mysignal(QObject *parent nullptr);signals:void my_signal(void); };#endif // MYSIGNAL_H/* mysignal.cpp */ #include mysignal.hMysignal::Mysignal(QObject *parent): QObject{parent} {// 可以不写任何东西 }// 不用对void my_signal(void) 函数进行定义槽函数 /* myslot.h */ #ifndef MYSLOT_H #define MYSLOT_H#include QObjectclass 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 QDebugMySlot::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::setWindowStateMyWdiget::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 QLabelint main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;QLabel *labelnew QLabel; // 单独一个窗体label-setParent(w); // 设置parent父窗口 // 利用指针创建就要利用new开辟一个QLabel这个类对象大小的内存空间QLabel *labelnew QLabel(w); // 设置parent父窗口label-setText(hello qt);w.show();return a.exec(); } #include widget.h #include ui_widget.h #include QLabelWidget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui-setupUi(this); QLabel *label1new QLabel(this); // this 相当于是Widget对象 等价于labe.setParent(w)label1-setText(hello qt1);label1-move(10,10); // 设置位置QLabel *label2new 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 imgQPixmap(:/icon/icon/Application.ico); ui-label_2-setPixmap(img); // 图片根据控件进行缩放 ui-label_2-setScaledContents(true);// 添加动图 QMovie *mvnew 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 QPushButtonint 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_itemnew 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 QListWidgetItemclass 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.husing 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 *listitemnew QListWidgetItem(qt); ui-listWidget-addItem(listitem); // 设置对齐方式 listitem-setTextAlignment(Qt::AlignHCenter);// 添加多个元素 QStringList list2; list2abcdefghijk; ui-listWidget_2-addItems(list2);QTreeWidget 树型控件 QTreeWidgetItem树型结构中的节点节点控件用于创建节点 可以创建多个顶层节点顶层节点也是节点QTreeWidgetItem类的对象 在不创建表头的时候默认表头是列的序号从1开始 #include QApplication #include QTreeWidget #include QTreeWidgetItemint 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 QTreeWidgetItemclass MyWidget:public QWidget{Q_OBJECTpublic slots: // 定义槽函数void treeWidgetClicked(QTreeWidgetItem* item); };//void MyWidget::treeWidgetClicked(QTreeWidgetItem* item){ // // 遍历item节点所有的子节点 // for(int i0;iitem-childCount();i){ // //找到每个子节点 // QTreeWidgetItem* childItemitem-child(i); // //将子节点的选中状态调整和父节点相同 // childItem-setCheckState(0,item-checkState(0)); // } //} #endif // QMYTREE_H /*main.cpp*/ #include QApplication #include QTreeWidget #include QStringList#include QMyTree.husing namespace std;void MyWidget::treeWidgetClicked(QTreeWidgetItem* item){// 遍历item节点所有的子节点for(int i0;iitem-childCount();i){//找到每个子节点QTreeWidgetItem* childItemitem-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;cexex2ex3;QTreeWidgetItem childItem1(topItem,c);childItem1.setCheckState(0,Qt::Unchecked);QStringList c2;c2exex2ex3;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; list3nameaddress; ui-treeWidget-setHeaderLabels(list3); // 添加多个列的表头 // version2 以匿名对象的方式创建 // ui-treeWidget-setHeaderLabels(QStringList()nameaddress);// 添加节点控件 QTreeWidgetItem *treeItem1new QTreeWidgetItem(QStringList()name1); // 以匿名方式创建 ui-treeWidget-addTopLevelItem(treeItem1); QTreeWidgetItem *treeItem2new QTreeWidgetItem(QStringList()name2); // 以匿名方式创建 ui-treeWidget-addTopLevelItem(treeItem2); treeItem1.setIcon(0,QIcon(:/Images/resource)); // 设置图标// 以子节点的方式添加节点控件 QTreeWidgetItem *childitem1new QTreeWidgetItem(QStringList()childname1childAddress1); // 注意这里边 可以添加两个列表的内容 // QTreeWidgetItem *childitem1new QTreeWidgetItem(QStringList()childname1childAddress13); // error超过范围添加列表的内容不会报错但是不会显示 treeItem1-addChild(childitem1);QTreeWidgetItem *childitem2new QTreeWidgetItem(QStringList()childname2childAddress2); treeItem2-addChild(childitem2); QTableWidget 表格控件 // 设置行、列 ui-tableWidget-setColumnCount(3); ui-tableWidget-setRowCount(3); ui-tableWidget-setHorizontalHeaderLabels(QStringList()namesexage); // ui-tableWidget-setItem(0,0,new QTableWidgetItem(zhangsan));QStringList namelist; namelist张三李四王五; QStringList sexlist; sexlist男女男;for (int row0;row3;row) {int col0;// 访问容器的方法和访问数组的方法是一样的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 *menubarnew QMenuBar(this);setMenuBar(menubar); // 等价于this-setMenuBar()// qmeua 是一个文件QMenu *filenamemenubar-addMenu(文件);// QMenu *filenamemenubar-addMenu(文件(F)); // 添加快捷键使用ctrlF// ‘文件’下面是一个选项卡// 添加一个选项卡// 添加一个动作filename-addAction(新建文件);filename-addAction(打开文件);filename-addAction(关闭文件);}MainWindow::~MainWindow() {delete ui; } addAction 相当于选项卡 // 添加菜单栏 QMenuBar *menubarnew QMenuBar(this); setMenuBar(menubar);// qmeua 是一个文件 QMenu *filenamemenubar-addMenu(文件);// ‘文件’下面是一个选项卡 // 添加一个选项卡 // 添加一个动作 filename-addAction(新建文件); filename-addAction(打开文件); filename-addAction(关闭文件);addAction 与 信号/槽 QToolBar – QMainWindow 工具栏 一个窗体可以有多个工具栏 一个窗体只能有一个菜单栏 #include QToolBar // 工具栏QToolBar * toolbarnew 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 QLabelQStatusBar *statusburnew QStatusBar(this); setStatusBar(statusbur); // 等价于 this-setStatusBar QLabel *labelnew QLabel(this); label-setText(状态栏); // 显示文字 statusbur-addWidget(label); // 一个控件内添加一个控件 使用addwidgetQDockWidget – QMainWindow 浮动窗口浮动窗口可以有多个 位置是相对于 中心区域 的 #include QDockWidget // 浮动窗口QDockWidget *docWidgetnew QDockWidget(this); addDockWidget(Qt::LeftDockWidgetArea,docWidget); QDockWidget *docWidgetnew QDockWidget(浮动窗口,this); addDockWidget(Qt::LeftDockWidgetArea,docWidget); QTextEdit – QMainWindow 文本编辑器也可以当做中心区域中心区域通常是文本编辑器 一个窗口只能有一个中心组件 #include QTextEdit/* 中心区域 */ QTextEdit *editnew 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 filenameQFileDialog::getOpenFileName(this,open file,f:\\,tr(images(*.png *.jpg))); // tr是字体兼容性的问题 qDebug()filename;字体对话框 #include QFontDialog #include QString #include QDebugbool ok; // 标志是否选择一个字体 QFont fontQFontDialog::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 inputQInputDialog::getText(this,输入对话框,请输入用户名,QLineEdit::Normal,password,flag);if (flag){qDebug()input;}bool flag_val;int valQInputDialog::getInt(this,输入对话框,0-100,0,0,256,1,flag_val);if (flag){qDebug()val;} } QMessageBox 消息对话框 // 问题对话框 int retQMessageBox::question(this,question, // 对话框的标题ues Qt T or F, // 对话框的内容QMessageBox::Yes, // 可选择的模式QMessageBox::No); if (retQMessageBox::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 *prodlgnew QProgressDialog(this);// 栈中 局部释放 QProgressDialog prodlg(copy progress,stop,0,50000,this);// 设置模态 prodlg.setWindowModality(Qt::WindowModal); prodlg.setWindowTitle(copy file); prodlg.show();for (int i0;i50000;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 QFileint 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* strnew char[100];// 每次从文件中读取一行数据或读取最多maxSize-1个字节存储到data中// 返回读取到的字节数qint64 readNumfile.readLine(str,100);// 当读取出现错误 返回为-1或者读取到字符数为0时结束读取while ((readNum!0)(readNum!-1)){qDebug()str;readNumfile.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 i0;i5;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 resArrfile.readAll();qDebug()resArr:resArr;//将二进制转换为整数char* dataresArr.data();while(*data){qDebug()*(qint32*)data;datasizeof(qint32);}return 0; }文件操作进阶 QTextStream /*QTextStream 类 提供了很多读写文件相关方法 */ #include QFile #include QDebug #include QString #include QTextStreamint 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;// 从文件中读取一个字符串instr;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 *timernew 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 重写定时器事件 timerId1startTimer(1000); // 直接启动定时器 timerId2startTimer(1000); // 直接启动定时器// 对应version1 信号和槽函数 void Widget::change_labelValue(void) {static int var1;ui-label_3-setText(QString::number(var)); }// 重写定时器事件 int timerId1; int timerId2;// version2 重写定时器事件 timerId1startTimer(1000); // 直接启动定时器 timerId2startTimer(1000); // 直接启动定时器// 对应version2 定时器事件 void Widget::timerEvent(QTimerEvent *event) {// version1 // static int num1; // ui-label_4-setText(QString::number(num));// version2if (event-timerId()timerId1){static int num11;ui-label_3-setText(QString::number(num1));}else if (event-timerId()timerId2){static int num22;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);angle0;// 创建定时器QTimer *timernew 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);// 更新angleangle10;if (angle360) angle0;// 抗锯齿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.272度逐渐变为Qt::cyanconicalGradient.setColorAt(0.4,Qt::black); // 设置渐变色 0-1 从72度到7272度逐渐变为黑色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 QPixmapQImageQBitmapQPicture 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); //在00点起始的宽高均为50的句型中显示图片painter.translate(50,50); //将起始点改为5050painter.drawPixmap(0,0,50,50,pix); //在5050起始的宽高为50的矩形中显示图片 }QLabel/QPixmap QPixmap pix(/path); QLabel label; label.setPixmap(pix); label.show();QPixmap/QImage 通常QImage 类用于加载图像文件并操作图像数据。然后将 QImage 对象转成 QPixmap 对象在屏幕上显示 QImage -- QPixmap QPixmap::fromImageQPixmap -- QImage QPixmap::toImageQPixmap/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 i50;i100;i){for (int j50;j100;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 QHostAddressQUdpSocket* 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_portui-targetPort-text().toInt();sendBuffui-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: \nsendBuff); }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 QTcpSocketQTcpServer *tcpServer; tcpServer new QTcpServer(this); tcpServer-listen(QHostAddress::Any,6666)//连接信号和相应槽函数,有新的连接进入是需处理 // 有新的连接接过来会触发newConnection()信号函数触发槽函数NewConnection() connect(tcpServer,SIGNAL(newConnection()),this,SLOT(NewConnection())); // 信号与槽函数// 槽函数 void Widget::NewConnection() {//初始化为0;//blockSize0;// inBlock.resize(0);//新连接进入的显示处理// 取出连接号的套接字currentClient tcpServer-nextPendingConnection();// QString iptcpsocket-peerAddress().toString();//获取连接的 ip地址// quint16 porttcpsocket-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 imagereader.read()imageimage.scaled() setPixmap(QPixmap::fromImage(image))安装问题 https://blog.csdn.net/qimo601/article/details/120197947 https://blog.csdn.net/husky66/article/details/117221693 !!! --这个无敌了
http://www.dnsts.com.cn/news/2947.html

相关文章:

  • 网站建设哪家售后做的好百度网盘下载app
  • 丰城住房和城乡建设部网站搜狗网
  • 企业网站建设基本流程百度应用平台
  • 网站后台有安全狗新平台推广
  • 网站开发样板百度资源分享网页
  • 公司向要做一个网站要怎么做常用的搜索引擎
  • 政府网站建设要点公司软文怎么写
  • 天津大寺网站建设如何自己开发一个网站
  • Javascript做网站cms快速建站
  • 360免费建站域名自动引流免费app
  • 做网站的职业规划网站建设服务公司
  • 本地用织梦做网站百度广告点击一次多少钱
  • 秒玩大型游戏的网站企业产品推广运营公司
  • 高端网站建设企业官网建设台州网站建设
  • java做音乐网站网页设计怎么做
  • php网站建设安装环境培训行业seo整站优化
  • 广州自助建站谷歌seo关键词优化
  • wordpress 在线购物关键词排名优化公司哪家强
  • wordpress ftp连接不上品牌关键词优化哪家便宜
  • 静态页面做网站百度一下官方网页
  • 怎么能看出别人的网站是哪一家做短视频推广渠道
  • 怎样把网站做有排名靠前上海网站建设哪家好
  • 小学网站建设实施方案品牌宣传的推广
  • 任务接单平台seo 网站排名
  • 做网站的资源有哪些网站建设平台哪家好
  • 网站建设要些什么网络推广公司如何做
  • 建设个网站从哪里盈利seo推广软件排名
  • asp.net 网站的头部和底部怎么来做 include中国seo关键词优化工具
  • 学做沪江网站要多久网站排名优化需要多久
  • 公司网站如何维护谷歌google浏览器官方下载