我是靠谱客的博主 羞涩哈密瓜,最近开发中收集的这篇文章主要介绍Qt基础知识大全Mouse Release(%1,%2)Mouse Move(%1,%2)Mouse is enterMouse is leave告诉 qmake 这是哪种项目,由于构建的是一个应用程序,因此使用 app 模板声明了要从 C++ 使用的 Qt 库构建项目需要一个 C++11 兼容的编译器列出了应该编译的所有源文件,类似的变量 HEADERS 可用于头文件。告诉 qmake 有一个资源集合,应该被内置到可执行文件中。,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

本文章记录着我学Qt几个月来的笔记,其中包括着控件的使用,样式表,绘图事件, 其他事件,Gstreamer等!还有很多东西,如果有问题的地方,希望大家可以评论告诉我,或者私信也可以,大家一起进步,谢谢啦!转载请标明连接!_
笔记多来源与书籍以及广大互联网大神,以及自己理解的知识点。

  1. qt文件最好没有中文路径
    Qt库(qt-4.8.6): qt-opensource-windows-x86-mingw482-4.8.6-1.exe
    编译器(Mingw): i686-4.8.2-release-posix-dwarf-rt_v3-rev3
    调试器(gdb): qtcreator-gdb-7.4-MINGW32_NT-6.1-i686.tar.gz — 这个不重要
    qtcreator : qt-creator-opensource-windows-x86-3.0.0.exe

    QT框架约等于MFC QT Creator约等于VC++ QT SDK约等于VS

  2. 快捷键 Ctrl+R 直接运行

  3. QApplication 用于管理应用程序的资源 - 任何一个Qt widget程序都要有一个QAppllication 类对象
    return a.exec(); 事件循环。
    单词代码快速补全:
    将鼠标指针放到一个类名或函数上,按 F1 键 可以快速进入帮助文档;
    greaterThan(QT_MAJOR_VERSION.4):QT += widgets 这句话的用途是兼容更高级版本用的!如果QT主版本大于4也就是
    说当前使用的是QT5或者更高版本,则需要添加widgets模块
    QObject::tr(“”) 这么用 不乱码!

  4. 继承关系
    QWidget 继承自QObject类 和 QPaintDevice类
    QObject 类是所有支持Qt对象模型(Qt Object Model)对象的基类,QPaintDevice类是所有可以绘制对象的基类

  5. #include 包含很多常用的模块

  6. 在qt中 用delete销毁父对象时会自动销毁自对象,例如用new 建立了一个标签A,如果在建立一个标签B,B将其父对象
    设置为A,则在销毁A的同时,B将被一起销毁。

  7. Qt 中把没有嵌入到其他部件中的部件称为窗口,一般窗口都是有边框和标题栏
    窗口就是没有父部件的部件,所以又称为顶级部件。与其相对的是非窗口部件,又称为子部件(嵌入到其他部件或窗口中)
    – 这些都是相对而言的没有绝对的一说!

  8. 程序调试

  9. 当创建一个需要放进某个布局中的窗口部件时,就没有必要为其显示的指定父对象了

  10. 对于所有定义了信号和槽的类,在类定义了信号和槽的类,在类定义开始处的 Q_OBJECT 宏都是必须的。

  11. 自定义信号时,需要 使用 signals: 访问限定符修饰一下,如同public什么的那个
    自定义槽时候,需要用 public - protectd - private 等修饰 slots : private slots:
    signals 与 slots关键字实际上是一个宏,c++预处理器会在编译程序找到它之前把它转换成标准c++代码;

  12. 代码
    find_label = new QLabel(tr(“Find &what”)); 设置快捷键
    line = new QLineEdit();
    find_label->setBuddy(line); 设置伙伴:所谓伙伴,就是一个窗口部件,它可以在按下标签的快捷键
    时接受焦点,所以当按下 Alt + W 时,焦点就会移动到这个行编辑器上

  13. 加如小弹簧 空间:
    layout->addStretch(); 拉伸,延伸
    setFixedHeight(sizeHint().height()); 设置 固定长度
    QWidget::sizeHint() 函数可以返回一个窗口部件所“理想" 的尺寸大小界面

  14. 信号和槽机制是qt编程的基础,它可以让应用程序编程人员把这些互不了解的对象绑定在一起。
    槽和普通的C++ 函数没有区别 - 可以是虚函数;可以被重载 - 可以是公有的,保护的或者私有的 - 也可以被其他c++
    成员函数直接调用,参数可以是任意的!唯一的区别:槽可以和信号连接在一起,在这种情况下,每当发射这个信号时
    就会调用这个槽;
    一个信号可以连接多个槽
    多个信号可以连接同一个槽
    一个信号可以与另外一个信号相连接
    connect(lineEdit,SIGNAL(textChanged(const QString &)),this SIGNAL(updateRecord(const QString &)));
    连接可以被移除
    disconnect(lcd,SIGNAL(overflow()),this,SLOT(handleMathError()));
    当删除对象时,Qt会自动删除和这个对象相关的所以连接。
    要把信号成功连接到槽(或者连接到另一个信号),他们的参数必须具有相同的顺序和相同的类型
    例外:当信号的参数比他所连接的槽的参数多,那么多余的参数将会被简单地忽略掉
    信号也是发送出去的 关键字:emit 发射signals函数

  15. 改变形状的对话框
    扩展对话框
    多页对话框

  16. 帮助文档:
    目录模式:
    在编辑里可以改模式

  17. 欢迎:
    项目:Qwidget 窗口部件的形式 所见及所得;在UI编辑器中拖进去 什么样,它就是什么样的
    Qt Console 终端的形式
    Qt Quick application 网站的形式 - CSS+DIV hml可以 用它写

  18. 项目文件:其中的
    QT += GUI; 这是将GUI 模块加载进来,在这个模块中又存在着很多的函数封装,例如 widget 等,然后就可以直接去调
    用啦!

  19. 快捷键: shift + table 格式化
    编码区名字显示 * 号; 意思是未保存

  20. 设计:对可视化界面的设计(Ui)

  21. gdb 调试:命令调试
    Debug 调试 断点 F9 调试
    调试模式:
    应用程序栏 可以关闭程序
    构建哪里更改的!
    发布版:relese 小 - 这个不包含调试信息 这个可以跑了
    调试版:Debug 大 - 这个是自己电脑上调试用的(包含调试信息)
    qmake g++
    qt code-----> c++ code— > a.out

    																qt中控件(部件)学习
    
  22. QLable 标签
    QLabel label;
    QLabel *label = new QLabel;
    QLabel *label = new QLabel(); – 有三个构造函数
    delete label; – 释放掉内存
    其成员函数先有(每个函数都有重载的函数,以下显示为常用的函数)
    lable -> setWindowTitle(“字符串”); 设计标题
    label -> setText(“字符串”); 设计文字内容
    label -> show(); 显示窗口函数
    label -> resize(宽,高); 标签窗口的大小
    label -> move(宽位置,高位置); 相对于其父对象(或电脑窗口)的偏移位置

  23. QWidget 窗口
    QWidget widget;
    QWidget *widget = new QWidget;
    QWidget *widget = new QWidget(QWidget *parent = 0 , Qt :: WindowFlags f = 0);
    parent 指的是父窗口部件,默认值为0,表示没有父窗口
    f 参数是Qt::WindowFlags类型,是Qt :: windowType枚举类型值的或组合.Qt::windowType 包含了很多类型
    例子:
    QWidget *widget = new QWidget(0 , Qt::Dialog); 将窗口类型改成对话框的形式
    Qlabel *label = new QWidget(0 , Qt::splashScreen); 可以看出窗口
    QWidget *widget = new QWidget(0,Qt::Dialog | Qt::FramelessWindowHint);
    QLabel *lable = new QLable(0 , Qt::splashScreen | Qt :: windowStaysOnTopHint);
    Qt::FramelessWindowHint 用来产生无边框效果
    Qt :: windowStaysOnTopHint 用来使该窗口停留在所在其他窗口的上面
    想要知道更多的设置:可以 索引 Qt::WindowFlags 关键字,查看更多的设置
    widget函数
    widget . setWindowState()函数用来设置窗口的状态;
    Qt::WindowMaximized() 最大化
    Qt::WindowMinimized() 最小化
    Qt::WindowFullScreen 全屏显示
    Qt::WindowActive 活动窗口

  24. QDialog 对话框 模态对话框 非模态对话框
    模态对话框就是在没有关闭它之前,不能再与同一个应用程序的其它窗口进行交互,比如新建项目时弹出的对话框。 阻塞式
    对话框.exec(); 函数 就能使窗口变成为莫态的
    QDialog dialog(this);
    dialog.exec();
    非模态对话框,即可以与它交互,也可以与同一个程序中其它窗口交互 非阻塞式
    QDialog *dialog = new QDialog(this);
    // dialoh -> setModal(); 就可以将它从非模态对话框转化为模态的对话框
    dialog -> show();

  25. 指定父对象两种方法:
    setParent();
    构造函数

  26. C++ 在构造函数中 创建的对象,出了构造函数,其类型也将会不见了的,因为其作用域就函数那么大而已,所以在构造
    函数中创建的部件,在主函数中就不见了的!

  27. 按钮 QPushButton

-------------------------------------------------------------
object 								对象  目标
enable 								启动  允许操作
geometry 						几何学 几何结构
sizePolicy							控件的默认布局的行为
minimumSize  					最小尺寸
maximumSize					最大尺寸
sizeIncrement					控件尺寸变化时候的步进尺寸
baseSize							基本尺寸		
font									字体
cursor								光标
mouseTracking      			鼠标跟踪
tabletTracking
focusPolicy						中心方针
toolTip								提示信息
toolTipDuration				控件的提示时间
statusTip							状态信息		
whatsThis							这是什么
accessibleDescription		说明
accessibleName				名称
layoutDirection			    布局的方向
autoFillBackground			自动填充背景色
styleSheet						样式表
locale								区域设置
inputMethodHints			控件的输入模式的提示
QAbstarctButton			    抽象的按钮
text									文本
icon									图标	图像
iconSize							图标大小	
shortcut							捷径
checkable						可用支票付款的
autoRepeat						自动重复
autoRepeatDelay				自动重复延迟
autoRepeat						自动重复间隔
autoDefault						自动默认
default								默认
flat									平的单调的

Button 								按钮类
radio button						单选框
check box							复选框 / 多选框
command link button		命令连接按钮
dialog button box				对话框按钮盒

Display Widgets				显示小部件
-------------------------------------------------------------
label									标签
text browser						文本游览器
graphics view					图形视图
LCD Number					液晶显示数字
prograss Bar						进度条
Horizontal line					水平线
vertical line						垂直线
openGL widget					开放图形语言
QQuickWidget					核心窗口

Input Widget						输入框
--------------------------------------------------------------
Combo Box						组合框
Font	Combo Box				字体组合框
Line Edit							行编辑
Text Edit							文本编辑器
Plain Text Edit					纯文本编辑
Spin Box							选值框
Double spin Box				双选值框
Time	Edit						时间编辑
Date	Edit							日期编辑
Date/Time	Edit				时间/日期 编辑
Dial									转盘
Horizontal Scroll Bar		水平滚动条
Vertical Scroll Bar			垂直滚动条
Horizontal Slider				水平滑块
Vertical Slider					垂直滑块
Key Sequence Edit			键序列排序
  1. 信号和槽
    槽:说白了就是个函数(对于命令的封装)
    一般在Qt4 中要定义为
    public slots; 但在Qt5中就没有这么多说道了,可以直接在public中 去运行
    Alt + Enter键 快速的根据 函数声明写出函数的定义;

第二讲:登录界面
按钮:
property edit 属性编辑器
echoMode 转换输入框的模式
设计师界面的组件都放在了 ui 那里了;
ui -> line_passwd -> setEchoMode(Qline::EchoMode);
再设计师中去 将部件 转化为 槽的时候,系统自己给你绑定什么的了! 所以你不需要写connect了
逻辑一般就在 槽函数中写
类名 即为头文件名
在C++中可以在类中创建 类类型的对象,然后还可以在类类型的对象中,去创建类类型的对象,依次类推

第三讲:登录界面手写编译
从生成 C++ 的代码开始学习
QPushButton *button =new QPushButton(this);
button -> setGeometry(); 设置几何:起始点(x,y)x和y的长度编写
部件水平和垂直方向的居中公式: (框体长 - 部件长)%2 (框体宽 - 部件宽)%2

第三讲:手动编译过程
1.生成解决方案
qmake - project
解决方案中添加(需要该模块):
QT += widgets
2.生成Makefile文件
qmake
3.生成最终可执行程勋

第三讲:手动编写信号与槽signal slots
产生者:按钮
绑定:connect函数
接受者:可以为当前对象 槽去处理
signal 没有 private和public等修饰

private slots:
	// 处理单击求值(槽:专门处理信号的特殊函数)
 
 QObject::connect(发送者为指针类型, SIGNAL(信号), 		this,SLOT() );
  
 将字符串转换为其他的类型;  
 字符串变量名.toInt();  -> 转化为 整形
 字符串变量名.toDouble();  -> 转化为浮点
 将数字转化为字符串
 QString::number(整形变量名);
	
获取 : get函数名		或者直接为		函数名
设置 : set函数名
insert 插入,嵌入

QString 构造函数
append() 拼接函数
arg 字符串格式化拼接
contains 包含某个字符串
cout() 字符串函数
replace 查找替换
split 分割字符串
QString::number (); 	把数字类型转化为字符串类型

第四讲:计算器的初步讲解

第五讲:计算器
在UI中创建对象时,最好应该先将对象的 名字更改在转到槽,如果先转到槽再更改对象,可能会造成未连接的问题。

connect(&b1,&QPushButton:pressed,this,&MainWidget::close);		qt5
&b1: 信号发出者,指针类型
&QPushButton:pressed : 处理的信号
this :信号接受者
&MainWidget::close:槽函数,信号处理函数

connect(&b1,SIGNAL(pressde()),this,SLOT(close));			qt4

QObject::connect(&b1,SIGNAL(pressed()),this,SLOT(close()));
connect(&b1,SIGNAL(pressed()),this,SLOT(close()));

&b1:信号发出者 指针类型	    会发出很多信号
&QPushButton::pressed() : 处理的信号				只接受这个信号
this:信号接受者
&MainWidget::close()): 槽函数(信号处理函数)
信号 与 槽 : 都有自定义的方法
connect(&b1,&QPushButton::pressed(),this,&MainWidget::close());	qt4 这种是错误的!
槽函数需要和信号一致(参数,返回值)

第五讲:对QLable 的使用

QtextEdit
第一种文本形式赋值
ui -> textedit-> setText("asdddddddddddd");
第二种 html 格式赋值
ui -> textEdit -> setHtml("<strong>222222222</strong>");
获取 
第一种文本形式获取其值
ui -> textEdit -> toPlainText();
qDebug() << ui -> textEdit -> toPlainText();
第二种 html 形式获取其值
ui -> textEdit -> toHtml(); 
qDebug() -> textEdit -> toHtml() ;
  
 QPuhsbutton  启动按钮的复选框  (播放器时用的比较多)
 ui -> pushButton -> setCheckable(true);

第六讲:对QLable 的使用

 QTool Batoon
 设置图标
 ui -> toolButton -> setIcon(QIcon("路径"));					设置图标
 ui -> toolButton -> setIconSize(QSize(110,100));		    设置大小
  
																		视频授课
 qt : 跨平台C++ 图形用户界面应用程序开发框架
 注意书写代码的格式规则:匈牙利,驼峰 
 window - get(Qwidget):能看到的实体  都是 从这里继承的 
 QFontDialog
 QTcpSocket
 QudpSocket
 Qstring 
 QColorDilog
 --------------------------	Qt的20%的类会被80%的使用到  --------------------------

电脑系统属性
QTableWidget	: 桌面(部件)控件 
Qlabel  :  				图片  文字
QlineEdit:			单行编辑器
QTextEdit:			多行编辑器
QPushButton:	按钮 (推出来的)     --- 继承与  QAbstractButton 抽象类
QGroupBox:		组框
<a href = "网址"> 地址 连接
QTableWidget	    表格部件		
QCheckBox		    复选框			--- 继承与  QAbstractButton 抽象类
QRadioButton	    单选框			--- 继承与  QAbstractButton 抽象类	
QSpinBOX			下拉列表框
QHBoxLayout 		horizontal	水平布局
QVBoxLayout		verticla		垂直布局

创建一个运行窗口:先创建对象,让他存在  		然后再去修改他的属性
#include <QAPplication>
#include <QLineEdit>
#include <QPushButton>
#include <QLabel>
#include <QWidget>
#include <QHBoxLayout>
#include <QVBoxLayout>

int main(int argc,char *argv[])
{
	QApplication app(argc,argv) ; 初始化应用图形程序的环境
	QLabel *infolLabel = new QLabel;
	QLabel *cmdLabel = new QLabel;
	QLIneEdit *cmdLineEdit = new QLineEdit;
	QPushButton *submittButton = new QPushButton;
	QPushButton *cancelButton = new QpushButton;
	QPushButton *browserButton = new QPushButton;
	
	infoLabel -> setText(“please input command in lineedit”);
	cmdLabel -> setText("Open");
	cmdLineEdit -> clear();			//清空
	submitButton -> setText("submit");
	cancelButton -> setText("cancel");
	browserButton -> setText("brows");
	
	QHboxLayout * cmdLayout = new QHboxlayout;
	cmdLayout -> addWidget(cmdLabel);    
	cmdLayout -> addWidget(cmdLineEdit);
	
	QHBoxLayout *buttonLayout = new QHBoxLayout;
	buttonLayout -> addWidget(submitButton);
	buttonLayout -> addWidget(cancelButton);
	buttonLayout -> addWidget(browserButton);
	
	QVBoxLayout *mainLayout = new QVBoxlayout;
	mainlayout -> addWidget(infoLabel);
	mainlayout -> addLayout(cmdLayout);
	mainlayout -> addLayout(buttonLayout);
	
	QWidfet *window = new QWidget();
	window -> setLayout(mainLay0out);
	window -> setWindowTitle("Running...");
	window -> show();
	
	return app.exec();
}

在 设计中:直接运用的
Ctrl + H		水平布局

Ctrl + L 垂直布局
更改多信息文本:可改变大小什么的
art + shif + r 是预览
spacers 占位
Ctrl +r的方法运行起来
一般程序都是固定大小的

第五讲:信号与槽、

layout 布局
-- Vertical Layout 				垂直布局
-- Horizontal Layout 	    水平布局
-- Grid Layout	 				网格布局
-- Form Layout 				基于窗口的Form 布局

spacers 空间
-- Horizontol Spacer			水平占用空间
-- Vertical	  SPacer			垂直占用空间

buttons 按钮
-- PushButton					按钮
-- Tool Button						
-- Radio Button		   		单选框
-- Check	Box					复选框
-- Command..k Button		命令行
-- Button Box					按钮组

iterm views ....  	 视图    								 list 列表视图   	tree 树视图    table 网格视图     column 列视图 
iterm widget  ....	 继承与(iterm views ....)	 list 列表  			tree 树   		table 网格 		    一般都有这个

containers  容器	        容纳其他布局的
 -- Group Box				能装入不同的控件
 -- Scroll Area  			    区域不够显示了  将提供滑条
 -- Tool Box  			    页的
 -- Tab widget 			    选项卡 
 -- Stacked Widget		能够更换的显示不同的控件
 -- Frame
 -- Widget
 -- MdiArea  		    可以存放很多其他的部件,可以打开多个窗口显示
 -- Dock WIdeget		停靠窗口 
 
Input Widget				输入窗口
 -- Combo Box 			    下拉列表框
 -- Font Combo Box		字体下拉框
 -- Line Edit 					行编辑器 
 -- Text Edit 					文本编辑器  复文本
 -- Plain Text Edit 			文本编辑器  纯文本 
 -- Spin Box					自旋框(微调框)
 -- Doble Spin Box 		基于浮点数的自旋框(微调框)
 -- Time Edit					时间框
 -- Data  Edit					日趋框
 -- Data/Time Edit			时间+日期框
 -- Dial 							滑框
 -- Horizont...Bar			横向滑条
 -- Verizont....Bar			竖向滑条
 -- Display Widget		也是一个滑条

Display Widget		输出/显示窗口
-- label 				标签
-- Text Browser		文档游览器
-- Graphics View	图片查看器
-- Calendar			日历
-- LCD Number		LCD显示
-- Progress Bar		进度条
-- Horizontal Line	横向分割符
-- Vertical Line		竖向分割符
-- QWebView		游览器

F4 信号与槽的编辑模式
F3 部件编辑模式

第六讲:启动一个额外的程序
#include <QProcess>		启动一个新的进程  父类:QIODevice
ui -> 就可以看成是一个 对象嘛。

void closeEvent(QCloseEvent *event);	
closeEvent() 函数是 QWidget 类中的一个虚函数,当用户关闭窗口时,这个函数被自动调用
当槽作为一个信号的相应函数被执行时,就会忽略这个返回值;但是当把槽做为函数来调用时,其返回值对我们的作用就和调用任何一个普通的
C++函数时的作用是相同的。
  1. #include
    带有 文字(字符)的 对象->setFont( QFont(“字体名”,字号大小,粗细,斜体) ); 这是将 QFont的对象 传到 setFont 函数中去了
    函数用 QFont 对象做参数
    b2 = new QPushButton(“Hello”,this); 创建一个按钮对象
    b2->setGeometry(100,110,160,80); 设置他的几何构造
    b2->setFont(QFont(“Adobe ?? Std”,20,QFont::Bold)); 设置他的字体 方式1 : 类名 + 构造函数参数 = 构造函数 直接传进去了一个构造函数
    QFont a(“Impact”,20,QFont::Bold); 先创建一个 字体对象
    b2->setFont(a); 再将对象传进去 : 这个是比较正常的

  2. label = new QLabel(this);
    label->setGeometry(200,200,180,180);
    label->setText(“this the first line n this is” 设置文字其中 可加换行符号等等。
    “the second line”);
    label->setFont(QFont(“Adobe Hebrew”,10,QFont::Bold,true)); 设置字体
    label->setAlignment(Qt::AlignLeft); 设置文字 对齐 (为左对齐)。

  3. MultiLineEdit - 多行编辑框 这个应该被取消了
    textEidt 进化为这个了

  4. 可以将多个槽连接到同一个信号,那么这些槽将一个接一个地被执行,其执行顺序是任意的
    滑块 与 lcd显示屏控件:
    建立与一般部件都相同,都是 先要有对象嘛,才能去搭积木
    QSlider *slider;
    QLCDNumber *lcd;

QSlider::QSlider ( Qt::Orientation orientation, QWidget * parent = 0 )     		 第一个参数,方向取向 , 第二个参数 父窗口
QLCDNumber::QLCDNumber ( uint numDigits, QWidget * parent = 0 )	         第一个参数 是显示的位数 用int类型写上就行,第二个参数 父窗口
																													 若为2,则最大不得超过9,若为3,则不得超过99。

/ ------------------------------------------------------ 程序:QSlider 和 QLCDNumber ------------------------------------------------------ /
b1 = new QPushButton("Quit",this);
b1->setGeometry(10,10,80,40);
b1->setFont(QFont("MBeiHK",20,QFont::bold,true));	//设置字体  字体 大小  粗细  斜不斜

lcd = new QLCDNumber(2,this);									//创建 显示屏 对象
lcd->setGeometry(100,10,190,180);							//这个控件都会存在,因为他们继承与 QWidget

slider = new QSlider(Qt::Vertical,this);							//创建滑块对象 对象的方向为竖直的方向
slider->setGeometry(10,60,80,130);						

connect(b1,SIGNAL(clicked()),this,SLOT(close()));		
connect(slider,SIGNAL(valueChanged(int)),					//改变滑块的值,其显示会跟着发生变化,int值在两个函数之间传递
        lcd,SLOT(display(int)));

/ ------------------------------------------------------ 程序:Qpushbutton 和 QlineEdit ------------------------------------------------------ /  
b1 = new QPushButton("Click here to mark the text",this);
b1->setGeometry(10,10,280,40);
b1->setFont(QFont("CHeiHKS",12,QFont::Bold,true));

b2 = new QPushButton("Click here to unmark the text",this);
b2->setGeometry(10,60,280,40);
b2->setFont(QFont("CHeiHKS",12,QFont::Bold,true));

b3 = new QPushButton("Click here to remo the text",this);
b3->setGeometry(10,110,280,40);
b3->setFont(QFont("CHeiHKS",12,QFont::Bold,true));

line = new QLineEdit("this is a line of text",this);			   //创建 单行编辑对象,其中有文字
line->setGeometry(10,160,280,30);

connect(b1,SIGNAL(clicked()),line,SLOT(selectAll()));	   //点击按钮1 实现全选文字功能呢
connect(b2,SIGNAL(clicked()),line,SLOT(deselect()));	   //点击按钮2 实现取消选择功能呢
connect(b3,SIGNAL(clicked()),line,SLOT(clear()));  		   //点击按钮3 实现清除工作
  1. 元对象编译器,创建用户和槽
    C++ 编译器不能理解 信号与槽的语句,因此完成这项工作必须使用特殊的工具,即元对象编译器(Meta OBject Compiler , MOC ) , 这一工具扫描源文
    件中用于创建信号和槽的特殊语句
创建槽:
在类定义中,写上成员函数
public slots:						// 将这行所有的函数看做槽(直到类声明结束或是另一部分开始 如 private :)
MyExitSlot();						// 定义槽函数
然后在函数定义中,与普通函数书写一样:
类名 :: MyExitSlot()	{	exit(0);	}

创建信号:
signals:					// 这个一下是 声明信号的地方
								--------------------------- 未知

信号和槽的有趣功能:
(1)避免不必要的信息
connect(slider,SIGNAL(valueChanged(int)) , lcd , SLOT(display(int)));
connect( togglebutton , SIGNAL(toggled(bool)) , anotherobject , SLOT(aslot())); 			在定义槽的中省略相应的参数
(2)信号和信号之间的连接
connect( button ,SIGNAL( clicked() ) , SIGNAL ( anothersignal ())) ;						  		当 button 信号被激活 , 后者的信号也将被激活
(3)断开槽和信号之间的 或者 信号和信号之间的 连接
connect(button ,SIGNAL( clicked() ) , this ,SLOT( quit() ));			建立连接
disconnect ( button ,SIGNAL( clicked() ) , this ,SLOT( quit() ) );	在其后添加这个代码,将断开连接
(4)使用 connect() 函数时省略对象名称
connect() 函数的这个功能能够减少击键次数 , 如果将信号连接到当前所定义类中的槽时,可以省略拥有该槽的对象名称。
connect(button ,SIGNAL( clicked() ) ,SLOT( quit() ));						就是这种,没有加 this 对象的!

如果编译器报告未找到 connect()函数:这种调用必须在一个 QObject 派生类的方法内。如果从一个外部函数中调用,则必须向下面这样调用
QObject::connect();
  1. Qt 构造块
滚动条:能够在屏幕上显示区域非常大的应用程序。使用滚动条,能够使用户更加容易使用应用程序(无视 分辨率的大小)
实现滚动条功能最简单的方法是将主部件(主窗口) 基于 QScrollView 类。之后在为每个子窗口调用 QScrollView :: addChild() 函数
就能自动创建一个按需滚动窗口:即只有 当窗口无法在原来尺寸下显示所以子部件时它才添加滚动条,但是当不需要滚动条时,将不会显示
滚动条。		----------------------------- 未知
  1. 菜单类
    QMenuBar 菜单条
    QPopupMenu 单个菜单条(弹出菜单)
    ----------------------------- 未知
工具栏:
直接调用QMainWindow类的addToolBar()函数获取主窗口的工具条对象,每增加一个工具条都需要调用一次该函数。
插入属于工具条的动作,即在工具条上添加操作。 
通过QToolBar类的addAction函数添加。
工具条是一个可移动的窗口,它的停靠区域由QToolBar的allowAreas决定,包括: 
Qt::LeftToolBarArea 停靠在左侧
Qt::RightToolBarArea 停靠在右侧
Qt::TopToolBarArea 停靠在顶部
Qt::BottomToolBarArea 停靠在底部
Qt::AllToolBarAreas 以上四个位置都可停靠 
使用setAllowedAreas()函数指定停靠区域:

setAllowedAreas(Qt::LeftToolBarArea | Qt::RightToolBarArea)				设置工具栏的停靠位置
使用setMoveable()函数设定工具栏的可移动性:
setMoveable(false)//工具条不可移动, 只能停靠在初始化的位置上

状态栏:
  1. 使用QMainWindow 部件
    QMainWindow (主窗口) 中封装着 菜单栏 工具栏 中心组件 状态栏 停靠窗口
    菜单栏:MenuBar
    工具栏:ToolBar
    停靠窗口:DockWidget
    状态栏:StatusBar
    中央窗口:Central Widget
菜单栏:QMenuBar		- 下拉菜单组 QMenu   	    -- 菜单项 QAction
创建菜单;
QMenuBar  *mb = menuBar();								// 菜单栏被封装在主窗口中,如果建立了窗口,就可以直接调用成员函数获得菜单栏对象
QMenu  *menu = new QMenu(" File(&F) ");			// 创建一个下拉菜单组
QAction *action = new QAction( "Print",NULL );	// 创建一个菜单项 , 第二个参数是指定父组件
menu -> addAction(action);									// 往下拉菜单组中添加菜单项
mb -> addMenu( menu );										// 往菜单栏中添加菜单

为菜单栏设置快捷键
action -> setShortcut( QKeySequence(KEY ));			setShortcut 函数 是 QAction类里面的函数
为下拉菜单组设置分割线
menu -> addSeparator( ) ;											分割菜单项

注意::::::::::
QMenu *m1 = new QMenu("one",mb);						这个直接将它的父类设置为菜单栏是不行的,必须用下面 那个方法
QMenu *m2 = new QMenu("two",mb);	
与
mb -> addMenu(m1);
mb -> addMenu(m2);
是不一样的哦

QMenuBar *mb = this->menuBar();							一般这么弄最好:这是通过QMainWindow类的menuBar()函数 获取主窗口菜单栏指针
QMenuBar *mb = new QMenuBar(this);					这么弄以后 会出现奇怪的问题:他的下面 空白 会漏出来
这两个经过实验得出 也是不一样的哦!

/ ------------------------------------------------------ 程序:QMainWindow : Menu------------------------------------------------------ /  
#include<QMenuBar>
#include<Qmenu>
#include<QAction>
QMenuBar *mb = menuBar();													// 创建菜单栏
mb->setFont(QFont("CHeiHKS",25,QFont::Bold,true));				// 可以对菜单栏设置字体,这么弄以后 菜单栏的主菜单名都会变名字
QMenu *m1 = new QMenu("file");											// 添加菜单
//mb->addSeparator();
m1->setFont(QFont("CHeiHKS",25,QFont::Bold,true));				// 设置菜单的字体属性
QMenu *m2 = new QMenu("open");

QAction *a1 = new QAction("text1",0);
QAction *a2 = new QAction("text2",0);

mb->addMenu(m1);
m1->addSeparator();
mb->addMenu(m2);

m1->addAction(a1);
m1->addSeparator();
m1->addAction(a2);
m2->addAction(a2);
  1. 在主窗口中创建工具栏
    QToolBar *tb = addToolBar(“Tool Bar”);
    QAction action = new QAction("",NULL);
    action -> setToolTip(“Open”); // 设置提示信息
    action -> setIcon( QIcon(“路径”) ) ; // 设置图标,使用的是资源文件
    tb -> addAction(action);
QToolBar的三个重要函数 
void setFloatable(bool floatable); 
设置工具栏是否可以作为一个独立的窗口进行拖动到任意位置悬浮 
void setMovable(bool movable); 
设置工具栏是否可以被拖动到其他工具栏区域 
void setIconSize(const QSize& iconSize); 
设置图标大小

注意:QToolBar 可以添加任意QWidget组件

/ ------------------------------------------------------ 程序:QMainWindow : QToolBar ------------------------------------------------------ /  
#include <QToolBar>
#include <QAction>
QAction *ac5 = new QAction("text5",0);								// 创建动作 即是工具栏的项目
QToolBar *to1 = addToolBar("tool_a");								    // 创建工具栏1
QToolBar *to2 = addToolBar("tool_b");								    // 创建工具栏2
to1->addAction(ac5);															// 加载到工具栏中
QPushButton *b1 = new QPushButton("hello",this);
to1->addWidget(b1);															// 将按钮部件加载到工具栏中
QLineEdit *li1 = new QLineEdit("hello world",this);			
to1->addWidget(li1);															// 将 行编辑 部件加载到工具栏中

to2->setAllowedAreas(Qt::LeftToolBarArea);
to2->addAction(ac5);        // 这个是可以的							// 可以将同一个动作 分配给两个 工具栏
//to2->addWidget(b1);       这两个是不行的						// 不可以将一个部件 分配给两个 工具栏
//to2->addWidget(li);
QPushButton *b2 = new QPushButton("hello",this);

to2->addWidget(b2);
QLineEdit *li2 = new QLineEdit("hello world",this);
to2->addWidget(li2);
to2->setMovable(true);														// 设置是否可以停靠
to2->setFont(QFont("CHeiHKS",13,QFont::Bold,true));		// 设置工具栏中出现的 文字的字体 		QFont 类是霸道的
  1. 状态栏
    状态栏是应用程序中输出简要信息的区域
    状态栏一般位于主窗口的最底部
    QStatusBar是容器类型组件
    状态栏中的显示消息类型:
    实时消息,如:当前程序状态
    永久消息,如:程序版本号,机构名称等
    进度消息,如:进度条提示,百分比提示等

    注意:状态栏QStatusBar是一个容器类,可以往里面添加任意的QWidget组件,如QLabel、QLineEdit、QPushButton等等。
    通过函数statusBar()可以直接生成一个指向状态栏的指针。
    通过函数addWidget()和函数addPermanentWidget()可以往状态栏中添加组件,但是添加的组件应该符合Qt状态栏内置的设计原则。
    Qt状态栏内置的设计原则:
    左边的区域用于输出实时消息
    右边的区域用于设置永久消息

    addWidget在状态栏左半部分添加组件
    addPermanentWidget在状态栏右半部分添加组件
    QStatusBar* sb = statusBar();//获取状态栏
    QLabel* l = new QLabel("Label");
    QLineEdit* e = new QLineEdit();
    QPushButton* b = new QPushButton("Button");
    
    sb->addWidget(l);//组件放状态栏左边部分
    sb->addPermanentWidget(e);//放状态栏右边部分
    sb->addPermanentWidget(b);
    
    windowFlags 窗口标志
    

    / ------------------------------------------------------ 程序:QMainWindow : QStatusBar ------------------------------------------------------ /
    #include
    QStatusBar *stu = statusBar();
    QPushButton *b3 = new QPushButton(“dabuguowo”);
    QLabel *l1 = new QLabel(“label1”,this,0);
    QLineEdit *li3 = new QLineEdit(“hello kiti”,this);
    stu->addWidget(b3,1); // 添加部件并非永久的
    stu->addWidget(l1,1); // 添加部件
    stu->addPermanentWidget(li3,1); // 添加部件为永久性的

  2. 中心窗口部件
    Qt程序中的主窗口通常具有一个中心窗口部件。从理论上来讲,任何继承自QWidget的类的派生类的实例,都可以作为中心窗口部件使用。
    QMainWindow的中心区域可以被任意种类的窗口部件所占用。下面给出的是可能的情形。
    常见情形:
    – 使用标准的Qt窗口部件(Standard Widget)
    像QWidget、Qlabel以及QTextEdit等等这样的标准窗口部件都可以用作中心窗口部件。
    – 使用自定义窗口部件(User-Define-Widget)
    有时候,某些有特殊要求的应用程序需要在自定义窗口部件中显示数据,你可以把自定义的窗口部件作为中心窗口部件。例如,你的绘
    图编辑器程序程序就可以使用类似名为PhotoEditor的自定义窗口部件作为自己的中心窗口部件。
    – 使用一个带布局管理器的普通Widget
    有时候,应用程序的中央区域会被许多窗口部件所占用。这时就可以通过使用一个作为所有这些其他窗口部件父对象的QWidget,以
    及通过使用布局管理器管理这些子窗口部件的大小和位置来完成这一特殊情况。
    – 使用切分窗口(QSplitter)
    其实,这种情况是上一种情况的一个例子。多个窗口部件一起使用的另一种方法是使用QSplitter。我们把QSplitter作为一个容器,在其
    中容纳其它的窗口部件,这时的中心窗口部件就是一个QSplitter。QSplitter会在水平方向或者竖直方向上排列它的子窗口部件,用户可以
    利用切分条(splitter handle)控制他们的尺寸大小。切分窗口可以包含所有类型的窗口部件,包括其他切分窗口。
    – 使用多文档界面工作空间(QMdiArea)
    如果应用程序使用的是多文档界面,那么它的中心区域就会被QMdiArea窗口部件所占据,并且每个多文档界面窗口都是它的一个子窗口界面。
    QMdiArea是在Qt4.3以后引入的一个支持多文档应用的类。
    – 使用工作空间部件(QWorkspace)
    这种情况通常用于多文档应用程序中,这时应用程序主窗口的中心部件是一个QWorkspace部件或者它的子类化部件。但这种方法在Qt4.5以后
    将被废弃。后面我们还会讲到它。

    void QMainWindow::setCentralWidget ( QWidget * widget );		QMainWindow  中本来就存在的
    QTextEdit * text;
    text = new QTextEdit(this);
    this->setCentralWidget(text);													//将文本编辑器加进去()
    

    / ------------------------------------------------------ 程序:QMainWindow : QStatusBar ------------------------------------------------------ /
    QSlider *slider = new QSlider(Qt::Horizontal,this); // 设置滑块 横向的
    this->setCentralWidget(slider); // 将滑块作为 中心 部件
    QStatusBar *stu = statusBar();
    QLCDNumber *lcd = new QLCDNumber(2,0);
    stu->addWidget(lcd,1); // 将LCD显示屏放入 状态栏中
    connect(slider,SIGNAL(valueChanged(int)),lcd,SLOT(display(int)));

  3. 浮动窗口
    QDockWidget *dock=new QDockWidget(this); 创建浮动窗口
    addDockWidget(Qt::LeftDockWidgetArea,dock);

    //给浮动窗口添加控件
    QTextEdit *tEdit1=new QTextEdit(this);
    dock->setWidget(tEdit1); 设置浮动窗口进去,这是设置不是添加哦!

    / ------------------------------------------------------ 程序:QMainWindow : QDockWidget------------------------------------------------------ /
    #include
    #include
    QDockWidget *dock = new QDockWidget(“hello”,this); // 创建浮动窗口类
    addDockWidget(Qt::LeftDockWidgetArea,dock); // 为主窗口添加浮动窗口
    QTextEdit *text = new QTextEdit(“write???”);
    dock->setWidget(text); // 设置窗口

    / ------------------------------------------------------ warning ------------------------------------------------------ /
    注意:
    工具栏:可以做容器,也可以加QAction对象
    状态栏:必须做容器使用,要不无意义
    中心窗口部件:必须做容器使用,要不无意义
    浮动窗口:必须做容器使用,要不无意义
    菜单栏及其菜单项:不能做容器
    加入到容器中的部件,所有用法与正常时是一样的!

  4. Qt中为按钮、标签添加图片的几种方法
    – 使用 QIcon 类
    QIcon icon;
    icon.addFile(tr ( "res/icon/wall.png " ) );
    按钮对象或标签对象 . seticon( icon );

    – 使用 QPixmap 和 QBitmap类
    QPixmap icon1(tr ( "res/icon/wall.png " ) );
    按钮对象或标签对象 . seticon( icon );
    按钮对象或标签对象 . setFixedSize(icon1.size());

    – 使用样式表
    ui->toolButton->setStyleSheet(tr(“background-image: url(:/icon/res/icon/wall.png);”));
    这里需要注意相对路径的问题。将res文件夹放置在程序目录下,然后添加如下代码,设置工作路径到程序目录:
    QDir::setCurrent(QCoreApplication::applicationDirPath());

    注意:本电脑显示 分辨率为 1920 * 1080
    则他的 一半就是 960 * 540

    增加资源文件的方法:
    项目文件 -> 右击 -> Add New -> Qt -> Qt Resourse File -> 命名 -> Location -> 下一步 -> 完成
    -> 添加前缀 (可以更改名字的)
    -> 添加文件 (可能会提示没有在资源文件的子目录中,所以应该将图片复制到程序的目录中)

    / ------------------------------------------------------ QPixmap + QIcon ------------------------------------------------------ /
    b1 = new QPushButton(“hello”,this);
    b1->setGeometry(50,50,300,100);
    b1->setDefault(true); // 设置 按钮为默认的 回车键启动 按钮
    //QPixmap pixmap(":/file1/button_8.png"); // 创建 象图 对象
    QIcon icon(":/file1/skill_icon_fire_airborne.png"); // 创建 图标对象 其路径为 资源文件中显示的路径
    b1->setIcon(icon); // 设置 象图图标

    label = new QLabel(“haha”,this);
    label->setGeometry(50,200,100,100);

    QPixmap pixmap2(":/file1/skill_icon_fire_airborne.png"); // 创建 象图 对象
    pixmap2 = pixmap2.scaled(label->width(),label->height()); // 根据 标签大小去设置象图的图像大小 scale 比例
    //label->setPixmap(pixmap); // 去直 接为标签设置象图
    label->setPixmap(pixmap2); // 为标 签设置象图
    connect(b1,SIGNAL(clicked()),this,SLOT(close()));

    注意:在 QPushButton 中 只有 setIcon(); 函数
    在 QLabel 中只有 setPixmap(); 函数

  5. 按钮
    按钮:QPushButton 常用与产生事件
    单选按钮:Radio Button 常用与做一些选择 只能是一种的选择
    复选按钮:Check Button 常用与做一些选择 例如文本编辑器的样式表等

    QPushButton :: setDefault() 函数
    应用这个函数 的按钮将变为默认按钮 - 即用户按回车键时将点击的按钮

    / ------------------------------------------------------ QRadioButton + QGroupBox ------------------------------------------------------ /
    #include
    #include

    this->setGeometry(860,440,300,300);

    group = new QGroupBox(“hello”,this); // 创建 分组框 对象
    group->setGeometry(10,10,130,120);

    b1 = new QRadioButton(“choice 1”,group); // 创建 单选按钮 对象 , 指定父对象为 group 就进去了
    b1->move(30,25); // 对象移动
    //b1->setParent(group); // 用这种方法实现 指定父对象也是可以的
    b2 = new QRadioButton(“choice 2”,group);
    b2->move(30,55);
    b3 = new QRadioButton(“choice 3”,group);
    b3->move(30,85);

    // group -> insert(b1); 这种做法可有可无了,不加也可以的
    // group -> insert(b2);
    // group -> insert(b3);

    / ------------------------------------------------------ QRadioButton + QButtonGroup ------------------------------------------------------ /
    #include
    #include
    setGeometry(800,400,300,340);
    group = new QButtonGroup(this); // 只能传入一种参数

    b1 = new QRadioButton(“choice 1”,this); QRadioButton(“choice 1”,this); 其指定父对象的参数不能为 group
    b1->move(20,20);
    b2 = new QRadioButton(“chocie 2”,this);
    b2->move(20,50);
    b3 = new QRadioButton(“chocie 3”,this);
    b2->move(20,60);

    group->addButton(b1,3); // 将单选框放入 按钮组中,依次编号的排好
    group->addButton(b2,1);
    group->addButton(b3,2);

    / ------------------------------------------------------ QCheckBox + QGroupBox ------------------------------------------------------ /
    #include
    #include
    this->setGeometry(100,100,150,140);
    group = new QGroupBox(“Options”,this);
    group->setGeometry(10,10,130,120);

    b1 = new QCheckBox(“choice 1”,group); // 创建 复选框(复选按钮) 对象,指定父对象为 group 就行了
    b1->move(20,20);
    b2 = new QCheckBox(“choice 2”,group);
    b2->move(20,50);
    b3 = new QCheckBox(“choice 3”,group);
    b3->move(20,80);

    // group -> insert(b1); 这种做法可有可无了,不加也可以的
    // group -> insert(b2);
    // group -> insert(b3);

    基本上与单选的没有什么区别!

    / ------------------------------------------------------ QCheckBox + QButtonGroup ------------------------------------------------------ /
    #include
    #include
    group = new QButtonGroup(this);
    b1 = new QCheckBox(“hello”,this);
    b1->move(20,20);
    b2 = new QCheckBox(“world”,this);
    b2->move(20,50);
    b3 = new QCheckBox(“haha”,this);
    b3->move(20,80);

    group->addButton(b1);
    group->addButton(b2);
    group->addButton(b3);

    QGropBox 和 QButtonGrop 是做容器用的

  6. 标签
    QLabel
    经常以标签的形式向应用程序添加文本,在程序中,标签常用来显示简短信息或者是部件的说明
    QLabel text(“hello”);
    text . setAlignment ( AlignHCenter | AlignVCenter ); // 用来设置文本的对齐方式
    也可以使用 QLabel 显示位图和动画,这以功能由 QLabel::setPixmap() 和 QLabel::setMovie() 函数来实现

  7. QLcdNumber
    #include
    lcd = new QLCDNumber(this); // 创建LCD对象
    lcd->setGeometry(10,10,150,80);
    lcd->display(12345); // 将LCD的显示 设置为数字 12345


  8. QTableView 类用于创建表 , 其定义也非常抽象,因此 需要从 QTableView 类派生一个新类。
    ----------------------------- 未知

  9. 选择部件
    选择部件使用户能够从预定义的条目菜单中做出选择,这包含列表框和组合框,QListBox 类用于列表框,QComboBox类用于组合框(下拉列表框)

  10. QListWidget
    列表框部件一般用于使用户选择一个或多个条目。条目常为文本类型,但也可以是位图

    / ------------------------------------------------------ QlistWIdget + QListWidgetItem ------------------------------------------------------ /
    list = new QListWidget(this); // 创建一个 列表框
    list->setGeometry(10,10,150,130); // 设置其大小

    i1 = new QListWidgetItem(“hello”); // 创建一个列表框项
    i2 = new QListWidgetItem(“world”);
    i3 = new QListWidgetItem(“hahah”);
    QIcon icon(":/new/prefix1/background_paper.png"); // 创建一个图标对象
    i4 = new QListWidgetItem(icon,0); // 创建一个列表框项,带有图标的那种

    list->insertItem(1,i1); // 将列表框项插入到,列表框中
    list->insertItem(2,i2);
    list->insertItem(3,i3);
    list->insertItem(4,i4);

  11. 下拉列表框(组合框) QComboBox
    #include

    combo = new QComboBox(this); // 创建下拉列表框
    combo->setGeometry(10,10,130,30); // 设置其几何结构

    //list = new QListWidgetItem(“list”); 创建列表框项 , 也不能扔进 , 下拉列表框中
    //combo->insertItem(3,list); 这种方法是错误的!

    combo->insertItem(1,“xinfu”); // 将文本 xinfi 插入到下拉列表框中
    combo->insertItem(2,“haha”);
    combo->insertItem(0,“list”);

    注意:有一些部件在其他部件上 用指定父对象和add添加的方法是不一样的!指定父对象,只能说明谁在谁的上,不能说明某个控件嵌入到某个控件中了!

    QLIstWidget 与 QcomboBox 不是容器

  12. 部件布局
    QGroupBox 编组框 - 分组框
    QButtonGroup 按钮组
    QSplitter 分离器 - 切分窗口
    QStackWidget 小部件堆

    QFrame 也可用于布局部件,但是,它更是一个用于创建用户类的基类

    注意:add 添加部件 装入到容器中的部件比较多 一般与 insert 是可以相互转换的
    insert 添加部件 且有顺序 一般与 add 是可以相互转换的
    set 设置部件 只是将什么设置什么

    / ------------------------------------------------------ QGroupBox ------------------------------------------------------ /
    QGroupBox类 用于在部件周围绘制一个框架。你也可以在框架的上端添加一些描述信息。
    groupbox = new QGroupBox(this); // 创建一个编组框
    groupbox->setGeometry(10,10,130,80);
    groupbox->setTitle(“A Group Box”);

    label = new QLabel(groupbox); // 将编组框放进去 这是比较好弄的
    label->setGeometry(30,35,70,40);
    label->setText(“Add Widget n here!”);
    label->setAlignment(Qt::AlignHCenter);

    / ------------------------------------------------------ QButtonGroup ------------------------------------------------------ /
    QButtonGroup 按钮组
    QButtonGroup 与 QGroupBox 非常类似,但是,它有一些布置按钮方面的特殊功能,QButtonGroup 对象最常用的方法是布置单选按钮,
    在QButtonGroup中放置一套单选按钮能够 确保用户一次只选一个按钮(使他们 之间互相排斥)
    当单选按钮插入到 QButtonGroup 对象中时,他们之间是自动互相排斥。但是,为了使其他按钮之间互斥,则必须调用
    QButtonGroup::setExclusibe(true)函数。

    / ------------------------------------------------------ QSplitter ------------------------------------------------------ /
    拆分对象使用户能够通过拖动拆分器所提供的部件间的分界线控制子部件的大小
    splitter = new QSplitter(this); // 创建切分窗口对象
    splitter->setGeometry(10,10,130,80);
    splitter = new QSplitter(Qt::Vertical,this); // 可以设置其分离器的方向
    //splitter->setOrientation(Qt::Vertical); // 也可以这么设置
    //splitter->setMaximumSize(100,500); // 设置最大或者最小
    splitter->setMinimumSize(500,100);

    b1 = new QPushButton(“button 1”,splitter); // 将按钮放入每个切分对象中
    b2 = new QPushButton(“button 2”,splitter);

    QSlider 该类可以用于实现分割的组件
    该类允许用户通过拖拽子组件之间的边界来控制组件大小。一个类的实例可以控制任意多个组件,典型的使用实例是创建多个组件,
    将组件通过insertWidget()和addWidget)()来将他们加入到类的实例中。

    QSplitter *splitterMain = new QSplitter(Qt::Horizontal,this);
    QTextEdit *textleft = new QTextEdit(" 左部件",splitterMain);
    textleft->setAlignment(Qt::AlignHCenter);

    QSplitter *splitterRight = new QSplitter(Qt::Vertical,splitterMain);
    splitterRight->setOpaqueResize(false); // 设定在拖拽分割条时,是否实时更新。若为true,则实时更新
    ;否则在拖拽时显示一条虚线。
    QTextEdit *textUp = new QTextEdit(“上部件”,splitterRight);
    textUp->setAlignment(Qt::AlignHCenter);

    QTextEdit *textMiddle = new QTextEdit(“中间部件”,splitterRight);
    textMiddle->setAlignment(Qt::AlignHCenter);

    QTextEdit *textBottom = new QTextEdit(“底部部件”,splitterRight);
    textBottom->setAlignment(Qt::AlignHCenter);

    splitterMain->setStretchFactor(1,1); // 设定是否可以伸缩

    注意:加控件 , 将自己创造窗口

    / --------------------------------------------------------------------------------------------------------------------------- /
    StackedWidget控件中文称作“控件栈”。Qt提供了这样一个控件栈,可以使开发人员用栈管理控件像用栈管理其他数据类型一样简单。
    在Stacked Widget控件的properties选项中,一般常对以下选项进行设置。
    name:该控件对应源代码中的名称;
    currentPage:当前活动的页面;
    pageName:当前活动页的名称;
    font:设置该控件内部文本的字体。
    – QWidgetStack::QWidgetStack ( QWidget *parent = 0, const char *name = 0 )构造一个名称为name、父对象为parent的WidgetStack。
    – int QWidgetStack::addWidget ( QWidget *w, int id = -1 )把控件w添加到该控件栈中,标识是id。
    – int QWidgetStack::id ( QWidget *w ) const 返回控件w的标识。
    – void QWidgetStack::raiseWidget ( int id ) [slot]把标识为id的控件升到该控件栈的栈顶。
    – void QWidgetStack::raiseWidget ( QWidget *w ) [slot]把控件w升到该控件栈的栈顶。
    – void QWidgetStack::removeWidget ( QWidget *w )把控件w从该控件栈中删除。
    – QWidget *QWidgetStack::widget ( int id ) const 返回标识是id的控件。
    Public Slots:
    void setCurrentIndex( int index ) index参数的索引位置的部件,是可见的。(index默认为-1,表示堆栈为空)
    void setCurrentWidget( QWidget * widget ) widget参数指定的部件,是可见的。

    / ------------------------------------------------------ QWidgetStack ------------------------------------------------------ /
    #include
    #include
    #include
    m_list = new QListWidget(this);
    m_list->insertItem(0,“Window1”); // 直接插入窗口
    m_list->insertItem(1,“window2”);
    m_list->insertItem(2,“window3”);

    stacked = new QStackedWidget(this); // 创建堆栈窗口
    lab1 = new QLabel(“this is window1”);
    stacked->addWidget(lab1); // 将标签添加进去
    lab2 = new QLabel(“this is window2”);
    stacked->addWidget(lab2);
    lab3 = new QLabel(“this is window3”);
    stacked->addWidget(lab3);

    QHBoxLayout *mianlayout = new QHBoxLayout(this); // 创建水平布局
    mianlayout->addWidget(m_list);
    mianlayout->addWidget(stacked,0,Qt::AlignHCenter); // 设置布局中的属性
    mianlayout->setMargin(5); // 设置边界
    mianlayout->setSpacing(5); // 设置间隔
    mianlayout->setStretchFactor(m_list,1); // 设置拉伸系数为 1
    mianlayout->setStretchFactor(stacked,3); // 设置拉伸系数为 3
    connect(m_list,SIGNAL(currentRowChanged(int)), // 最后连接信号与槽
    stacked,SLOT(setCurrentIndex(int)));

  13. 滑动框和微调框
    滑动框:鼠标拖动调节器来选择数值
    微调框:点击按钮来改变数值

    / ------------------------------------------------------ QSpinBox ------------------------------------------------------ /
    spinbox = new QSpinBox(this);
    spinbox->setGeometry(50,10,50,30);

  14. 文件输入域
    / ------------------------------------------------------ QLineEdit ------------------------------------------------------ /
    line = new QLineEdit(this); // 创建对象
    line->setText(“hello i love you!”); // 设置文字
    line->setEchoMode(QLineEdit::Password); // 更该模式:密码模式
    line->setMaxLength(5); // 设置密码长度最大为

    使用 QLineEdit::text() 函数,可以检索当前写入到QLineEdit对象中的文本,当文本改变时,将发射QLineEdit::valueChanged() 信号

    / ------------------------------------------------------ QTextEdit ------------------------------------------------------ /
    QTextEdit 的使用方法与 QLineEdit 基本相同,但是,QTextEdit 包含几个新的用于编辑文本的函数。使用 insertAt() 函数,能够在
    QTextEdit 对象中的某一位置插入文本
    Object -> insertAt(“Hey!”,12,37); 第一个参数所插入的字符串,第二个参数指出所插入文本的行号,第三个参数指出在第几个字符后插
    入。
    Object -> insertAt(“Hey”,5); 在第五行 插入HEY;
    QLineEdit 和 QTextEdit 都能使用系统剪贴模板,这通过调用 cut() , copy() 和 paste() 函数实现

    注意:文本的对齐方式
    水平对齐方式有:
    Constant Value Description
    Qt::AlignLeft 0x0001 Aligns with the left edge.
    Qt::AlignRight 0x0002 Aligns with the right edge.
    Qt::AlignHCenter 0x0004 Centers horizontally in the available space.
    Qt::AlignJustify 0x0008 Justifies the text in the available space.

    垂直对齐方式有:
    Constant Value Description
    Qt::AlignTop 0x0020 Aligns with the top.
    Qt::AlignBottom 0x0040 Aligns with the bottom.
    Qt::AlignVCenter 0x0080 Centers vertically in the available space.
    Qt::AlignBaseline 0x0100 Aligns with the baseline.

  15. 列表视图
    QListView
    ----------------------------- 未知

  16. 进度条
    Qt 中进度条的显示方式有2种,一种是控件方式:QProgreeBar 一种是针对慢速过程的对话框方式:QProgressDialog
    ----------------------------- 未知

  17. 当创建 Qt 部件时,Qt 使用系统的低级函数(绘制线,矩形等图形的函数)在屏幕上绘制部件
    但是,有时可能需要创建 Qt 没有创建的用户图形对象。在这种情况下,需要某个能够产生用户图形的低级图形产生器,为此,Qt 提供了
    QPainter 类。

  18. 事件处理
    用户事件:键盘,鼠标,绘图等
    系统事件:定时器事件
    信号与槽:signal由具体对象发出,然后会马上交给由connect函数连接的slot进行处理;
    事件:而对于事件,Qt使用一个事件队列对所有发出的事件进行维护,当新的事件产生时,会被追加到事件队列的尾部,
    前一个事件完成后,取出后面的事件进行处理。

    事件函数的 函数参数一般都是 Event类 的对象指针 所以要在头问价 包含这个类 #include <QEvent>

    reurn app.exec(); 消息循环 , 监听检查各种各样的事件
    产生一个事件
    exec() 检测到了 事件
    其事件创建一个事件对象
    交给一个 event() 函数:这个函数不是立马处理
    给了一个事件处理器 相当于: switch( a ) { case 事件对象:事件函数(虚函数) }

    事件相当于一个中断,发生事件,就去处理,处理以后在回来!
    所有的事件类都继承与QEvent;

    / ------------------------------------------------------ QMouseEvent ------------------------------------------------------ /
    protected:
    virtual void mousePressEvent(QMouseEvent *ev); // 任何都不能改的,重写一下就行了
    virtual void mouseReleaseEvent(QMouseEvent *ev);
    virtual void mouseMoveEvent(QMouseEvent *ev);
    virtual void enterEvent(QEvent *);
    virtual void leaveEvent(QEvent *);

    MyLabel::MyLabel(QWidget *parent) : QLabel(parent)
    {
    this->setMouseTracking(true); // 设置运行程序就启动事件

    }
    void MyLabel::mouseReleaseEvent(QMouseEvent *ev) // 抬起事件
    {
    QString text = QString(“

    Mouse Release(%1,%2)

    ”). // 格式化输出 - 格式
    arg(ev->x()).arg(ev->y());
    this->setText(text);
    }
    void MyLabel::mousePressEvent(QMouseEvent *ev) // 按下事件
    {
    int i = ev->x();
    int y = ev->y();
    if(ev->button() == Qt::LeftButton)
    {
    }else if(ev->button() == Qt::RightButton) {

    }else if(ev->button() == Qt::MiddleButton)
    {
    
    }
    QString text = QString("<center><h1>Mouse press(%1,%2)</h1></center>").
    		arg(i).arg(y);
    this->setText(text);
    

    }
    void MyLabel::mouseMoveEvent(QMouseEvent *ev) // 鼠标移动事件
    {
    QString text = QString(“

    Mouse Move(%1,%2)

    ”).
    arg(ev->x()).arg(ev->y());
    this->setText(text);
    }
    void MyLabel::enterEvent(QEvent *)
    {
    QString text = QString(“

    Mouse is enter

    ”);
    this->setText(text);

    }
    void MyLabel::leaveEvent(QEvent *)
    {
    QString text = QString(“

    Mouse is leave

    ”);
    this->setText(text);

    }

  19. Qt 中定时器使用的两种方法:
    QObject 类提供的定时器
    QTime 类 使用
    其定时参数 都是 ms 级别的!
    QObject 类提供的定时器,需要用到三个函数

    1. int QObject::startTimer (int interval);
      这个是开启一个定时器的函数,他的参数interval是毫秒级别。当开启成功后会返回这个定时器的ID, 并且每隔interval 时间后会进入timerEvent 函数。直到定时器被杀死。
    2. void QObject::timerEvent( QTimerEvent * event );
      当定时器超时后,会进入该事件timerEvent函数,需要重写timerEvent函数,在函数中通过判断event->timerId()来确定定时器,
      然后执行某个定时器的超时函数。
    3. void QObject::killTimer ( int id );
      通过从startTimer返回的ID传入killTimer 函数中杀死定时器,结束定时器进入超时处理。以下是QObject中的定时器具体使用简单例子

    / ------------------------------------------------------ QtimerEvent ------------------------------------------------------ /
    label = new QLabel(this);
    label->setGeometry(0,0,600,340);

    label->setFont(QFont(“MYuenHK-SemiBold”,30,QFont::Bold,true)); // 设置字体
    label->setAlignment(Qt::AlignVCenter|Qt::AlignHCenter); // 设置文字在窗口中的布局
    m_nTimerID = this->startTimer(500); // 创建定时器1 , 返回一个独有的id
    m_nTimerID2 = this->startTimer(750); // 创建定时器2
    m_nTimerID3 = this->startTimer(980); // 创建定时器3
    m_nTimerID4 = this->startTimer(1330); // 创建定时器4

    qDebug() << "m_nTimerID = " << m_nTimerID << endl; // 输出每个独有的 id
    qDebug() << "m_nTimerID2 = " << m_nTimerID2 << endl;
    qDebug() << "m_nTimerID3 = " << m_nTimerID3 << endl;
    qDebug() << "m_nTimerID4 = " << m_nTimerID4 << endl;

    void Widget::timerEvent(QTimerEvent *event)
    {
    static int i = 0;
    static int j = 0;
    static int x = 0;
    static int y = 0;
    if(m_nTimerID == event->timerId()) // 匹配 id
    {
    label->setText(QString(“time-value-i:%1”).arg(i++)); // 进行输出
    killTimer(m_nTimerID); // 杀死定时器
    }
    else if(m_nTimerID2 == event->timerId())
    {
    label->setText(QString(“time-value-j:%1”).arg(j++));
    killTimer(m_nTimerID2);
    }
    else if(m_nTimerID3 == event->timerId())
    {
    label->setText(QString(“time-value-x:%1”).arg(x++));
    killTimer(event->timerId());
    }
    else if(m_nTimerID4 == event->timerId())
    {
    label->setText(QString(“time-value-y:%1”).arg(y++));
    }
    //killTimer(m_nTimerID);
    }

    / ------------------------------------------------------ QTimer ------------------------------------------------------ /
    使用QTimer定时器类

    1. 首先创建一个定时器类的对象
      QTimer *timer = new QTimer(this);
    2. timer 超时后会发出timeout()信号,所以在创建好定时器对象后给其建立信号与槽
      connect(timer, SIGNAL(timeout()), this, SLOT(onTimeout()));
    3. 在需要开启定时器的地方调用void QTimer::start ( int msec );
      这个start函数参数也是毫秒级别; timer->start(msec );
    4. 在自己的超时槽函数里面做超时处理。

    private slots:
    void handleTimeout(); // 创建一个 槽函数

    QTimer *m_pTimer; // 创建 time 类
    m_pTimer = new QTimer(this); // 连接信号与槽
    connect(m_pTimer,SIGNAL(timeout()),
    this,SLOT(handleTimeout()));
    m_pTimer->start(5000); // 开启 定时器,5000ms 以后调用信号与槽

    void Widget::handleTimeout()
    {
    qDebug() << “Endter timerout proica” << endl;
    if(m_pTimer->isActive()) // 判断是否已经执行了
    {
    m_pTimer->stop(); // 停止定时器
    }
    }

  20. 事件的接受和忽略
    void Widget::mousePressEvent(QMouseEvent *ev)
    {
    qDebug() << " jinrudaol hanshuz" << endl;
    if(ev->button() == Qt::LeftButton) //这一块就是信号的接受
    {
    qDebug() << “an xia de shi zuo jian” << endl; // 事件接受后,就不会向下传递了
    ev -> ignore() ; // 忽略,事件继续往下传递,但没有告诉传递给谁
    // 事件传递给了父组件 , 而不是基类
    }
    else
    {
    //不做处理,掉给他的父类处理
    QWidget::mousePressEvent(ev); // 事件忽略后 , 就交给 父类继续传递了
    //这一块就是信号的忽略
    }
    QWidget::mousePressEvent(ev);
    }

    -------------------------- 未完待续;

  21. event() 函数
    只要是每个控件继承与QWidget , 则都会自带一个 event()函数 , 且为虚函数;
    QWidget -> event() ->
    event() 事件分发作用

    -------------------------- 未完待续;

  22. 事件过滤器
    -------------------------- 未完待续;

  23. 绘图
    QPainter 画家
    QPaintEngine 通信接口
    QPaintDevice 设备

    / ------------------------------------------------------ QPainter 到背景图 ------------------------------------------------------ /
    //重写绘图函数,虚函数;如果在窗口绘图,必须放在绘图事件里实现
    //绘图事件内部自动调用,窗口需要重绘的时候(状态改变-窗口中任何地方有改变,其上部件改变也 算)
    //鼠标事件都是点击以后改变的,而绘图是窗口改变就调用它
    //当然也可以人为调用它
    //自动绘图的这是 – 但是也有手动更新的
    virtual void paintEvent(QPaintEvent *);

    #include
    #include
    #include

    void Widget::paintEvent(QPaintEvent ) // 在qt中这个参数如果不用,就可以不写这么放着就行
    {
    //方法1
    //QPainter p(this); // 指定widget主窗口为绘图设备
    // QWidget 还继承与 QPaintDevice
    //方法2
    QPainter p; // 创建画家对象
    p.begin(this); // 指定画图设备及在哪里画画指定 当前窗口为绘图设备
    // 绘图操作
    //p.draw
    ** // 绘制各种各样的图形
    QPixmap a(":/new/prefix1/drake_3rd_fire.png" );
    p.drawPixmap(0,0,this->width(),this->height(),a ); // 以窗口的长宽高为基础去绘图
    //p.drawPixmap(0,0,this->width(),this->height(),QPixmap(":/new/prefix1/drake_3rd_fire.png"));

    //p.drawPixmap(this->rect(),a);           							//	rect() 函数获取矩形区域属性 - 也是可以这么画的
    
    QPen pen;                               											// 创建画笔
    pen.setWidth(5);                        										// 设置画笔属性
    //pen.setColor(Qt::red);               									// 设置颜色
    pen.setColor(QColor(58,55,66));         								// 设置RGB三原色 0~255
    pen.setStyle(Qt::DashLine);             									// 设置风格
    
    p.setPen(pen);                          										// 把新画笔交给画家
    p.drawLine(50,50,150,50);
    p.drawLine(50,50,50,150);
    
    QBrush brush;                            										// 创建画刷
    brush.setColor(Qt::red);
    brush.setStyle(Qt::VerPattern);
    
    p.setBrush(brush);                       									// 设置画刷,画刷只对闭合图形有用,其他的不闭合的没有用
    
    p.drawRect(100,100,100,100);             							// 画矩形
    p.drawEllipse(QPoint(300,300),50,25);    						// 画圆,第一个参数为圆心,然后是圆的水平宽度,和竖直长度
    
    p.drawPixmap(x,250,80,80,QPixmap(":/new/prefix1/blue.thumbnail (6).png")); 		 //画笑脸 		其中x的参数是随之改变的
    
    p.end();            																// 还要用end结束
    

    }

    void Widget::on_pushButton_clicked() // 按钮的槽,当按下按钮时,就会因为update() ; 重绘窗口
    {
    x+=20;
    if(x > this->width())
    {
    x = 0;
    }
    // 刷新窗口,让窗口重绘 : 手动刷新窗口,间接调用 paintEvent() 函数
    update(); // 可以指定范围,如果不指定则为窗口全部
    // 不能将update();函数放入 绘图事件中,否则会进入 死循环状态
    }

    注意:尽量不要在绘图事件中做太复杂的数据处理

  24. QBitmap 继承与 QPixmap
    QBitmap 画黑白图 效率高
    QPixmap 画彩图 效率低

    / ------------------------------------------------------ QPainter - QBitmap ------------------------------------------------------ /
    QPainter p(this);
    p.drawPixmap(0,0,QPixmap(":/new/prefix1/category_gold.png")); //没有 drawPixmap这个函数 因为是继承关系,所以直接这么用了
    p.drawPixmap(300,0,QBitmap(":/new/prefix1/category_gold.png"));

    //QPixmap pixmap; 这样也是可以的
    //pixmap.load(":/new/prefix1/category_gold.png");
    //p.drawPixmap(300,0,pixmap);

  25. 绘图设备
    QPixmap 最常用的,针对屏幕进行优化了,和平台相关,不能对图片进行修改
    QImage 和平台无关,可以对图片进行修改,可以进行像素点的修改,可以在线程里绘图
    QPicture 保存绘图的状态,保存一个二进制文件
    三者之间的用法基本一样

    / ------------------------------------------------------ QPixmap 绘图设备 ------------------------------------------------------ /
    QPixmap pixmap(400,300); // 绘图设备,大小是 400 * 300
    QPainter p(&pixmap);
    // 填充白色背景 根据画家填充
    // p.fillRect(0,0,400,300,QBrush(Qt::white));
    pixmap.fill(Qt::white); // 填充白色背景 根据绘图设备填充

    p.drawPixmap(0,0,80,80,QPixmap(":/new/prefix1/blue.thumbnail (6).png"));
    pixmap.save("…/pixmap.jpg");

    / ------------------------------------------------------ QImage 绘图设备 ------------------------------------------------------ /
    QImage image(400,300,QImage::Format_ARGB32);
    QPainter p;
    p.begin(&image); // 创建画家,指定画图设备
    p.drawImage(0,0,QImage(":/new/prefix1/blue.thumbnail (6).png")); // 画图 用这个画了 - 也可以用 drawPixxmap()

    // 对绘图设备 前50个像素点 进行设置
    for(int i = 0;i < 50;i++)
    {
    for(int j = 0;j < 50;j++)
    {
    image.setPixel(QPoint(i,j),qRgb(0,255,0)); // 设置像素点
    image.pixel(QPoint(i,j)); // 可以对像素点进行获取
    }
    }
    image.save("…/iamge.png"); // 最好是绘图设备的进行保存

    / ------------------------------------------------------ QPicture 绘图设备 ------------------------------------------------------ /
    QPicture picture;
    QPainter p;
    p.begin(&picture);
    p.drawPixmap(0,0,80,80,QPixmap(":/new/prefix1/blue.thumbnail (6).png"));
    p.drawLine(50,50,150,50);

    //保存的是二进制文件,能在其他地方能加载出来
    picture.save("…/asd.png");

  26. 因为各种特性的原因,所以各种设备之间可以进行转换

    QPainter p;
    QPixmap pixmap;
    pixmap.load("…/asd.png");
    // QPixmap -> QImage;
    QImage tempImage = pixmap.toImage();
    p.drawImage(0,0,tempImage);

    QImage image;
    image.load("…/asd.png");
    QPixmap tempPixmap = QPixmap::fromImage(image);
    p.drawPixmap(100,0,tempPixmap);

  27. 不规则窗口

    / ------------------------------------------------------ 不规则窗口 ------------------------------------------------------ /
    // 设定窗口标记,实现窗口的透明化
    // this->setWindowFlags(Qt::Dialog); 变成对话框了
    //this->setWindowFlags(Qt::FramelessWindowHint | windowFlags()); //Qt5中的去边框了
    this->setWindowFlags(Qt::FramelessWindowHint ); // 去边框了
    this->setAttribute(Qt::WA_TranslucentBackground); // 窗口透明,与去边框一起使用

    void Widget::paintEvent(QPaintEvent *)
    {
    QPainter painter(this);
    painter.drawPixmap(0,0,this->width(),this->height(),
    QPixmap(":/new/prefix1/card_earth.png"));
    }

  28. Qt 文件系统
    QIODevice 基类 以下为继承
    – QBuffer 读写文件以后放入这里
    – QProcess 进程相关的
    – QFile Device -> QFile -> QTemporaryFile
    – QAbstractSocket -> QTcpSocket 面向连接的 -> QSalSocket
    -> QUdpSocket 面向无连接的

    / ------------------------------------------------------ 文件操作 ------------------------------------------------------ /
    void Widget::read_file()
    {
    QString path = QFileDialog::getOpenFileName(this,“open_title”,"…/"); // 获取文件地址及其名字
    if(path.isEmpty() == false)
    {
    QFile file(path); // 文件对象 - 关联了
    //打开文件,只读方式打开其函数是有返回值的,打开成功为true,未成功为false
    bool isok = file.open(QIODevice::ReadOnly);
    if(isok == true)
    {
    #if 0
    //读文件 file.readAll 返回字节数组 即定义一个字节数组
    //读文件,默认只识别 utf8 的, 其他的识别不了
    QByteArray array = file.readAll();
    text->setText(QString(array));
    // text->setText(array);
    #endif
    QByteArray array;
    while(file.atEnd() == false) // 如果读到文件尾部,就会返回一个 false ,没读到,其文件指针接着读 应该是了
    {
    array += file.readLine(); // 读一行
    }
    text->setText(array);
    }
    file.close(); // 关闭文件
    }
    }
    void Widget::write_file()
    {
    QString path = QFileDialog::getSaveFileName(this,“save”,"…/",“TXT(*.txt)”);
    if(path.isEmpty() == false)
    {
    QFile file;
    file.setFileName(path); // 关联文件名
    bool isok = file.open(QIODevice::WriteOnly); // 打开文件, 只写方式
    if(isok == true)
    {
    QString str = text->toPlainText(); // 获取 编辑区内容
    file.write(str.toUtf8()); // 写文件 QString -> QByteArray
    }
    file.close();
    }
    }

  29. Qt TCP网络

    Linux
    客户端 服务端
    Sokcet Socket 监听套接字
    connect bind
    read/write 读写操作 listen
    accept 通信套接字
    read/write 读写操作

    Qt
    客户端 服务端
    QTcpSocket 套接字 QTcpServer 监听套接字
    connectToHost() 连接到主机 listen() 绑定和监听放在一起了 bind /listen 合为了一个函数了

    如果连接成功!服务器会触发服务器的 newConnection()信号,然后调用服务器的槽
    – 取出建立好连接的套接字 QTcpSocket 通信的套接字

    发送数据 write() 函数:如果数据传输成功,对方服务器的通信套接字会触发readyRead( ),需要在对应的槽函数做接受处理。

    常用信号:
    如果成功和对方建立好连接,通信套接字会自动触发:connected
    如果对方主动断开连接,通信套接字会自动触发:disconnected();

    在项目文件中要加入 QT += network

  30. 对话框
    自定义对话框:
    预定义对话框:QColorDialog QFileDialog QFontDialog QMessageDialog QProgressDialog QInputDialog

    void on_btnColor_clicked();
    void on_btnFont_cliced();
    void on_btnInpu_cliced();
    void on_actionOpen_triggered();
    void on_actionSave_triggered();

    #include //消息对话框
    #include //颜色对话框
    #include //字体对话框
    #include //文件对话框
    #include //输入对话框
    #include //文件相关信息

    //QColorDialog a(this);
    //a.setGeometry(0,0,15,55);
    //a.show();
    //QInputDialog b(this);
    //以上代码都不会出现对话框,只有在出现函数 get*** 时才会出现对话框!

    connect(ui->btnColor,SIGNAL(clicked()),this,SLOT(on_btnColor_clicked()));
    connect(ui->btnFont,SIGNAL(clicked()),this,SLOT(on_btnFont_cliced()));
    connect(ui->btnInput,SIGNAL(clicked()),this,SLOT(on_btnInpu_cliced()));
    connect(ui->actionOpen,SIGNAL(clicked()),this,SLOT(on_actionOpen_triggered()));
    connect(ui->actionSave,SIGNAL(clicked()),this,SLOT(on_actionSave_triggered()));

    }
    void MyMainWindow::on_btnColor_clicked()
    {
    QColor color = QColorDialog::getColor(Qt::blue,this,“请选择颜色!”); //不需要创造类对象!只需要静态函数调用,就可以出现对话框啦!
    QString style = QString(“background-color:rgb(%1,%2,&3):”).arg(color.red()).
    arg(color.green()).arg(color.blue()); //使用格式化 获取三原色
    ui->edt_count->setStyleSheet(style); //根据返回的颜色 设置样式表
    }
    void MyMainWindow::on_btnFont_cliced()
    {
    bool is_ok;
    QFont font = QFontDialog::getFont(&is_ok,QFont(“微软雅黑”),this,“zi ti xuan ze”); //获取字体,然后交给字体对象
    ui->edt_count->setFont(font);
    }
    void MyMainWindow::on_btnInpu_cliced()
    {
    QString text = QInputDialog::getText(this,“shuruneirong”,“asddsa”); //获取字符串,然后交个字符串
    ui->edt_count->setText(text);
    }

    void MyMainWindow::on_actionOpen_triggered()
    {
    QString filepath = QFileDialog::getOpenFileName(this,“xuan ze biaoti”,"…/"); //根据文件对话框,获取文件路径(字符串)
    QFile *file = new QFile(filepath); //创建一个文件对象,利用文件路径对其初始化(字符串)
    bool isok = file->open(QIODevice::ReadOnly); //以只读方式打开,成功返回一个true
    if(isok)
    {
    QByteArray array = file->readAll(); //读取文件中所以内容
    ui->edt_count->setText(array);
    }
    else
    {
    QMessageBox::warning(this,“thishi”,“dakaiwenjianshbai”); //如果获取失败,则弹出一个消息对话框
    }
    file->close(); //最好关闭文件
    }

    void MyMainWindow::on_actionSave_triggered()
    {
    QString saveFile = QFileDialog::getSaveFileName(this,“mingcheng”,"…/"); //弹出文件对话框,填写文件路径
    QFile *save = new QFile(saveFile); //创建文件对象
    save->open(QIODevice::WriteOnly); //以只写方式打开文件

    save->write(ui->edt_count->toPlainText().toUtf8());													//开始将信息写入文件中
    
    save->close();																												//关闭文件
    QMessageBox::aboutQt(this,"hello");																			//消息对话框 弹出关于信息
    QMessageBox::warning(this,"tishi","save all");																//消息对话框 弹出提示信息
    

    }

  31. 视频播放器
    1.书写界面
    2.播放视频
    3.实现视频调节
    4.播放 暂停 停止功能实现
    5.实现列表 显示 视频播放文件《文件操作,目录文件》

    QT += multimedia multimediawidgets 首先添加模块 (多媒体模块)
    在Qt4.6中新加入了QtMultimedia模块来提供一些底层的多媒体功能,比如音频的采集和回放、频谱分析、操作视频帧等。该模块主要由8个类组成,

    遇到的问题:

    1. setGemotry 是否可以和 布局一起使用
      1920 * 1080
      1260 760 -
      减法初二 : 330 - 160
  32. QMovie
    QMovie类是一个很方便的类,用于播放动画。在刷新页面的时候,可以尝试用QMovie 来实现等待界面。
    QMovie类用于显示简单的动画,没有声音。
    首先,通过将一个文件的名称或者一个指针传递给QMovie的构造函数构建一个QMovie对象。传递的文件包含文件的格式。
    可以调用函数isValid()来检测在动画开始播放前,动画是否有效。
    调用函数start() 函数开始播放动画,QMovie将进入运行状态,并发射started() 和 stateChanged()信号。
    当然,调用函数state() 可获取当前动画的播放状态。

  33. Qt 网络编程之UDP编程
    linxu的:
    服务器端口: 客户端:
    创建套接字 Socket 创建套接字 Socket
    绑定 - bind (不需要建立连接)
    读写操作 recvFrom / sendto 读写操作 recvFrom / sendto
    close Socket close Socket
    udp 特别像现实生活中的写信
    tcp 像是打电话

    Qt
    服务器端 客户端:
    创建套接字:QUdpSocket 创建套接字:QUdpSocket
    绑定 - bind()
    读写操作 readDategram / writeDatagram 读写操作 readDategram / writeDatagram
    注意:如果对方给我发数据,套接字自动触发
    readyRead()

    255.255.255.255 局域网 广播地址

  34. Qt TCP 文件传输流程
    客户端: 服务器:

    						--- 建立好连接以后 ---
    																			1.选择一个文件
    																			2.文件大小 		1024	例:
    																			文件 信息			hello	
    						发送文件信息
    
    1. 接受,分析字符串 (拆包)
      文件大小,文件名字
    2. 本地创建一个文件
      3.读文件
      4.发送数据(读多少发多少)
      5.发送文件大小和获取文件大小
      发送文件
    3. 对方发多少,接受多少
    4. 把接受到的内容写到文件里面
  35. Qt 线程 (Qt4简单 Qt5灵活)
    界面处理很复杂的时候:
    多任务的时候

    在多线程应用程序中,图形用户界面运行与它自己的线程中,而另外的事件处理过程则会发生在一个会多个其他线程中。这样做之后,即使处理那些
    数据秘籍的事件时,应用程序也能对图形用户界面保持响应!
    涉及到的类:QThread QMutex互斥 QSemaphore QWaitCondition
    操作系统中,运算调度的最小单位
    进程支持多线程,但是必须有一个主线程
    多个线程之间:是相互独立的
    其他线程都是通过主线程 直接/间接 启动的
    主线程结束,其他子线程都没了

    qApp -> thread()

    2个方法:
    QThread (较为传统)
    QtConcurrent (高级API,较为方便)

    / ------------------------------------------------------ QThread ------------------------------------------------------ /

    #include
    #include “my_thred.h”

    int main(int argc,char *argv[])
    {
    QApplication app(argc,argv);

    QString filePath = "D:/text.txt";										
    QByteArray data = "Hello,thread!";									//将地址和数据传如
    
    qDebug() << QThread::currentThread();
    
    MyThread my_thread(filePath,data);								//创建一个线程类
    my_thread.start();          //启动线程									//启动线程
    

    // QThread(0xbe52ba8) 主线程
    // MyThread(0x65fe18) 次线程

    return app.exec();
    

    }

    #ifndef MY_THRED_H
    #define MY_THRED_H

    #include
    #include
    #include

    class MyThread:public QThread //继承与 QThread
    {
    Q_OBJECT

    public:
    MyThread(const QString &filePath,const QByteArray &data)
    {
    filePath_ = filePath;
    data_ = data;
    }
    //线程的起点。在调用start()之后,新创建的线程调用这个函数。默认实现只调用exec()。
    您可以重新实现此功能,以促进高级线程管理。从这个方法返回将结束线程的执行。
    参见start()和wait()。
    virtual void run() //run 是实现部分哈
    {
    qDebug() << QThread::currentThread();

    	QFile file(filePath_);
    	file.open(QIODevice::WriteOnly);
    	file.write(data_);
    	file.waitForBytesWritten(30 * 1000);
    }
    

    private:
    QString filePath_;
    QByteArray data_;

    };

    #endif // MY_THRED_H

  36. 样式表
    颜色:
    color 颜色
    background - color 背景颜色
    alternate - background - color 替换背景颜色
    border - color 边境 - 边框
    border - top -color 边框上的颜色
    border - right -color 边框右的颜色
    border - lift -color 边框左的颜色
    border - bottom -color 边框下的颜色
    gridline - color 网格线颜色
    selection - color 选择颜色
    selection - background - color 选择背景颜色

    添加渐变:
    color 颜色
    background - color 背景颜色
    alternate - background - color 替换背景颜色
    border - color 边境 - 边框
    border - top -color 边框上的颜色
    border - right -color 边框右的颜色
    border - lift -color 边框左的颜色
    border - bottom -color 边框下的颜色
    gridline - color 网格线颜色
    selection - color 选择颜色
    selection - background - color 选择背景颜色

    添加资源:
    background - image 背景 - 图像
    border - image 边框 - 图像
    image 图像

    添加例子:
    color: rgb(170, 255, 127);
    background-color: rgb(0, 0, 0);
    alternate-background-color: rgb(255, 255, 0);
    border-top-color: rgb(0, 85, 0);
    直接是 属性:rgb(); 就行

    1.从层次上来说:
    控件可分为前景与背景
    前景:多包含文件,图片等内容
    背景:多包含图片,图形等内容

    2.由于QT style是模拟CSS的布局结构,因此其满足CSS的盒子模型
    从里到外的4个区域分别是:
    1: content 内容
    2: padding 填充
    3: border 边框
    4: margin 边界

  37. Qt 多媒体
    首先 : 在项目文件中加入模块 QT+multimedia

    播放压缩音频: //Qt5
    #include media player 媒体播放机
    player = new QMediaPlayer;
    player->setMedia(QUrl::fromLocalFile (" mp3路径 "));
    player->play();
    URL是Uniform Resource Location的缩写,译为“统一资源定位符”。

    Qt4中 的QtMultimedia 多媒体
    QAbstractVideoBuffer 视频数据的抽象
    QAbstractVideoSourface 视频呈现表面(video presentation surfaces)的基类
    QAudioDeviceInfo 查询音频设备及其功能的接口
    QAudioFormat 存储音频参数信息 - 采样率 - 样本大小 - 样本类型 - 字节顺序 - 声道数量
    QAudioInput 从音频输入设备接受音频数据的接口
    QAudioOutput 从音频输出设备输出音频的接口
    QVideoFrame 代表一个视频数据帧数
    QVideoSourfaceFormat 指定一个视频呈现表面的流格式

    QSound 音乐播放: //Qt4
    QSound::isAvailable() 静态函数判断平台是否存在响应的音频设备
    播放方式 2种:
    直接调用:静态函数
    QSound::play(path); 最好音频文件是放在项目文件中的,而不是资源文件中
    创建类
    sound = new QSound(path,this);
    sound->play(); 即可播放

    #include
    #include
    #include
    #include
    #include

    namespace Ui {
    class Widget;
    }

    class Widget : public QWidget
    {
    Q_OBJECT

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

    private:
    Ui::Widget *ui;
    QFile file;
    QAudioInput *audioInput;
    QAudioOutput *audioOutput;

    private slots:
    void stopRecording();
    void finishedPlaying(QAudio::State state);

    void on_pushButton_clicked();
    void on_pushButton_2_clicked();
    

    };

    / ------------------------------------------------------ 音频播放器 ------------------------------------------------------ /
    #include “widget.h”
    #include “ui_widget.h”
    #include
    #include
    #include
    #include
    #include
    #include
    #include

    Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
    {
    ui->setupUi(this);
    }

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

    void Widget::on_pushButton_clicked()
    {
    file.setFileName("…/test.raw");
    file.open(QIODevice::ReadOnly|QIODevice::Truncate); //Truncate 截断文件
    QAudioFormat format;
    format.setFrequency(8000);
    format.setChannels(1);
    format.setSampleSize(8);
    format.setCodec(“audio/pcm”);
    format.setByteOrder(QAudioFormat::LittleEndian);

    QAudioDeviceInfo info = QAudioDeviceInfo::defaultInputDevice();
    if(!info.isFormatSupported(format))
    {
    	format = info.nearestFormat(format);
    }
    
    QTimer::singleShot(10000,this,SLOT(stopRecording()));
    audioInput = new QAudioInput(format,this);
    audioInput->start(&file);
    ui->label->setText(QString::fromUtf8("正在录制。。。"));
    

    }
    void Widget::on_pushButton_2_clicked()
    {
    QString path = QFileDialog::getOpenFileName(this,“huoqu”,"…/");
    qDebug() << path << endl;
    file.setFileName(path);
    file.open(QIODevice::ReadOnly);
    QAudioFormat format;
    format.setFrequency(8000);
    format.setChannels(1);
    format.setSampleSize(8);
    format.setCodec(“audio/pcm”);
    format.setByteOrder(QAudioFormat::LittleEndian);
    format.setSampleType(QAudioFormat::UnSignedInt);
    QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice());
    if(!info.isFormatSupported(format))
    {
    return;
    }
    audioOutput = new QAudioOutput(format,this);
    connect(audioOutput,SIGNAL(stateChanged(QAudio::State)),
    SLOT(finishedPlaying(QAudio::State)));
    audioOutput->start(&file);
    ui->label->setText(QString::fromUtf8(“正在播放…”));
    }
    void Widget::stopRecording()
    {
    audioInput->stop();
    ui->label->setText(QString::fromUtf8(“停止录制…”));
    file.close();
    delete audioInput;
    }
    void Widget::finishedPlaying(QAudio::State state)
    {
    if(state == QAudio::IdleState)
    {
    audioOutput->stop();
    ui->label->setText(QString::fromUtf8(“停止播放…”));
    file.close();
    delete audioOutput;
    }
    }

    / ------------------------------------------------------ Phonon框架 ------------------------------------------------------ /
    phonon 是一个多媒体框架,利用它可以在Qt应用程序中使用音频和视频等多媒体文件
    QT += Phonon
    包含3个基本概念:媒体对象(Media Objects),汇点( Sinks )和路径( Paths ).
    媒体对象用来管理媒体源,例如一个音乐文件,提供开始,停止和暂停等简单播放功能;
    汇点用来从 Phonon 中输出媒体,例如在媒体上渲染视频或将音频传送到声卡
    路径用来连接Phonon 对象,例如连接一个媒体对象和一个绘体,这样形成关系图

    媒体源(Media Source) ----> 媒体对象(MediaObject) -----> 音乐汇点(Audia Sink) ----> 音频设备
    (路径)
    音频媒体与视频媒体图 是一样的!
    媒体源也是一个独立的对象,媒体源为媒体对象提供原始的数据,其可以从一个文件中读取,也可以从网络媒体流读取
    汇点是一个可以从媒体图中输出媒体的节点,通常是一个渲染设备,对于音频汇点,它代表一个虚拟的音频设备,可以对音量进行控制,对于一个
    视频汇点,比如VideoWidget,可以在一个 QWidget 部件上渲染视频,并且可以改变亮度,色调,视频缩放等
    播放音频:

    简单的程序:使用Phonon 提供的便捷函数 createrPlayer() 来创建一个媒体图
    #include
    #include
    Phonon::MediaObject *music = Phonon::createPlayer()
    qDebug() << Phonon::BackendCapabilities::availableMimeTypes(); //查询后台支持的功能::查看我能用的类型
    Phonon::MediaObject *music = Phonon::createPlayer(Phonon::MusicCategory, //音乐类别
    Phonon::MediaSource(“D:/Qt4_Project/ainiaini.mp3” ));
    //媒体源
    //创建由路径连接的MediaObject和AudioOutput的便利函数。MediaObject返回的源集将被设置为当前源和指定的类别。
    //创建 对象
    qDebug() << str << endl;
    music->setParent(this);
    music->play();

    创建音频流媒体图:
    创建一个媒体对象,然后将它连接到一个音频输出节点,该节点由 AudioOutput类 提供,将音频输出到声卡
    ui->setupUi(this);
    Phonon::MediaObject *mediaObject = new Phonon::MediaObject(this); //创建媒体对象
    mediaObject->setCurrentSource(Phonon::MediaSource(“D:/Qt4_Project/ainiaini.mp3”)); //设置媒体源
    Phonon::AudioOutput *audioOutput = new Phonon::AudioOutput(Phonon::MusicCategory,this); //创建媒体汇点
    Phonon::Path path = Phonon::createPath(mediaObject,audioOutput); //路径将音频输出连接到媒体对象上
    mediaObject->play(); //开始玩耍
    注意:AudioOutput 提供函数控制音量大小,还可以设置静音,音量控制部件VolumeSlIder,播放进度滑块 该类也是QWidget 的子类

    播放视频 2种方式:
    快捷创建:
    Phonon::VideoPlayer *player = new Phonon::VideoPlayer(Phonon::VideoCategory,this);
    player->resize(400,300);
    QString id = QFileDialog::getOpenFileName(this,“haha”,"…/");
    player->play(Phonon::MediaSource(id));

    创建视频的媒体图:
    播放视频可以使用 VideoWidget 类,该部件可以自动选择可用的设备来播放视频。
    VideoWidget 并不会播放媒体流中的音频,如果需要播放音频,那么就要创建一个 AudioOutput节点

    QString id = QFileDialog::getOpenFileName(this,“haha”,"…/"); //获取文件路径
    Phonon::MediaObject *mediaObject = new Phonon::MediaObject(this); //创建媒体对象
    Phonon::VideoWidget *videoWidget = new Phonon::VideoWidget(this); //汇点为视频窗口小部件
    Phonon::createPath(mediaObject,videoWidget); //建立路径连接媒体对象和媒体小窗口
    Phonon::AudioOutput *audioOutput = new Phonon::AudioOutput(Phonon::VideoCategory,this); //创建媒体音频汇点,音频类型
    Phonon::createPath(mediaObject,audioOutput); //建立路径连接媒体对象和音频汇点
    mediaObject->setCurrentSource(Phonon::MediaSource(id)); //设置媒体源
    videoWidget->resize(1314,800);
    mediaObject->play(); //开始跳舞

    / ------------------------------------------------------ 视频播放器 ------------------------------------------------------ /
    VideoWidget 类的 : 亮度 brightness ,色调 hue , 饱和度 saturation 和对比度 contrast 这四个属性都是浮点值,取值范围在 -1 ~ 1 之间,默认值
    为0。

    / ------------------------------------------------------ 音频播放器 ------------------------------------------------------ /
    question:
    set Size Policy 设置大小政策 :
    Constants Description
    QSizePolicy::Fixed widget 的实际尺寸只参考 sizeHint() 的返回值,不能伸展(grow)和收缩(shrink)
    QSizePolicy::Minimum 可以伸展和收缩,不过sizeHint() 的返回值规定了 widget 能缩小到的最小尺寸
    QSizePolicy::Maximum 可以伸展和收缩,不过sizeHint() 的返回值规定了 widget 能伸展到的最大尺寸
    QSizePolicy::Preferred 可以伸展和收缩,但没有优势去获取更大的额外空间使自己的尺寸比 sizeHint() 的返回值更大
    QSizePolicy::Expanding 可以伸展和收缩,它会尽可能多地去获取额外的空间,也就是比 Preferred 更具优势
    QSizePolicy::MinimumExpanding 可以伸展和收缩,不过sizeHint() 的返回值规定了 widget 能缩小到的最小尺寸,同时它比 Preferred 更具优势去获取额外空间
    QSizePolicy::Ignored 忽略 sizeHint() 的作用

    sizeHint 大小提示
    这个属性所保存的 QSize 类型的值是一个被推荐给窗口或其它组件(为了方便下面统称为widget)的尺寸,也就是说一个 widget 该有多大,它的一个参考来源就是这个 sizeHint 属性的值,而这个值由 sizeHint() 函数来确定。但是 widget 的大小的确定还有其它因素作用,下面会讲到。现在只需知道 sizeHint() 会返回一个被推荐的尺寸。那么这个尺寸的取值是怎样的呢?当它是一个无效值的时候(sizeHint().isValid() 返回 false,QSize 中 width 或者 height 有一个为复数就会是无效的),什么作用也没有;当它是一个有效值的时候,它就成了 widget 大小的一个参考。Qt 中对 sizeHint() 的默认实现是这样的:当 widget 没有布局(layout),返回无效值;否则返回其 layout 的首选尺寸( preferred size)。

    QTime 类
    QTime 提供时间函数给用户使用,它和QTimer的区别就和手表与秒表的区别一样。

    在Phonon中将媒体部件划分为几个状态,媒体对象 MediaObject 总是处于几种状态的其中一种。这几种状态由 Phonon::State枚举变量定义
    当状态发送改变时就会发射 stateChanged() 信号,可以通过关联该信号来获取媒体对象当前的状态,从而进行一些有关的设置,例如改变图标的
    状态等等。
    Phonon::LoadingState 加载状态
    Phonon::StoppedState停止状态
    Phonon::PlayingState播放状态
    Phonon::BufferingState 缓冲状态
    Phonon::PausedState 暂停状态
    Phonon::ErrorState 错误状态

    创建一个类,继承自其他的部件,在继承中会默认继承与 QWidget 等系统顶级窗口,则需要改变其中的继承基类,才能随心所欲
    1.包含那个想要继承的部件的 头文件 例:
    2.在.h 文件中更改继承自 基类那个类
    3.在.cpp 中 更改继承的那个就好了
    例:
    class MyPlaylist : public QWidget //这里继承改一下
    {
    Q_OBJECT
    public:
    explicit MyPlaylist(QWidget *parent = 0);
    signals:
    public slots:
    };
    MyPlaylist::MyPlaylist(QWidget *parent) : Widget(parent); //这里继承改一下
    这是建立 Class 文件的,更改以后为
    class MyPlaylist : public QTableWidget //这里继承改一下
    {
    Q_OBJECT
    public:
    explicit MyPlaylist(QWidget *parent = 0);
    signals:
    public slots:
    };
    MyPlaylist::MyPlaylist(QWidget *parent) : QTableWidget(parent);

    获取媒体源中的元数据
    MediaObject 中的 metaData() 函数获取媒体源中的元数据

  38. 部件大集合
    在部件中 一般都继承自 QWidget ,只有layout布局 spacers弹簧

    object 对象 值
    objectName 对象名字 weidget 可随意更改的 在设计师中

    QWidget 小部件

    windowModality 窗口模式 NoModel 非模态窗口
    WindowModal 模态窗口,对应于父窗口,及祖父窗口,和相关的兄弟窗口
    APPlicationModal 模态窗口,对应于应用程序,所以的窗口

    enabled 激活的;可行的 ture 激活
    false 不激活

    gemetry 几何学 x,y,width,height 起始宽,高坐标,宽,高

    sizePolicy 控件在布局管理中的缩放方式 水平策略,垂直策略,水平伸展,垂直伸展等
    QSizePolicy::Fixed widget 的实际尺寸只参考 sizeHint() 的返回值,不能伸展(grow)和收缩(shrink)
    QSizePolicy::Minimum 可以伸展和收缩,不过sizeHint() 的返回值规定了 widget 能缩小到的最小尺寸
    QSizePolicy::Maximum 可以伸展和收缩,不过sizeHint() 的返回值规定了 widget 能伸展到的最大尺寸
    QSizePolicy::Preferred 可以伸展和收缩,但没有优势去获取更大的额外空间使自己的尺寸比 sizeHint() 的返回值更大
    QSizePolicy::Expanding 可以伸展和收缩,它会尽可能多地去获取额外的空间,也就是比 Preferred 更具优势
    QSizePolicy::MinimumExpanding 可以伸展和收缩,不过sizeHint() 的返回值规定了 widget 能缩小到的最小尺寸,同时它比 Preferred 更具优势去获取额外空间

    minimumSize 最小尺寸 长,宽
    maximumSize 最大尺寸 长,宽

    sizelncrement

    baseSize 底座尺寸

    palette 调色版 设置窗体的颜色
    QPalette::window 窗口颜色
    QPalette::Background 背景颜色
    QPalette::Button
    QPalette::Light 光
    -----------

    font 字体 可以调节字体 字体大小 粗细 斜不斜等等

    cussor 光标 使用枚举类型,选用光标

  39. 部件精讲
    控件类 控件名 中文名
    QGroupBox GroupBox 组合框
    QScrollArea ScrollArea 滚动区
    QToolBox ToolBox 工具箱
    QTabWidget TabWidget 切换卡
    QWidgetStack WidgetStack 控件栈
    QFrame Frame 框架
    QWidget Widget 组件
    QMdiArea MdiArea MDI窗口显示区
    QDockWidget DockWidget 停靠窗口

  40. 自定义控件外观
    Qt提供了3种方式自定义空间的外观:样式表 QStyle QPalette 自定义控件的使用有两种方式:提升法和插件法。提升法的优点是配置简单,缺点是在designer中不能使用自定义的属性和方法。插件法的优点是在designer中可以灵活使用,但是需要编译,配置复杂,涉及32bit/64bit的不同版本就更麻烦了。
    目前我接触的应用场景,通过样式表+提升法的结合已经可以满足绝大部分需求。将常用的自定义控件总结在这,用于参考。

    / ------------------------------------------------------ QStyle 的使用 ------------------------------------------------------ /
    Qt中的风格继承自QStyle的类,这个类为一个抽象类,封装了一个GUI的外观,Qt的内建部件使用它来执行几乎所以的绘制工作,有很多种风格,例如
    微软平台上一个样,Linux平台上又是一个样的哈!

    使用不同风格运行程序:
    #include
    主程序中:
    QApplication a(argc, argv);
    a.setStyle(new QMotifStyle); 这种设置整个程序都会改变
    想要改变程序中某个部件的可以单独使用
    例:ui->prograssBar->setStyle(new QWindowsXpStyle); 这种方法就可以改其中的某个指定的部件了
    使用 QStyleFactory::keys() 函数可以获得当前系统所支持的风格,除了Qt自己提供的风格外,还可以自定义子类化Qt的风格类,或者子类化QStyle

    qDebug() << QStyleFactory::keys() << endl; //Factory 制造厂长 keys关键点
    窗口显示:(“Windows”, “WindowsXP”, “WindowsVista”, “Motif”, “CDE”, “Plastique”, “Cleanlooks”) 我电脑支持的风格

    / ------------------------------------------------------ QPalatte ------------------------------------------------------ /
    调色板:包含部件各种状态的颜色组。一个调色板3种状态:激活 Active 失效Diaabled 非激活 Inactive
    Qt中所以部件都包含一个调色板,并且使用各自的调色板来绘制他们自身,
    调色板中的颜色组:
    激活颜色组 QPalatte::Active 用于获得键盘焦点的窗口
    非激活颜色组 QPalette::Inactive 用于其他的窗口
    失效颜色组 QPalatte::Disabled 用于由于一些原因而不可用的部件
    改变整体程序的调色板
    QApplication::palette() 可以获取其调色板本
    QApplication::setPlalette() 更改这个调色板,会影响到该程序的所有窗口部件

    改变部件的调色板
    //获取 pushButton 的调色板
    QPalette button_platte = ui->pushButton->palette();
    qDebug() << button_platte << endl;
    //设置这个调色板 的文字颜色
    button_platte.setColor(QPalette::ButtonText,Qt::red);
    //设置按钮背景为绿色
    button_platte.setColor(QPalette::Button,Qt::green);
    //然后修改他的调色板
    ui->pushButton->setPalette(button_platte);
    //设置lineEdit不可用
    ui->lineEdit->setDisabled(true);
    QPalette line_palette = ui->lineEdit->palette();
    //设置行编辑器不可用时的背景颜色为蓝色
    line_palette.setColor(QPalette::Disabled,QPalette::Base,Qt::blue);
    ui->lineEdit->setPalette(line_palette);
    注意:设置颜色时用的 setColor 函数,这个函数肚需要指定颜色角色(colorRole),在QPalette中,颜色角色决定对谁起作用
    主要的颜色角色有:
    QPalette::weindow 一个一般的背景颜色
    QPalette::windowText 一个一般的前景颜色
    QPalette::Base 一般用于输入部件的前景色,也可QComboBox 的下拉列表的前景色等
    – AlternateBase 在交替行颜色的视图中作为交替背景色
    – ToolTipBase 作为QToolTip和QWhatsThis的背景色
    – ToolTipText 作为QToolTip和QWhatsThis的前景色
    – QPalette::Text 和Base 一起使用,作为前景色
    – QPalette::Button 按钮部件背景色
    – QPalette::ButtonText 按钮部件前景色

    / ------------------------------------------------------ 样式表 ------------------------------------------------------ /
    Qt样式表是一个可以自定义部件外观的十分强大的机制,Qt样式表的起源来自于 HTML 的层叠样式表的启发,不过与CSS不同的是,Qt样式表应用
    于部件的世界。

    样式表使用文本描述,可以使用 QApplication::setStyleSheet() 函数讲其设置整个应用程序上,也可以使用 QWidget::setStyleSheet() 函数将其设置
    到一个指定的部件上,如果在不同的级别都设置了样式表,那么Qt会使用所有的样式表,这被称为样式表的层叠

    //设置整个应用程序都为 黄色的
    QApplication a(argc, argv);
    a.setStyleSheet(“background:yellow;”);

    //设置整个顶级部件的背景色都为黄色,其中的子部件 也会随着 父部件变化的
    this->setStyleSheet(“background:yellow;”);

    //设置 pushbutton_2 的背景为黄色
    ui->pushButton_2->setStyleSheet(“background:yellow”);
    //设置 horizontalSlider 的背景为蓝色
    ui->horizontalSlider->setStyleSheet(“background:blue”);
    这是设置单个指定部件 单个设计

    //设置 QPushButton 和 horizontalSlider
    this->setStyleSheet(“QPushButton{background:yellow}”
    “QSlider{background:blue}”);
    这是设置单个类型部件的 单个设计

    //再设计模式中使用样式表: 这个也可以这么弄
    Qt样式表语法:Qt样式表语法规则与 HTML CSS基本相同;
    – 样本规则
    样式表包含一系列的样本规则,一个样式表规则由一个选择符(selector)和声明(declaration)组成,选择符指定了授该规则影响的部件,声明指
    定了这个部件上要设置的属性
    QPushButton{ color : red}
    QPushButton 是选择符,{color : red} 是声明,而color是属性,red是值
    这个规则指定了 QPushButton 和它的子类应该使用红色作为他们的前景色。Qt样式表一般不区分大小写,例如:color,COLOR,COlor等等表示
    相同的属性,只有类名,对象名和Qt属性名是区分大小写的,一些选择符可以指定相同的声明,只需要使用逗号隔开
    QPuhsButton,QLIneEdit,QComboBox{color:red}
    QPushButton{color : red ;background - color:white};
    可以在 Qt Style Sheet Reference 关键字对应的文档中的 Lisr of Properties 一项中查看 Qt 样式所支持的所以属性

    选择符类型
    *														所有部件
    QPushButton									匹配所以QPushButton 的实例和它的所以子类
    QPushButton[flat = "false"]			匹配 QPushbutton 的属性 Flat 为 false 的实例
    ..................
    

    – 子控件:一些复杂的部件修改样式可能需要访问他们的子控件,例如 QComboBox 的下拉按钮
    QComboBox::drop-down{ image:url(dropdown.png)}
    这样的规则可以改变所以 QComboBox 部件的下拉按钮的样式

    – 伪装态
    选择符可以包含伪装态来限制规则在部件的指定的状态上应用。伪装态出现在选择符之后,用冒号隔离
    QPushButton:hover{color:white} //hover 盘旋
    这个规则表明当鼠标悬停在一个QPsuhButton 部件上时才被应用,伪装态可以用 感叹号表示否定,例如当鼠标没有悬停在 QRadioButton上
    时的
    QRadioButton :! hover{color:red}
    伪装态还可以连用
    QCheckBox:hover:checked{color:white} 也可以
    QCheckBox : hover , QCheckBox : checked { color:white }

    –冲突解决
    当几个样式规则对相同的属性指定了不同的值时就会发生冲突时,特使的选择优先,如果特殊性相同,则后来者居上
    QPushButton# okButton{ color:gray }
    QPushButton{ color:red }

    – 层叠
    如果没有属性冲突,则 QApplication 与 部件祖先样式表 部件样式表 合并得到的。
    冲突时:优先级为 部件的 -> 祖先的 -> QApplocation 的

    / ------------------------------------------------------ 自定义部件外观与换肤 ------------------------------------------------------ /
    Box 模型
    当使用QSS时,每个widget都被看做是一个具有四个同心中心矩形的box模型: 从外到内的矩形为
    margin 矩形 边缘
    border 矩形 边框
    padding 矩形 内边距,填充,填衬
    content 矩形 内容,整个页面
    初始时,他们默认都为0,所以其4个矩形重合在了一起的

    QMainWindow
    {
    background-image:url(:/new/prefix1/battle_scene_frame_element.earth.png);
    }
    QPushButton{
    background-color:rgba(100,200,100,30);
    border-style:outset;
    border-width:4px;
    border-radius:10px;
    border-color:rgba(255,255,255,30);
    font:bold 14px;
    color:rgba(0,0,0,100);
    padding :6px;
    }
    QPushButton:hover
    {
    background-color:rgba(100,255,100,100);
    border-color(255,255,255,200);
    color:rgba(0,0,0,200);
    }

    – Qt样式表可以存放在一个以 .qss 为后缀的文件中,这样就可以在程序中调用不同的 .qss 文件来实现换肤的功能。下面在前面的程序中添加新文件,
    模板选择“General 中的 Empty File, 名称为 **.qss 。建立完成后,将写好的样式表放入到其中 然后 Ctrl+s 保存,既可以了
    – 然后,将.qss文件 加入到资源文件中,在资源文件中,新建立前缀 /qss(只是为了将文件区分开),然后添加资源文件 **.qss
    – 正常和图片资源调用是一样的了,现在
    – 使用样式表
    #Include
    QFile file( " qss 资源文件的位置 "); -<直接复制过去就行
    file.open(QFile::ReadOnly); //只读方式打开文件
    QString styleSheet = tr(file.readAll()); //读取文件全部内容,使用tr函数将其转换为 QString 类型
    qApp->setStyleSheet(styleSheet); //为其QApplication 设置样式表

    void Widget::on_pushButton_clicked() //利用信号与槽实现换肤的功能,其实现与上面是一致的
    {
    QFile file1(":/qss/myl.qss");
    file1.open(QFile::ReadOnly);
    QString styleSheet1 = file1.readAll();
    qApp->setStyleSheet(styleSheet1);
    }

    由此可以看出 然和文件都可以,只要是 .qss结尾的就 ok,不放在程序的资源文件中也可以,也可以放在其他的地方的

  41. Item widget 项目小部件
    Qt界面设计中有model-based的List View,有Item-based的List Widget,关于这2者到底有什么区别,暂时也没弄太明白,这些都是界设
    计中的设计模式,从MVC发展而来。以后用到的时候自然会明白的。
    一般简单的都是用Item-based的List Widget,Qt中给出了List Widget,Tree Widget,Tabel Widget三种,这里就简单了解一下List Widget和Tree Widget的使用。Tabel Widget的使用应该也类似。

    list widget列表小部件
    List WidgetList Widget的使用比较简单,加入数据时直接用addItem()函数。读取数据时采用currentItem->text()方法。
    例子:
    QListWidget 和 QListWidgetItem 类基本一起使用,将item 放入其中,然后可以对item项进行操作

    QTreeWidget 的使用也需要,另一个辅助类 QTreeWidgetItem 一起使用,它与listWidget是一样的

    QTableWidget 一般也是有辅助类,相辅想成的,QTableWidgetItem 类;
    tableWidget.setParent(this);
    tableWidget.setColumnCount(3);
    tableWidget.setRowCount(5);

    QStringList headers;
    headers << “ID” << “Name” << “Age” << “Sex”;
    tableWidget.setHorizontalHeaderLabels(headers); //水平标题栏标签
    tableWidget.setItem(0,0,new QTableWidgetItem(QString(“0001”)));
    tableWidget.setItem(1,0,new QTableWidgetItem(QString(“0002”)));
    tableWidget.setItem(2,0,new QTableWidgetItem(QString(“0003”)));
    tableWidget.setItem(3,0,new QTableWidgetItem(QString(0004)));
    tableWidget.setItem(4,0,new QTableWidgetItem(QString(“20110112”)));

  42. 2D绘图
    drawArc() 绘制圆弧
    drawChord() 绘制弦
    drawConvexPolygom() 绘制多边形
    drawEllipse() 绘制椭圆
    drawLine() 绘制线条
    drawPie() 绘制扇形
    drawPoint() 绘制点
    drawPolygon() 绘制多边形
    drawpolylin() 绘制折现
    drawRect() 绘制矩形
    drawRoundedRect 绘制圆角矩形

    / ------------------------------------------------------ QPen + QBrush ------------------------------------------------------ /
    QPainter painter;
    painter.begin(this);
    painter.drawLine(QPoint(0,0),QPoint(100,200)); //画一个普通的线,有默认的画笔和画刷

    QPen pen(Qt::green,5,Qt::DotLine,Qt::RoundCap,Qt::RoundJoin); //定义了一个画笔
    QPen pen2(Qt::red,5,Qt::DotLine,Qt::SquareCap,Qt::MiterJoin); //定义了第二个画笔
    // QPen pen2(const QBrush,qreal width,Qt::PenStyle style,
    // Qt::PenCapStyle cap,Qt::PenJoinStyle);
    // 几个参数依次为:画刷,线宽,画笔风格,画笔端点风格,画笔连接风格
    // 也可以使用 setBrush(),setWidth…等等为其设置

    painter.setPen(pen2); //为画家 换上一直画笔
    QRectF rectangle(70.0,40.0,800.0,400.0); //rectangle 矩形 长方形 //定义一个 矩形长方形用于辅助
    int startAngle = 1016; //10 是水平逆时针起始角度
    int spanAngle = 160
    16; //120 是逆时针旋转以后的角度
    painter.drawRect(rectangle); //查看辅助矩形的样子,可有可无
    painter.drawArc(rectangle,startAngle,spanAngle); //利用辅助的矩形,画一个圆弧
    //这里的3个参数分别对应弧线所在的矩形,起始角度和跨越角度,最后得到图形数
    //两射线与 一条弧形组成的扇形,弧的长为矩形的长,弧的宽为矩形的宽

    pen.setWidth(1); //设置画笔宽度
    pen.setStyle(Qt::SolidLine); //风格
    painter.setPen(pen);
    //更改画笔属性,然后在交给画家
    painter.drawRect(160,20,50,40); //然后画出一个矩形来,可以根据那个辅助的话
    //绘制矩形
    QBrush brush(QColor(0,0,255),Qt::Dense4Pattern); //定义画刷,颜色,还有系统的纹理样式
    //创建画刷
    painter.setBrush(brush); //使用画刷
    painter.drawEllipse(220,20,20,50); //绘制一个圆形
    brush.setTexture(QPixmap(":/new/prefix1/background (7).png")); //利用图片 给画刷 设置纹理
    painter.setBrush(brush); //更改画刷属性后,从新给画家
    static const QPointF points[4] =
    {
    QPointF(270.0,80.0),
    QPointF(290.0,10.0),
    QPointF(350.0,30.0),
    QPointF(390.0,70.0)
    };
    painter.drawPolygon(points,4); //绘制多边形
    painter.fillRect(QRect(10,100,150,20),QBrush(Qt::darkYellow)); //使用画刷快速填充和使用一个矩形
    painter.eraseRect(QRect(50,0,50,120)); //擦除一个矩形区域的内容,所以东西都被擦除

    painter.end();

    注意:只有封闭的空间,才能显示出 画刷的作用

    / ------------------------------------------------------ QGradient + QBrush ------------------------------------------------------ /
    // Gradient 渐变
    Qt 现在 支持 有三种渐变
    linear gradient : 线性渐变
    radial gradient : 辐射渐变
    conial gradient : 锥形渐变

    //线性渐变,构造函数中(开始点,结束点)
    QLinearGradient linearGradient(QPointF(40,190),QPointF(70,190));

    //插入颜色,将两点直接的区域进行等分,开始点的位置为0.0,结束点的位置为1.0
    linearGradient.setColorAt(0,Qt::yellow); //在哪个地方设置颜色 at,在,向
    linearGradient.setColorAt(0.4,QColor(255,0,0));
    linearGradient.setColorAt(1,QColor(0,255,0));
    linearGradient.setSpread(QGradient::ReflectSpread);
    //这个的设置填充的扩散方式,即指明在指定区域以外的区域怎样填充有三种方式
    //QGradient::ReflectSpread 在渐变外反射渐变
    //QGradient::PadSpread 使用最接近的颜色进行填充,默认值
    //QGridient ::RepeatSpread 重复渐变填充
    //Spread 传播 ReflectSpread反应了传播
    painter.setBrush(linearGradient); //使用渐变作为画刷,已前的是使用画刷作为画刷
    painter.drawRect(10,170,90,40);

    //辐射渐变 构造函数中,指定圆心,半径,焦点(该点向外扩散)
    QRadialGradient radialGradient(QPointF(200,190),50,QPointF(270,200));
    //焦点位置为0,圆环位置为1,在焦点位置和圆环位置插入颜色
    radialGradient.setColorAt(0,QColor(255,255,100,150));
    //QColor::QColor(int r,int g,int b,int a=255)
    //前三个值是rgb 最后的是 alpha通道,用来设置透明度的;
    radialGradient.setColorAt(1,QColor(0,0,0,50));
    painter.setBrush(radialGradient);
    //设置画刷以后,弄出个圆来
    painter.drawEllipse(QPointF(50,150),50,50);

    //锥形渐变 构造函数(指定中心点center,和一个角度angle:0~360之间)
    QConicalGradient conicalGradient(QPointF(350,190),60);
    conicalGradient.setColorAt(0.2,Qt::cyan);
    conicalGradient.setColorAt(0.9,Qt::black);
    painter.setBrush(conicalGradient);
    painter.drawEllipse(QPointF(350,190),50,50);

    //画笔使用线性渐变来绘制直线和文字
    painter.setPen(QPen(linearGradient,2));
    painter.drawLine(0,280,100,280);
    painter.drawText(150,280,tr(“HelloQt”));
    //综上可看出:渐变就是自定义画刷而已

    / ------------------------------------------------------ 坐标系统 ------------------------------------------------------ /
    Qt的坐标系统是由QPainter类控制的,QPainter的逻辑坐标与绘图设备的物理坐标之间的映射由QPainter的变换矩阵,视口和窗口处理。逻辑坐标
    和物理坐标默认是一致的
    抗锯齿绘图(反锯齿或者反走样),对图形的边缘进行平滑处理,使其看起来更加柔顺流畅的一种功能
    QPainter::RenderHint //呈现提示
    QPainter::Antialiasing //指定绘图引擎在可能的情况下应该进行边缘的抗锯齿
    QPainter::TextAntialiasing //指定绘图引擎在
    QPainter::SmoothPixmapTransfrom //指定绘图设备使用一个平滑pixmap转换算法而不是临近插值算法

    在默认情况下绘制会产生锯齿:
    当使用宽度为一个像素的画笔进行绘制时,像素会在数学定义的点的右边和下边进行绘制 比如说 drawRect(10,10,10,10);
    画出一个正方形后,会 煲起来 99的位置 而不是 1010,被画笔宽度占去了一个格子
    当使用一个拥有偶数像素的画笔进行渲染时,像素会在数学定义点的周围进行渲染
    当使用一个拥有奇数像素的画笔进行渲染时,像素会被渲染到数学定义的点的右边和下边

    如果在绘制时使用了抗锯齿渲染提示,即使用 QPainter::setRenderHint(RenderHint,bool on = true)
    painter.setRendHint{QPainter::Antialiasing}; 将实现抗锯齿功能,就和 ps 那里的图形显示是一样的!
    像素会在数学定义的点的两侧对称地进行渲染!

    / ------------------------------------------------------ 坐标系统 ------------------------------------------------------ /
    深入研究坐标系统:
    在2D绘图中,存在着,两种坐标系统:物理坐标和逻辑坐标
    逻辑坐标:比如现在有一个手机150x50mm,或者一个图片800x600像素,又或者一个房子占地30x6米。这是具体的,与显示设备无关的单位。
    描述这些内容的坐标系称为逻辑坐标系。因为眼睛看不来那么多东西,所以你还会有一个特别关注的地方,比如说一幅上百米的清明上河图,你
    要是拉远了就可以看到全部,拉近了就只能看到几个人的画像。描述你需要关注的这个部分矩形就是窗口,决定了你需要显示的内容。
    物理坐标:这是一个以像素为基本单位进行描述的设备。比如说1024x768分辨率的显示器,或者说一个100x200像素的QWidget。那么描述这种环境
    的坐标系就是物理坐标系。要正确显示的话,程序需要知道的也是两个方面的东西,你在设备环境的什么地方,以多大的范围给你显示出来。
    逻辑坐标系:原点正右:x轴正半轴 , 原点正上:x轴上半轴
    物理坐标系:原点正右:x轴正半轴 , 原点正上:x轴下半轴

    / ------------------------------------------------------ 平移,缩放,旋转 ------------------------------------------------------ /
    QPainter painter(this);
    painter.fillRect(rect(),QColor(255,255,255,255));
    //填充整个窗口,背景为白色
    painter.setPen(QPen(Qt::red,11));
    painter.drawLine(QPoint(5,6),QPoint(100,99));
    //绘制直线
    painter.translate(200,150);
    // 将坐标原地进行平移,使(200,150)点作为原点(0,0)
    // 想要将原点变回来,就得使用反向平移了 painter.translate(-200,-150)
    painter.setRenderHint(QPainter::Antialiasing);
    painter.drawLine(QPoint(5,6),QPoint(100,99)); //绘制直线
    painter.save(); //保存painter的状态
    painter.rotate(90); //将坐标系统旋转90度
    painter.setPen(Qt::cyan); //青色
    painter.drawLine(QPoint(5,6),QPoint(100,99)); //重绘图,不会重合,直线被旋转了90度,根本原因来自坐标系统的旋转
    painter.restore(); //将保存的画笔属性释放出啦
    painter.drawLine(QPoint(35,6),QPoint(100,99)); //重绘图

    painter.setBrush(Qt::darkGreen);
    //绘制一个矩形
    painter.drawRect(-50,-50,100,50);
    painter.save(); //画笔保存以后,其后的printer属性还以它的基础上添加
    //将系统坐标进行缩放
    painter.scale(0.5,0.4); //水平方向,和垂直方向的缩放倍数,进行缩放的时候 使用的
    painter.setBrush(Qt::yellow);
    //重新绘制相同的矩形
    painter.drawRect(-50,-50,100,50);
    painter.restore(); //画笔恢复后,其后的priter属性将会展现出,它保存之时的效果

    painter.setPen(Qt::blue);
    painter.setBrush(Qt::darkYellow);
    //绘制一个椭圆
    painter.drawEllipse(QRect(60,-100,50,50));
    //将系统坐标进行扭曲
    painter.shear(1.5,-0.7); //水平方向,和垂直方向的扭曲值
    painter.setBrush(Qt::darkGray);
    //重新绘制相同的椭圆
    painter.drawEllipse(QRect(60,-100,50,50));

    / ------------------------------------------------------ 逻辑坐标与物理坐标 ------------------------------------------------------ /
    QPainter painter(this);
    painter.setWindow(-50,-50,100,100); //设置逻辑坐标
    //现在逻辑坐标的(-50,-50)点对应界面左上角的(0,0)点,而且因为逻辑坐标矩形宽度为
    //100,100 所以界面上的宽度和高度都会被分为100等分
    painter.setBrush(Qt::green);
    painter.drawRect(0,0,20,20);

    / ------------------------------------------------------ 绘制字体 ------------------------------------------------------ /
    QPainter::drawText() 函数来绘制文字
    QPainter::setFont 函数来设置文字
    两种方法,我认为用的 都不是特别多

    / ------------------------------------------------------ 绘制路径 ------------------------------------------------------ /
    若绘制复杂的图形,尤其是重复绘制这样的图形,可以使用 QPainterPath 类,并使用 QPainter::drawPath() 进行绘制
    路径可以说封闭的,也可以是不封闭的

    QPainter painter(this);
    QPainterPath path;
    //移动当前点到点(50,250)
    path.moveTo(50,250);
    //从当前点即(50,250)绘制一条直线到点(50,230),完成后 当前点更改为(50,230)
    path.lineTo(50,230);

    path.cubicTo(QPointF(105,40),QPointF(115,80),QPointF(120,60));
    path.lineTo(130,130);
    //向路径中添加一个椭圆
    path.addEllipse(QPoint(130,130),30,30);
    painter.setPen(Qt::darkYellow);
    //绘制路径
    painter.drawPath(path);
    //平移坐标系统后重新绘制路径
    path.translate(200,0);
    painter.setPen(Qt::darkBlue);
    painter.drawPath(path);

    可以使用 lineTo(),arcTo(),cubicTo()和quadTo() 等函数将直线或者曲线 添加到路径中,
    还可以使用 addEllipse(),addPath,addRect(),addRegin()等,向路径中添加一些图片或者文字

    填充规则:
    Qt::OddEvenFill 使用奇偶填充规则,具体,如果要判断一个点是否在图形中,那么可以从该点向图形外引一条水平线,如果该水平线与图形的焦点的
    个数为奇数,那么就在图形中
    Qt::WindingFill 使用的非零弯曲规则。。。。。。。。

    / ------------------------------------------------------ 绘制图像 ------------------------------------------------------ /

    / ----------------------------------------------------- 双缓冲绘制 ------------------------------------------------------ /
    所谓双缓冲绘制,就是在进行绘制时,先将所以内容都绘制到一个绘图设备上,然后在将图形绘制到部件上显示出来,使用双缓冲绘图可以避免显示
    时的闪烁现象,在Qt4以后 都已经自动实现了双缓冲技术,但在其它的地方可以

  43. 进程和线程
    进程:
    Qt 的 QProcess类用来启动一个外部程序并与其进行通信,要启动一个进程,可以使用start()函数

    线程:
    QTread 继承自QObject,发射信号来告知线程的开始和结束执行等状态,QObject可以在多线程中使用发射信号来调用其他线程中的槽,可以向其他
    线程中的对象发送事件,这些之所以成为可能,这些之所以成为可能,因为每个线程都允许有自己的事件循环。
    QObject是可以重入的,重入的意思是在多个线程中可以同时使用这些类
    拥有跨线程的信号和槽
    QThread 类提供了与平台无关的线程,一个QTread代表了一个在应用程序中可以独立控制的线程,他与进程中的其他线程分享数据,但是是独立执行的;
    其从run() 函数开始执行,默认 run() 通过exec() 来开启事件循环,从run函数开始执行的

    创建线程有两种方式:
    – 重写QTread类:
    – 调用函数 QObject::moveToThread() 函数:
    void run(); 虚函数 当Tread实例以后,调用statrt函数将会默认的调用 run这个函数,因为run是虚函数,需要重写嘛
    void stop(); 使用从run中退出的函数
    线程对象调用 isRunning() 来判断线程是否运行
    void MyTread::run() 重写的虚函数
    {
    qreal i = 0;
    while(!stopped)
    {
    qDebug() << QString (“in MyTread:%1”).arg(i);
    msleep(1000);
    i++;
    }
    stopped = false;
    }
    void MyTread::stop() 用来停止进程用的
    {
    stopped = true;
    }

    同步线程:
    Qt 中的 QMutex,QReadWriteLock 提供了同步线程的方法,虽然使用线程的思想是多个线程可以尽可能的并发执行,但是总有一些时刻,一些
    线程必须停止下来等待其他的线程,例如两个线程尝试同时访问相同的全局变量
    互斥锁:
    读-写锁:

48.图形视图,动画和状态机框架
QGraphicsScene 场景
QGraphicsViev 图形
QGraphicsItem 图形项

QGraphicsScene 场景:提供了图形视图框架中的场景
提供用于管理大量图形项的告诉接口
传播事件到每一个图形项
管理图形项的状态,比如选择和处理焦点
提供无变换的渲染功能,主要用于打印
场景是图形项QGradhicItem对象的容器
场景可以告诉我们那些项是重叠的,哪些是被选取的,以及哪些是在一个特定的点处,或者在一个特定的区域内!
一个场景分为3层:图形项层,前景层,背景层:场景的绘制首先从背景层开始,然后是图形项层,最后是前景层

/ ----------------------------------------------------- 视图 ------------------------------------------------------ / 	
QApplication app(argc,argv);
//新建场景
QGraphicsScene scene;
//创建矩形图形项目
QGraphicsRectItem *item = new QGraphicsRectItem(0,0,100,100);
//将图形项加到场景中
scene.addItem(item);
//输出(50,50)点处的图形项
qDebug() << scene.itemAt(50,50,QTransform());

QGraphicsView view(&scene);
//为场景创建视图
scene.setForegroundBrush(QColor(255,255,0,100));
//设置场景的前景色
view.setBackgroundBrush(QPixmap(":/new/prefix1/5993edf46d3fb.jpg"));
//设置场景的背景图片
//的绘制总是从背景层开始的,背景,前景,图形项层
//为场景设置 三层,则所以视图项都会实现,若是,为其中一个视图项设置,则只会显示在那个
//图形上
view.resize(400,300);
view.show();

QGraphicsView view2(&scene);
view2.resize(400,300);
view2.show();
return app.exec();

QGraphicsView 视图:提供了视图部件,可以连接多个部件视图到同一个场景来为相同的数据集提供多个视口
setDragMode(0 )
视图从键盘或者鼠标接受输入事件,然后会在发送这些事件到可视化的场景之前将他们转换为场景事件(将坐标转化为合适的场景坐标)

QGraohicsItem 是场景中图形项的基类。图形项视图框架为典型的形状提供了标准的图形项,比如矩形(QGraphicsRecctItem)
椭圆(QGraphicsEllipseItem) 和文本项 (QGraphicsTextItem),最重要的是能够自定义
鼠标按下,移动,释放,双击,悬停,滚动和右击菜单事件;
键盘输入焦点和键盘事件
拖放事件
分组
碰撞事件

图形项还可以存储数据,可以使用 setDate()进行数据存储,然后使用 data() 获取其中的数据。
要进行自定义的图形项绘制的时候,需要进行两个 虚函数的重写:
boundingRect();		前者用来返回要绘制图形项的矩形区域,所有的绘图操作都必须限制在图形项的边界矩形之中
paint();						后者用来执行实际的绘图操作,
这个函数一般会被 QGraphicsView调用,用来在本地坐标中绘制图形项中的内容,painter参数主要是进行绘制的,widget表述的是一种风格.

/ ------------------------------------------------------ 终极坐标系统 ------------------------------------------------------ / 
坐标系统:
图形视图框架3个有效的坐标系统:图形项坐标,场景坐标和视图坐标
进行绘图时,场景坐标对于QPainter的逻辑坐标,视图坐标对应设备坐标

图形项使用自己的本地坐标系统,坐标通常是以它们的中心为原地(0,0),而这也是所以变化的中心,当要创建一个自定义图形时,只需要考虑图形项的
坐标系统,QGraphicsScene和QGraphisView会完成其他所有的变换!

Qt2D绘图的坐标系统分为:物理坐标和逻辑坐标
物理坐标和逻辑坐标默认是一致的
逻辑坐标:与显示设备无关
物理坐标:显示器,打印机,具体的显示控件等等为设备环境
视口:设备环境中的一部分,一个矩形框,使用的单位同设备环境相同
QPainter 类的逻辑坐标和QPainterDevice 的物理坐标间的映射是由QPainter变化矩阵,视图可见区域,和窗体共同来处理

事件处理与传播
图形视图框架中的事件传播途径:	
		视图接受 ->  场景 -> 图形项
同一个场景可以在多个视图中显示		

图形项的坐标
	图形项使用自己本地坐标系统,坐标通常是以它们的中心为原点(0,0),而这也是所有变换的中心,当创建一个自定义图形项目时,只需要考略图形项
	的坐标系统,QGraphicsScene 和 QGraphicsView 会完成其他所有的变换。
	一个图形项在另一个图形项之中,那么被称为子图形项
	
场景坐标:
	场景坐标是所有图形项的基础坐标系统。场景坐标系统描述了每一个顶层图形项的位置,也用于处理所以从视图传到场景上的事件
视图坐标:
	视图坐标就是部件坐标,视图坐标的每一个单位对应一个像素 , 原点(0,0)总在 QGraphicsView 视口的左上角 , 而右下角是(宽 , 高)。
	所有的鼠标事件和拖放事件最初都是使用视图坐标接受的!


QtScript 脚本
  1. Qt随机数
    产生的是一个伪随机数,因为种子的值相同的情况下,函数运行两次产生的随机序列一致,因为种子不变的情况下,随机数就是重复循环的
    获得不同的随机序列,可以使用当前时间作为种子,来进行模拟随机数。因为时间是不断变化的,即种子的值也是不同的,所以产生的随机序列也是不同的。
    第一步:qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); 这一行,就是根据时间去产生种子的代码;
    int QTime::secsTo ( const QTime & t ) const

    第二步:qrand()%10; 产生是个随机数
    如果没有第一步:则种子会自动初始化为 qsrand(1);
    函数返回这个时间到t的秒数(如果t早于这个时间,返回的为负数)。因为QTime只能度量一天之内的时间,而且一天内只有86400秒,
    所以结果就应该在-86400秒和86400秒之间。
    实际上QTime(0,0,0).secsTo(QTime::currentTime())返回的值就是从0到QTime::currentTime()的值。

    随机数由两部分组成:
    随机数种子 qsrand函数获取
    qrand函数 - 播下随机数发生器种子
    当前时间 - 上个时间 = 二者之间的毫秒数
    -> 初始化 -> 随机数种子 -> 生成 -> 随机数

  2. Qt播放音乐的三种方式:QMediaPlayer 和 QSound
    都必须加入模块: QT += multimedia
    player = new QMediaPlayer(this);
    player->setMedia(QUrl::fromLocalFile(str_addr)); //将本地文件加载进去,也可以放网络个歌曲,在这里放入播放连接就可以啦
    player->setVolume(60); //设置音量
    player->play(); //Qt5 中的

    soun = new QSound(str_addr); //将地址加载进去也是 Qt4中的
    soun->play(); //开始唱

    QSoundEffect 是QSound的升级版本,在Qt5中存在的!

    effect = new QSoundEffect(this);
    effect->setSource(QUrl::fromLocalFile(str_addr));
    //effect->setVolume(0.25f); //设置音量的取值范围这个是。
    effect->play();
    effect->setLoopCount(循环次数)

    E:/Books/Qt/CodeShow/MyLove/Music/Music_QiXi.wav // 绝对播放路径 /这样的哈
    ./Music/Music_QiXi.wav // 相对路径播放的 ,构建目录改成相同的那个

  3. Qt播放视频的三种方式:QMovei phonon模块 QMediaOlayer + QVideoWidget + QGraphicsVideoItem + 或者自定义的类

    QMediaOlayer + QVideoWidget + QGraphicsVideoItem 方式的
    player = new QMediaPlayer(this); 创建多媒体播放对象
    videoWidget = new QVideoWidget(this); 创建显示区
    videoWidget->resize(600,300);
    player->setVideoOutput(videoWidget); 在显示区上进行输出
    player->setMedia(QUrl::fromLocalFile(str_addr)); 加载小电影
    player->play();

    QMovie 播放方式:
    QLable label;
    QMovie *movie = new QMovie(“路径”);
    label.setMovie(movie);
    movie->start();
    GIF图片可以放入到 资源文件中哦!
    图片或者GIF自适应部件的大小设置为
    label->setScaledContents(true); 这个是快速的哦,还是 可以的呢!
    一下代码比较冗杂:
    QPixmap *pixmap = new QPixmap(":/images/welcome_tlauto.png");
    pixmap->scaled(ui->label->size(), Qt::KeepAspectRatio);
    ui->label->setScaledContents(true);
    ui->label->setPixmap(*pixmap);

  4. 输入/输出设备
    QIODivice 类是抽象的,无法被实例化的
    在访问一个设备以前,需要使用open() 函数打开该设备,必须指定正确的打开模式
    文件操作:
    文件 QFile
    文件信息 QFileInfo 可以获取文件的大小和最近一次修改 / 读取的时间

    / ----------------------------------------------------- QFile - QFileInfo ------------------------------------------------------ /
    QString str_path = QFileDialog::getOpenFileName(this,“get path:”,"…/");
    QFile file(str_path);
    if(!file.open(QIODevice::WriteOnly | QIODevice::Text))
    {
    qDebug() << file.errorString();
    }
    file.write(“hello n yafe linux”);
    file.close();

    QFileInfo info(file);
    qDebug() << QObject::tr(“绝对路径:”) << info.absoluteFilePath() << endl
    << QObject::tr(“文件名:”) << info.fileName() << endl
    << QObject::tr(“基本名称:”) << info.baseName() << endl
    << QObject::tr(“后缀:”) << info.suffix() << endl
    << QObject::tr(“创建时间:”) << info.created() << endl
    << QObject::tr(“大小:”) << info.size() << endl;

    if(! file.open(QIODevice::ReadOnly | QIODevice::Text))
    {
    qDebug() << file.errorString();
    }
    qDebug() << QObject::tr(“文件内容:”) << endl << file.readAll();
    qDebug() << QObject::tr(“当前位置:”) << endl << file.pos();
    file.seek(0);
    QByteArray array;
    array = file.read(5);
    qDebug() << QObject::tr(“前5个字符:”) << array
    << QObject::tr(“当前位置:”) << file.pos();
    file.seek(15);
    array = file.read(5);
    qDebug() << QObject::tr(“第16-20个字符:”) << array;
    file.close();

    QByteArray 是一个用来存放二进制数据的字节数组!

    文件都是 分三步走的:
    定义文件:指针或者是路径
    open函数打开:C语言就会是函数,C++和Qt会是 成员函数
    进行读写操作(设定读写方式哦!):

  5. 项目制作
    获取系统桌面的大小
    QDesktopWidget* desktopWidget = QApplication::desktop();
    //得到客户区矩形
    QRect clientRect?= desktopWidget->availableGeometry();
    //得到应用程序矩形
    QRect applicationRect = desktopWidget->screenGeometry();

    图形在某个部件上的的大小使用
    QLable 中可以使用 setScaledContents(true);使其自适应大小
    在其他部件中可以使用 setStyleSheet() 中的设置图片,就可以自适应大小啦!

  6. 设置应用程序图标
    两种方法:
    (1). 创建一个应用程序图标
    可以在网上对其格式进行转换 转换为ico格式的
    (2) 将转换好的文件放到源码目录,就是和 pro 同级下的目录就可以了
    (3) 在.pro项目文件中添加一行代码:RC_ICONS = 名字.ico
    一般在 QT += core gui 下一行就可以了
    注意: this->setWindowIcon(“图片路径”); 与本方法不起冲突,如果在程序中有这个函数,其窗口标题和任务栏标题会变成此函数设置的,但是在外面的
    大应用里,或者说是系统上显示的,其会是上面那种设置的(任务管理器及其exe等)。
    第二种方法:
    (1) 项目目录中新建文档目录。改为名字 proj.rc
    (2) 右击以记事本打开 输入以下内容
    IDI_ICON1 ICON DISCARDABLE “名字.ico”
    保存关闭记事本
    (3) 在pro项目文件中添加代码:
    RC_FILE = proj.rc
    编译以后看效果吧! 生成目录下会有一个 proj_res.o的文件,这个是proj.rc资源文件编译后的目标文件
    #################这个直接改的 是大应用里,或者是系统上显示的那种,在打开软件以后和任务栏里是不显示的,需要另外设置
    setWindowIcon 的。

    设置应用程序的名字:
    TARGET = HELLO 等等 这个是已经存在的,想要更改最好是,进去就修改,或者是创建程序的时候注意一下,自己干的是什么事
    当然还有很简单的方法就是:
    在创建成功.exe文件以后,可以手动直接重命名呀!然后其在系统就显示的是重名以后的了

    debug 和 realese 的区别:debug会增加调试代码,方便调试。调试完后,用release版本发布,没有调试代码,减小程序体积,加快执行速度!
    在修改电脑文件后缀时,需要设置显示后缀开启的功能才可以,要不太费劲了

  7. windows 平台下软件打包发布

    1. 程序书写
    2. 使用 release版本 - 构建项目(小锤子标志) //【构建目录最好是将shadow build勾掉:则将会出现在程序代码的路径】 没太大关系,想多了
      【在文件名上 - 右击 : 在Explorer中显示】
      【release 和 debug 同级:注意一下】
    3. 编译执行
      – 在relese 目录下生成 一个文件的 .exe文件 【如果有Qt的环境直接点开 是应该可以跑起来的 - 没有Qt环境是无法跑起来的】
    4. 打来 MinGw 版本号 的控制台(一般在 Qt 4.8.7 Command Prompt下)
      先到:盘符
      然后:cd 到项目所在的目录:
    5. 文字:windeployqt 可执行程序名.exe 回车
    6. 在release文件夹中生成一些固定的文件:在release文件夹中还可以删除一些 原有生成的,除了 .exe文件 都可以删除(这个经过测试,最好是先删除,在
      去生成会更好一些)
    7. 拷贝release文件夹 , 在其他电脑上就可以运行啦!
      ################ windeployqt源码是可以 查看的
  8. 程序最小托盘显示及其操作
    对于GUI程序,如果想要实现当最下化时,程序从任务栏消失,在系统托盘显示一个图标,表示此程序,并能在托盘内通过双击或者菜单使
    程序界面恢复!
    使用类:QSyestemTratIcon
    QSyestemTratIcon 其类是主要操作系统托盘的操作类,通过此类可以在托盘显示指定程序的图标,响应用户鼠标的点击,显示指定消息,显示菜单等
    enum QSystemTray::ActivationReason 表述托盘上图标的触发缘由
    QSystemTrayIcon::DoubleClick 鼠标双击
    QSystemTratIcon::Trigger 鼠标单击
    QSystemTrayIcon::Context 请求系统托盘的上下午菜单
    常用函数:
    void setIcon(const QIcon & icon)
    请求系统托盘的图标
    void setToolTip(const QString &tip)
    设置鼠标放到图标上的提示文字
    void setContexMenu(QMenu *menu)
    设置当前点击图标弹出的菜单
    void show()
    显示系统托盘

    / ----------------------------------------------------- QSystemTrayIcon ------------------------------------------------------ /
    this->hide();
    //新建 QSystemTrayIcon 对象
    mSysTrayIcon = new QSystemTrayIcon(this);
    //新建托盘显示的icon
    QIcon icon = QIcon(":/new/prefix1/icon_hp (2).png");
    //将icon射到QSystemTrayIcon对象中
    mSysTrayIcon->setIcon(icon);
    //当鼠标移动的托盘上的图标时,会显示此处设置的内容
    //这么设置以后,系统上显示的图标就变成了 这个图标了 有点厉害啊
    mSysTrayIcon->setToolTip(QString::fromUtf8(“测试到系统托盘图标”));

    connect(mSysTrayIcon,SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
    this,SLOT(on_activatedSysTrayIcon(QSystemTrayIcon::ActivationReason)));
    //在系统托盘显示此对象
    mSysTrayIcon->show();
    //槽函数,用来实现,点击程序以后进行跳转至此的故事
    void Widget::on_activatedSysTrayIcon(QSystemTrayIcon::ActivationReason reason)
    {
    switch(reason)
    {
    case QSystemTrayIcon::Trigger:
    break;
    case QSystemTrayIcon::DoubleClick:
    this->show();
    break;
    default:
    break;
    }
    }

  9. 实现启动画面

    实现启动界面 , 主要就是使用 QSplashScreen类
    第一种:
    QPixmap pixmap(":/new/prefix1/scene01.jpg");
    QSplashScreen screen(pixmap); //初始化界面 , 使用图片进行的初始化
    screen.show(); //显示
    screen.showMessage(“LOVE”,Qt::AlignCenter,Qt::red); //显示消息

    Widget w;
    w.show();

    screen.finish(&w);
    以上代码为显示图片的: 一晃而逝

    第二种:
    带有延迟功能的显示方式:
    QPixmap pixmap(":/new/prefix1/scene01.jpg");
    QSplashScreen screen(pixmap);
    screen.show();

    a.processEvents();
    //这个 一定要加上这句话,不然程序睡眠,界面不会得到更新。
    //让程序在显示启动画面的同时可以响应其他鼠标事件
    screen.showMessage(“LOVE”,Qt::AlignCenter,Qt::red);

    QDateTime n = QDateTime::currentDateTime();
    QDateTime now;
    do{
    now = QDateTime::currentDateTime();
    }while(n.secsTo(now)<=5);
    //核心延时代码
    screen.finish(&w);

    第三种:
    通过继承QSplashScreen类,得到CMySplashScreen类,然后在其中定义QProgressBar变量,这样就实现进度条的启动界面了
    将这个类从新实现一下 就可以了的,然后根据上面的两个方法任何一种从新创建的!

  10. Qt到Qt5的区别

  11. Qt:windows 下设置指定图片填充形成桌面背景
    QSettings wallPaper(“HKEY_CURRENT_USERControl PanelDesktop”, QSettings::NativeFormat); //格式采用本机格式
    QString path(“c:/users/administrator/desktop/2.png”); //获取图片路径呀
    把注册表的桌面图片路径改为指定路径.
    wallPaper.setValue(“Wallpaper”, path); 值

    QByteArray byte = path.toLocal8Bit();
    调用windows api.
    SystemParametersInfoA(SPI_SETDESKWALLPAPER, 0, byte.data(), SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE);

注册表打开方式:搜索:regedit
注册表是Microsoft Windows中的一个重要的数据库,用于存储系统和应用程序的设置信息。
  1. openGL 开放图形语言
    OpenGL是近几年发展起来的一个性能卓越的三维图形标准,OpenGL实际上是一个开放的三维图形软件包,它独立于窗口系统和操作系统,以它为基础
    开发的应用程序可以十分方便地在各种平台间移植;

  2. 获取桌面框体大小的设置
    // #include
    // QDesktopWidget *desk_top_widget = QApplication::desktop(); //获取系统窗口的长和宽度
    // QRect clintRect = desk_top_widget->availableGeometry(); //给一个宽度模型,任务栏存在
    int width_ = qApp->desktop()->size().width();
    int hight_ = qApp->desktop()->size().height();
    在使用qApp的时候需要有 UI文件,否则不好用的
    //彻底获得系统窗口的属性,比上面那两个跟强烈一些, 低下的任务栏都没有了!

    问题:
    1.QT同时实现通信,界面交互总结
    int main(int argc, char *argv[])
    {
    QApplication a(argc, argv);
    Widget w; //构造界面
    w.show(); //显示界面
    return a.exec();
    }
    当程序执行到show函数时候,实际只是显示了窗口的载体,并没有显示窗口上的任何内容,
    必须等到 a.exec() 语句执行后才能显示,而这个函数其实是调用qApp->processEvent()实现的

    函数原型void QCoreApplication::processEvents(QEventLoop::ProcessEventsFlags flags = QEventLoop::AllEvents) [static]
    这个函数,其实就是一个大循环,等待事件的发生吧!

    对于调用这个接口的线程,会处理所有的等待事件直到这个线程没有事件需要处理了,对于单线程程序,界面相应就是等待事件,界面响应就是等待事件
    ,所以解决方法就是在每一句界面发生变化需要刷新的时候加上这句话

    数据格式:
    读取数据格式:
    可以将一个数据包:一次性收发
    QButerArray ba;
    ba.resize
    这个是用来 接受数据用的
    mySocket->readGategram(ba.data9).ba.lengh,&addr,&port)
    QString msg = QString(ba)
    {
    if(msg.contains(""inlibne:)) //是否有这个东西
    member mb;
    mb.client;
    }

  3. &= 按位与后赋值
    |= 按位或后赋值 a |= b; a = a|b;
    ^= 按位异或后赋值

    checkable 按钮类的成员函数 再这个被设置为真后,其按钮的形状就出现凹槽状,并且不会返回了
    this->setAutoFillBackground(true); //设置自动填充背景

  4. QSocketNotifire 用来监听系统的文件操作,将操作转换为Qt事件进入系统的消息循环队列。并调用预先设置的事件接受函数

  5. QPushButton 中的函数
    setCheckable(true) 表示为可以选中
    setChecked(true) 表示为已经选中
    此属性保存是否选中按钮。
    只能选中可选按钮。默认情况下,该按钮未选中。

  6. 每个页面下都有自己的专属事件!

---------------------------------------------------------------------------------- Qt Quick ------------------------------------------------------------------

  1. Qt Quick 杂烩集合
    Qt Quick是一些新UI技术的集合;
    Qt Quick 是一种高级用户界面技术:
    一个改进的Qt Creater IDE(其中包含了Qt Quick设计器)
    新增的简单易学的 QML语言
    新加入的模块 QtDeclarative的模块
    QML是对 JavaScript的一种扩展
    在QML中,Qml是一个用来描述应用程序的用户界面的声明式语言。一个用户界面被指定为一个拥有属性的对象树,这里各种各样的对象被统称为元素

    ECMAScript 脚本程序设计语言
    脚本语言:
    脚本语言又被称为扩建的语言,或者动态语言,是一种编程语言,用来控制软件应用程序,脚本通常以文本(如ASCII)保存,只在被调用时进行解释或编译。
    API: 系统或应用框架开发出来,给程序员使用的接口 , 就是API,它可以是C函数那样的东西,也可以是C++类,还可以是信号。。。。。
    SDK:software Development Kit: 软件开发工具包,广义上指辅助开发某一类软件的相关文档,源码,范例和工具的集合,比如QT SDK。。。。。。
    对象定义:ECMAScript中没有类的说法,只有对象定义,其实也是创键对象的模板
    Qt Quick是Qt SDK4.7中 引入的一种新的界面开发框架,使用Qt Quick,你可以快速,轻松的创建提供移动和嵌入式设备使用的动态触摸式界面和轻量级应用
    程序,这也是他被命名为Quick的原因
    高度直观:Qt API
    快速上手:Qt 标记性语言 QML
    也可以同时使用他们,后端逻辑使用Qt C++,使用QML开发用户界面

    QML文件的扩展名是 .qml , 语法格式像CSS,但又支持 JaveScript形式的编程控制

  2. 创建新项目
    (1) 打开Qt Creater
    (2) 新建文件或项目
    (3) 应用程序 - Qt Quick Application 模板 : 此模板支持QML和C++混合编程
    (4) 运行项目就可以啦!哈

  3. Qt Quick Designer 和Qt Creater 一个级别的存在
    在QML中存在的 这个是
    元素部件是通过拖拽实现的 - 当选中一个元素时 , 右侧会展现与该元素相关的属性 , 允许编辑他们

    qmlscene 是随着Qt5 发布的一个工具 , 用来加载 QML文档 , 它使得你可以在应用开发过程中随时查看QML代码的效果,它支持下列特性

  4. 代码秀
    imort QtQuick 2.2 这句话是引入 Qtquick 2.2模块,import和C++中的#include 类似都是包含的意思
    Rectangle { 这句话的意思是定义了一个类型为 Rectangle的对象,对象要用 一对花括号来描述,花括号前写上对象的名字
    width : 320; 以下是属性的初始化 , 建议要使用 ; 分开
    height : 480;
    Image {
    source: " image / iMG_001.jpg";
    anchors.centerIn:parent;
    }
    }

    Rectangle {
    width : 2310; 这么弄也是可以的
    height : 6
    80;
    color: “#121212”;
    }

    Button{
    text : “Quit”;
    style:ButtonStyle{
    background : Rectangle{
    implicitWidth : 70;
    implicitHeight : 25;
    border.width : control.activeFocus ? 2:1;
    }
    }
    }
    这个语句定制了一个按钮风格
    control.activeFocus 在表达式中可以引用其他对象及其属性,当你这么做的时候 , 待赋值的属性就和你所引用的对象的那个属性建立了连接,当被引用属性
    发生变化时,表达式的值会重新计算,而待赋值的属性也会变化。

    通过对象的id值来引用一个对象
    Rectangel{
    width:320;
    height:480;
    Button{
    id: openFile;
    text:“打开”;
    anchors.left : parent.left;
    anchors.leftMargin : 6;
    anchors.top : parent.top;
    anchors.topMargin:6;
    }
    }
    Button {
    id : quit;
    text : “退出”
    anchors.left : openFile.right;
    anchors.leftMargin : 4;
    anchors.bottom : openFile.bottom;
    }
    在一个QML文档中,每个对象都可以指定一个唯一的ID,在代码中可以通过这个ID来引用某个对象,访问其属性,方法,这个ID就像是C++的一个具有
    文件作用域的全局变量一样。

  5. 注释
    注释与C++的都是一样的

6 . 属性
对应与我们熟悉的C++中的成员变量
属性命名:一般采用驼峰式命名规则
属性的类型大概有三类:
id属性是唯一的,在一个对象中

  1. 简单程序解析
    QGuiApplication app(argc, argv);
    QQmlApplicationEngine engine; //定义一个实例,代表QML引擎
    engine.load(QUrl(QStringLiteral(“qrc:/main.qml”))); //将文件放进去
    if (engine.rootObjects().isEmpty())
    return -1;
    return app.exec(); //qt应用的主事件循环

    import QtQuick 2.6
    import QtQuick.Window 2.2
    Window { //最大的这个就是 根对象
    visible: true
    width: 640
    height: 480
    title: qsTr(“Hello Qt Quick App”)

     MainForm {														//它是 Window 的孩子
     	color: "#aaaaff"
     	anchors.fill: parent
     	mouseArea.onClicked: {
     		console.log(qsTr('Clicked on background. Text: "' + textEdit.text + '"'))
     	}
     }
    

    }
    一个mian.qml文档可以看出,由两个部分组成:
    imprt 语句。
    QML对象树

    wondow 为根对象的QML文档,QML文档则拥有窗口的完整控制权,可以直接设置标题,窗口尺寸等属性

    属性更改通知:
    Rectangle{
    width:100;
    heiht:100;
    onWidthChanged:console.log(“Width has changed to:”,width);
    onColorChanged:console.log(“Color has changed to:”,color);
    }
    当有属性被更改以后,其就会调用其后的值!

    Qt Quick 本身主要包含了 QML,JavaScript,Qt C++三种技术
    其中主角是 QML , QML的主要作用我理解就是将界面设计与程序逻辑解耦,通常来说前端需求的变动远超后台逻辑,因此界面与
    逻辑分离不仅有利于开发人员之间的分工,也提高了更快速的迭代速度的可能性,也会大大降低程序的后期维护成本。

    QML是一种简单的脚本语言,语法和CSS比较接近,因此学起来相当简单。

  2. anchors.centerIn: parent;
    Anchors 用于指定item相对其它item的关系。这里,我们使用anchro.centerln 将text元素固定到Rectangle的中心

  3. QML 是一种多范式语言,使对象能够根据属性以及如何关联和响应其它对象的更改来定义对象。与纯粹的命令代码相反,属性和行为
    的变化通过一系列逐步处理的语句表达,QML的声明性语法属性和行为更直接集成到单个对象的定义中,这些属性可以包含必要的代码
    ,在情况复杂的定义应用程序是必要的

    QML 文档可以在文件的顶部包含一个或多个 import 语句。一个 import 可以是以下任何一种:

    一个已经注册了类型的版本化命名空间(例如:通过插件)
    一个包含 QML 文档类型定义的相对目录
    一个 JavaScript 文件

    一个对象声明包含:
    对象类型的名称(例如:Rectangle)
    一组花括号{}:紧跟着(对象类型的名称)后
    属性(例如:width)和子对象():在花括号中声明

    Window{
    width: 800;
    height: 800;
    visible: true;

    Rectangle {
    width: 300;
    height: 300;
    color:“lightgray”;

     gradient: Gradient{
         GradientStop{position: 0.0;color: "yellow"}
         GradientStop{position: 1.0;color: "green"}
     	}
     }
     Text {
     	anchors.centerIn: parent;
     	text:"Hello QMl";
     }
    

    }
    这个只是在对象数上的上下级,并非是在视觉场景中的上下文,视觉场景中的父子关系的概念来自QtQuick 模块的item类型提供,
    QtQuick 模块是大多数QML 类型的基本类型,因为大多数QML对象皆在可视化的实现
    可以修改parent熟悉以更改视觉对象,但是对象树的上下文的一个对象不能从QML更改

    opacity: 可以用来设置不透明度

  4. QPro的故事

    告诉 qmake 这是哪种项目,由于构建的是一个应用程序,因此使用 app 模板

    TEMPLATE = app

    声明了要从 C++ 使用的 Qt 库

    QT += qml quick

    构建项目需要一个 C++11 兼容的编译器

    CONFIG += c++11

    列出了应该编译的所有源文件,类似的变量 HEADERS 可用于头文件。

    SOURCES += main.cpp

    告诉 qmake 有一个资源集合,应该被内置到可执行文件中。

    RESOURCES += qml.qrc

  5. 搭建窗口的两种方法:
    第一种:
    QQuickView 是一个基于QWindow的类,能够加载QML文件:
    QQuickView 初始化
    QQuickView view; //创建view对象
    view.setSource(QUrl(QStringLiteral(“qrc:/main.qml”))); //将对象装进去
    view.show(); //就可以显示了

    第二种:
    如果 main.qml 中没有任何图形组件,或者存在其他原因希望避免使用 QQuickView,可以直接构造 QQmlEngine。这种情况下,main.qml 将作为一个 QQmlComponent 实例被加载,而不是被放入一个 view 中:
    QQmlEngine engine;
    QQmlContext *objectContext = new QQmlContext(engine.rootContext());

    QQmlComponent component(&engine, “qrc:/main.qml”);
    QObject *object = component.create(objectContext);

    第三种:
    就是根据创建那种的,直接看看喽!

  6. 可以为QML对象中的属性分配两种类型的值 - 静态值和绑定表达式,后者也称为属性绑定
    静态值:一个不依赖于其他属性的常数值 例如:width:100 , 其中100就是一个静态值
    说白了,和别人没有任何关系的变量就是
    绑定表达式:一个用于描述属性间依赖关系的 JavaScript 表达式

    属性绑定是QML的一个核心特性,运行指定不同对象之间的依赖关系。当属性的依赖项(属性绑定中的变量)的值发生改变时,属性
    将根据指定的关系自动更新。
    属性绑定:简单的解释就是一个绑定表达式,用于描述属性之间的依赖关系。例如:width:parent.width / 2;
    QML引擎时刻监视属性的依赖项,当检测到任何依赖项的值发生改变后,就会自动重新计算绑定表达式,并为属性分配新的结果

    // 访问对象属性
    width: parent.width / 2

    // 使用内置的 JavaScript 对象 Math
    width: Math.min(parent.width, parent.height)

    // 使用三目运算符
    width: parent.width > 100 ? parent.width : parent.width /2

    // if-else 代码块中的 return 关键字可有可无
    width: {
    if (parent.width > 100)
    return parent.width
    else
    return parent.width / 2
    }
    // 调用方法
    height: someMethodThatReturnsWidth()

  7. QML中的信号与槽
    信号:来自QML对象的通知
    信号处理程序:由信号触发的表达式(或函数),也被称为Qt C++中的“槽”。

    import QtQuick 2.3

    Rectangle {
    id: rect
    width: 100; height: 100

     MouseArea {
     	anchors.fill: parent
     	onClicked: {  // 鼠标单击
     		rect.color = Qt.rgba(Math.random(), Math.random(), Math.random(), 1);
    
     		// 访问 mouse 参数
     		console.log("Clicked mouse at", mouse.x, mouse.y)
     	}
     }
    

    }

-------------------------------------- C++ GUI Qt4编程 --------------------------------------

  1. QPainter 的主要设置是画笔,画刷和字体
    画笔用来画线和边缘。它包含颜色,宽度,线性,拐点风格以及连接风格
    画刷用来填充几何形状的图案,它一般颜色和风格组成,但同时也可以是纹理(一个不断重复的图像)或者是一个渐变
    字体用来绘制文字。字体有很多属性,包括字体族和磅值大小
    通过调用:QPen,QBrush或者QFont 对象的 setPen(),setBrush()和setFont()来修改这些设置
    画的图:
    drawPonit() 点
    drawLine() 线
    drawPolyLine() 封装的不规则线,连接的
    drawPonits() 多点
    drawLines 多线,可能不连接
    drawPolygon() 封装的不规则图形
    drawRect() 矩形
    drawRoundRect() 圆角矩形
    drawEllipse() 画椭圆或者是圆
    drawArc() 画弧
    drawChord() 和弦封装图形
    drawPie() 绘制扇形图
    drawText() 绘制文字
    drawPixmap() 绘制图片
    drawPath() 绘制路径
    拐点绘制:有6种方法

    painter.setBrush(QBrush(Qt::blue,Qt::DiagCrossPattern));
    painter.drawPie(80,80,400,240,6016,27016);
    //最好两个参数是以 1/16 度为单位,60为起始度数,270为加的度数 1/16为是加的

    QPainterPath path;
    path.moveTo(80,320); //起点坐标
    path.cubicTo(200,80,320,80,480,320); //下一个点的坐标
    //path.cubicTo(150,150,150,150,150,150); //连接的下一点
    painter.setPen(QPen(Qt::black,8));
    painter.drawPath(path);
    //QPainterPath类可以通过连基本的图形元素来确定任意的矢量形状:直线,椭圆,多边形,弧线,贝塞尔曲线
    //和其他的绘制途径。绘制路径是基本的图元,从这个意义上来说,任何图形或图形组合都可以绘制路径描述
    /*贝塞尔曲线(Bézier curve),又称贝兹曲线或贝济埃曲线,是应用于二维图形应用程序的数学曲线。一般的矢量图形

    • 软件通过它来精确画出曲线,贝兹曲线由线段与节点组成,节点是可拖动的支点,线段像可伸缩的皮筋,我们在绘图工
    • 具上看到的钢笔工具就是来做这种矢量曲线的*/

    三种渐变模式:
    线性渐变:两点之间的颜色渐变
    QLinearGradient gradient(x,y起始点,x,y终止点);
    gradient.setColorAt(0.0 , Qt::white);
    -------------- 0 ~ 1之内就ok的。
    辐射渐变:中心点(x,y),半径r,一个焦点(xf,yf)以及颜色断点定义
    辐射从焦点向外扩散,其渐变范围为 中心到半径的圆
    锥形渐变:一个中心点(x,y) 和一个角度 a 定义 , 像素在中心点周围像钟表的秒针掠过一样扩散

    save(); 存储当前状态
    restore(); 恢复以前状态

  2. 坐标系统变换
    理论上,像素的中心取决于半像素坐标,如果告诉 QPainter 绘制一个像素,例如(100,100),他会相应的在两个方向做 0.5 的偏移,
    使得中心位置在(100.5,100.5);
    不开反走样时才会 偏移0.5; 如果开启反走样了,则会在四个像素的周围着浅灰色,给人的印象是一个像素正好位于

    视口和窗口密不可分,视口是物理坐标系下指定的任意矩形。
    窗口也是指同一矩形,只不过是在逻辑坐标下的
    当绘制图形时,在逻辑坐标下指定的点,这些坐标都是基于当前的窗口 - 视口 并以线性代数的方式转换为物理坐标的
    窗口 - 视口机制对于编写独立于绘制设备大小和分辨率的绘制代码是很有用的,例如,
    第一种方法:
    让 逻辑坐标从(-50,-50) - (+50,+50) , 并且(0,0)在中间,可以这样设置窗口:
    painter.setWindow(-50,-50,100,100);
    (-50,-50)指定了原点,(100,100)指定了宽和高,逻辑坐标(-50,-50)对应物理坐标(0,0),而逻辑坐标(+50,+50)对应物理坐标
    (320,320)
    世界变化:窗口 - 窗口转换之外使用的变换矩阵。它允许移动,缩放,旋转或者拉伸绘制的项,例如想以45度绘制文本,可以使用
    这样代码:

    QTransform transform;
    transform.rotate(45.0);

    transform.translate(50.0,50.0);
    transform.rotate(45.0);
    transform.translate(-200,-200);

    painter.setWorldTransform(transform);
    //painter.drawText(pos,tr(“Sales”));
    painter.drawText(100,20,“HELLO”);
    传递给deawText() 的逻辑坐标会被世界变换转换,然后使用窗口 - 视口设置映射到物理
    如果想要使用点(50,50)作为旋转的中心点,可以移动到窗口到(+50,+50),执行旋转,然后把窗口移回到原来的初始位置。

    坐标变换另一种更为简单的方法:使用QPainter 作家的函数!
    第二种方法:
    painter.translate(-50,-50);
    painter.rotate(45,0);

  3. GStreamer+QT
    GStreamer 多媒体框架

  4. 基于项的视图
    Qt的视图体系包括:QGrapahicsScene充当场景 QGraphicsItem的子类充当场景中的项,场景在视图中显示,这样就可以看大它啦
    它由QGraohicsView类充当
    同一个场景可以在多个视图中显示
    预定义的QGraphicsItem 子类:包括QGraphicsLineItem,QGraphicsPixmapItem,QGraphicsSimpleTextItem(纯文本)
    QGraphicsTextItem(应用与多文本),还可以子自己创建QGraphicsItem的子类
    场景分为三层,背景层,项层,前景层 夹心饼干一样 哈哈
    场景可以告诉我们哪些项是重叠的,哪些项是被选取的 , 以及哪些是在一个特定的点处,或者在一个特定的区域内。场景中的项
    或者是最高层的项(场景就是其父对象),或者是子项(他们的父对象是另外的项),任何应用与项的变换都会自动的应用于子对象。

    视图体系两种分组项的方法:
    使用一个项成为另一个项的子项
    使用QGraphicsItemGroup。
    把一个项添加到组件中不会引起任何变换,这些组可以很方便的处理大量的项,就像他们是一个单独项一样,就是集合在一起了吗
    QGraphcisView 是一个窗口部件,这个窗口部件可以显示场景,在需要的情况下提供滚动条,以及影响绘制方式的变化能力。
    这有利于支持缩放和旋转,帮助游览场景
    视口坐标是 QGraphicsView的坐标 就是物理坐标
    场景坐标是逻辑坐标,用来布置场景中的项
    项坐标针对某一项,并且以(0,0)点为中心。
    在场景中移动项时,项坐标保存不变

    自定义视图项的方法:

    1. 继承自 QGraphicsItem
    2. 重写两个虚函数
      QRectF MyItem::boundingRect() const //返回要绘制图形的矩形区域
      {
      qreal penWidth = 1;
      //定义一个变量,qreal其实就是double类型;而在嵌入设备系统中,qreal则等同于float 类型
      return QRectF(0 - penWidth / 2 , 0 - penWidth / 2,
      20 + penWidth , 20 + penWidth);
      }
      boundingRect() 函数将图形的外部边界定义了一个矩形,所以的绘图操作都必须限制在图形项边界的矩形之中
      void MyItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
      //用来执行实际的绘图操作,painter参数进行一般的绘图操作,参数为图形项提供了一个风格选项,最后一个用来指定父对象
      {
      painter->setBrush(Qt::red);
      painter->drawRect(0,0,20,20);
      }

    三个坐标系统:图形项坐标,场景坐标,视图坐标
    图形项坐标:使用笛卡尔坐标系统,以他们中心为原点,他们所处的位置,如果是在另一个图形项中,它被称为子图形项,而包
    含它的被称为父图形项。没有父图形项的图形项都会在场景的坐标系统中,没称为顶层图形项,使用setPos函数指定位置,若没指定,
    则默认出现为图形项的或场景的原点处。
    子图形项的位置和坐标是相对与父图形项的
    所有的图形项都会使用确定的顺序来进行绘制,这个顺序决定了单击场景时哪个图形项会先获得鼠标输入,默认的,父图形项会被
    最先进行绘制,然后按照顺序对其其上的子图形项进行绘制,其有一个函数 setZValue可以对其顺序进行更改的。

     场景坐标:
     场景坐标的原点在场景的中心,x和y分别是向右和向下增大。,每一个场景中的图形项除了拥有一个图形项的本地坐标和边界坐标
    

    外,还都拥有一个场景坐标(QGraphicsItem::scenePos())和一个场景中的边界矩形(sceneBoundingRect())场景坐标用来描述
    图形项在场景坐标系统中的位置
    setSceneRect(0,0,400,300); 设置场景矩形,如果不自定义场景矩形,则其场景矩形的大小会随着视图项的增大而增大

     视图坐标,视图坐标就是部件的坐标,视图坐标的每一个单位对应一个像素,原点(0,0)总是在QGraphicsView视口的左上角,
    

    而右下角是宽,高。所有的鼠标事件和拖故事最初都是使用视图坐标接受的

    坐标映射,所谓的坐标映射,我认为就是想多坐标
    void MyView::mousePressEvent(QMouseEvent *event)
    {
    QPoint viewPos = event->pos();
    QDebug() << “viewPos:” << viewPos;
    QPointF scenePos = mapToScene(viewPos);
    qDebug() << “scenePos:” << scenePos;
    QGraphicsItem *item = scene()->itemAt(scenePos,QTransform());
    if(item)
    {
    QPointF itemPos = item->mapFromScene(scenePos);
    qDebug() << “item:” << itemPos;
    }
    }
    使用鼠标事件,获取了,获取了在视图中的位置,然后将这个位置转换为场景中的坐标,并使用itemAt() 函数获取了场景中该坐标处
    的图形项,如果这里有图形项,那么便输出该点在图形项坐标系统中的坐标

    事件处理:
    框架的事件都是由视图进行接受,然后传递给场景,再由场景传递给相应的图形项的
    场景对象->setFocusItem() 或者是 图形项对象->setFocus() 来设置焦点图形项,如果没与设置焦点图形项,那么所有的
    键盘事件都会被抛弃

    动画框架:
    现在是主要是通过动画框架来实现动画效果,另一个方法是创建一个继承自QObject和QGraphicsItem的自定义图形项,然后创建
    它自己的定时器来实现动画,第三种方法是使用QGraphicsScene::advance() 来推进场景
    void advance(int phase) //第一阶段不进行处理
    {
    if(! phase)
    return ;
    }
    int value = qrand() % 100; //图形项向不同方向随机移动
    if(value < 25)

    setRotation(45);
    moveBy(qrand() % 10, qrand() %10;

    else if(value < 50)
    {
    setRotation(-45);
    moveBy(qrand() % 10, qrand() %10;
    }
    else if(value < 75)
    {
    setRotation(30);
    moveBy(qrand() % 10, qrand() %10;
    }
    else
    {
    setRotation(-30);
    moveBy(qrand() % 10, qrand() %10;
    }
    调用场景的 advance() 函数就会自动调用场景中所有的图形项

    碰撞检测:
    碰撞检测可以使用两种方法来实现:
    重新实现 QGraphicsItem :: shape() 函数来返回图形项准确的形状,然后使用默认的 colledes withItem() 函数通过两个图形
    项形状的交集判断是否发生碰撞,如果没有重新实现shape() 函数,那么他会默认调用 boundingRect()
    重新实现 colledesWithItem() 函数来提供一个自定义的图形碰撞算法

    图形项组:
    提供了一个容器为各种图形项

4.5 动画机制
QPushButton button(“Animated Button”); //创建一个按钮
button.show();

QPropertyAnimation animation(&button,"geometry");			
animation.setDuration(10000);
animation.setStartValue(QRect(0,0,120,30));						动画开始时
animation.setKeyValueAt(0.8,QRect(250,250,200.60));
animation.setEndValue(QRect(250,250,200,60));					动画结束时
animation.start();

还可以调用 setKeyValueAt(qreal step,const QVariant &value);  在动画中间为属性设置值,0.0~1.0之间,0.0表示开始位置,
1.0表示结束位置,而value为属性值
动画中,pause() 来暂停动画,resume() 来恢复动画,stop() 来停止动画
setDirction() 设置动画的方向
setLoopCount() 函数设置动画的重复次数

使用缓和曲线:
缓和曲线描述了怎样来控制0和1之间的插值速度的功能
animation.setEasingCure(QEasingCurve::OutBounce);		它会使按钮部件就像从开始位置掉落到结束位置的皮球一样出现
弹跳效果,该缓和曲线还可以自己定义

动画组:同时移动多个图形项或者让他们一个接一个的串行移动
串行动画组:QSequentilAnimationGroup			执行完第一个以后,然后执行第二个,一个部件也行,两个部件也行
QSequentialAnimationGroup group;
group.addAnimation(&animation);
group.addAnimation(animation2);
group.start();

并行动画组:QParallelAnimationGroup				需要有两个以上的部件,在执行的时候会一起执行的
QParallelAnimationGroup group;
group.addAnimation(animation1);
group.addAnimation(animation2);
group.start();

在图形框架中使用动画
需要继承自 QGraphicsObject , QPropertyAnimation在其中添加的动画必须要是 QObject 的,
QGraphicsObject 继承自QObject 和 QGraphicsItem

4.9 状态机框架

  1. 多线程
    步骤就是:
    先根据线程继承一个类
    然后 重写run() 函数
    在其他文件中 根据这个类去实例化一个对象,
    调用start就会启动这个线程了
    然后 - 自动调用那个 run 函数的(在开始执行线程的时候,就会调用run()函数)
    线程 . start() 启动线程
    线程 . stop() 停止线程
    线程 . isRunning() 查看状态
    线程 . wait() 线程等待

    线程同步执行:
    QMutex 互斥量 lock()函数,锁住 unlock()解锁 - 否则当前线程就会被阻塞
    使用方法:
    QMutex mutex;
    mutex.lock();
    中间是锁住的代码
    mutex.unlock();
    使用互斥量的作用是,每次只能有一个线程可以访问同一变量
    QReadWriteLock 读写锁 它是一个同步量,运行同时执行多个读取访问而不会影响性能
    使用方法:
    QReadWriteLock mutex;
    mutex.lock();
    中间是锁住的代码
    mutex.unlock();
    与互斥量的用法是基本相同的了!
    QSemaphore 信号量
    QWaitCondition 等条件

    在次线程和主线程之间进行通信的一个解决方案是在线程之间使用信号 - 槽的连接,当连接位于不同线程中的对象时,这一机制
    就会变得不同步起来【这种状态可以通过修改QObkect::connect()中的第5个可选参数而改变】
    QObkect 存在与创建它的线程中,通过调用QObject::moveToThread()可以正在任意时刻修改它。

    imageLable = new QLable;
    imageLable->setBackgroundRole(QPalette::Dark);

  2. Qt常用事件
    //绘图事件
    void paintEvent(QPaintEvent *event);
    //定时事件
    void timerEvent(QTimerEvent *event);

    //鼠标按下事件
    void mousePressEvent(QMouseEvent *event);
    //鼠标按下移动事件
    void mouseMoveEvent(QMouseEvent *event);
    //鼠标释放事件
    void mouseReleaseEvent(QMouseEvent *event);
    pos()、posF()、x()、y()这四个函数返回的是鼠标指针在当前接收鼠标事件的窗口中的位置。

    //键盘按下事件
    void keyPressEvent(QKeyEvent *event);

  3. Qt的元对象系统
    Qt中的对象系统和 标准C++中对象系统是在区别的,更确切的讲是对后者的一种扩展。每个对象具有一个原信息,包含有对象的
    类名以及相应的信号和槽的列表,以及指向对应函数的指针
    Qt的元对象系统和标准C++系统的我知道的区别:
    支持对象间使用信号和槽的机制进行通信
    事件和事件过滤器
    层次结构可查询的对象树
    Q_OBJECT 实现了,元对象系统的主要

  4. 分组属性两种写法
    font.pixelSize:
    font{pixelSize : }

  5. 属性绑定

  6. QML中所以可视项目都继承自Item.虽然Item本身没有可视化的外观,它定义了可视化的所以属性,例如位置的x和y属性,大小的
    width , height , 关于布局的 anchors属性 , 按键的 keys属性
    作用:
    作为容器:
    Item 常常对项目进行分组

  7. 事件处理
    QML程序更多的是实现触摸式用户界面,在QML中如果想要一个项目能被点击,鼠标或者是手指,就要在其上放置一个
    MouseArea元素,用户只能在MouseArea 确定的范围内进行点击

  8. QML布局属性,anchor , 锚点可以指定对象与父对象和同级对象的相对几何位置,比如定义元素在另一个元素中央
    anchors.centerIn:parent

    QML中的信号,命名方式是 on + 标题名

  9. 动画实现:
    一个动画定义了一个属性的在一段时间内的变化过程,为了实现这个效果,我们使用一个动画类型叫做属性行为。这个行为指定了
    一个动画来定义属性的每一次改变并赋值给属性。每次属性改变,动画都会运行
    Image {
    id:wheel
    Behavior on rotation{
    NumberAnimation {
    duration:250;
    }
    }
    }

  10. 将QML使用在C++ 程序中
    QQuickView *view = new QQuickView();
    QUrl source = QUrl::fromLocalUrl(“main.qml”);
    view->setRouse(source);
    view.show();

  11. QML是一种描述用户界面的声明式语言,他将用户界面分解成一些更小的元素,这些元素能够结合成一个组件。QML语言描述了
    用户界面元素的形状和行为
    子元素从父元素上继承了坐标系统,他的x,y坐标总是相对于它的父元素坐标系统
    元素可以嵌套,这意味着一个元素可以拥有多个子元素,子元素可以通过访问parent 关键字来访问他们的父元素。还可以通过父类的
    id 进行访问。

  12. 在javeScript 中其函数的定义

    function 函数名(),在程序中进行调用的时候,会出现斜体的情况
    在自定义属性的时候,引用的过程中,也会出现协斜体的情况。所以不要慌
    property 正常编程原因类型名, 自定义属性的时候。

    QML : 的属性绑定 存在与整个声明周期,其后的值一旦改变,其前面的值也会随时改变的,

    基本元素分为 可视化和不可视化的
    item 是所以可视化元素的基础对象 , 所以其他可视化元素都继承自item
    Gemoetry
    Layout handling
    Key handling
    TransFromation
    Visual
    State definition

    在QML中 , 一个矩形框如果没有 width/height(宽度与高度)将不可见。

    文本可以使用horizontalAlignment与verticalAlignment属性来设置它的对齐效果。为
    了提高文本的渲染效果,你可以使用style和styleColor属性来配置文字的外框效
    果,浮雕效果或者凹陷效果。

    图像元素的加载 使用source属性 , fillMode属性能够控制元素的大小调整行为。

  13. 组件
    一个组件是一个可以重复使用的元素,QML提供几种不同的方式来创建组件。
    一个文件就是一个基础组件。 一个以文件为基础的组件在文件中创建了一个QML元素,并且将文件以元素类型来命名

    首先我们新建一个QML文件,这里的文件名,如果是组件,也就是说将来会在其他QML文件中使用这个QML文件组件的话,你的组
    件就是这个QML文件的名称了

    QML 元素对象通常能被平移,旋转,缩放

    QML 定位元素
    有一些元素被用于放置元素对象,他们被称做是定位器。row column grid flow

  14. 动画被用于属性的改变 。 一个动画定义了属性值改变的曲线,将一个属性值变化从一个值过度到另一个值。
    所有在QtQuick 中的动画都由同一个计数器来控制,因此它们始终都保持同步,这也提高了动画的性能和显示效果
    动画控制了属性的改变,每个元素都有大量的属性供你任意使用

  15. 动画元素
    有几种类型的动画
    每一种都在特定情况下都有最佳的效果
    PropertyAnimation 属性动画
    NumberAnimation 数字动画
    ColorAnimation 颜色动画
    RotationAnimation 旋转动画
    特殊场景下使用的动画
    PauseAnimation 停止动画
    SequentialAnimation 顺序动画
    ParallelAnimation 并行动画
    AnchorAnimation

    PropertyAction(属性动作)- 在播放动画时改变属性
    ScriptAction(脚本动作)- 在播放动画时运行脚本
    
  16. 应用动画
    属性动画:在元素完整加载后自动运行
    属性动作:当属性值改变时自动运行
    独立运行动画 - 使用start()函数明确指定运行或者running属性被设置为
    true(比如通过属性绑定)

  17. 粒子系统
    发射器:喷射 -> 方向
    画笔:可视化(一张图片,一个QML , 着色项)
    粒子模型:提供控制器
    方向:
    粒子组
    粒子控制器

    Rectangle {
    id:root;
    width: parent.width ;
    height: parent.height; //跟随他的父类
    color: “#1f1f1f” //底图颜色

    ParticleSystem { //定义一个粒子系统
    id:pariticleSystem
    }
    Emitter {
    id : emitter
    anchors.centerIn: parent //嵌入到父类中
    width: parent.width;
    height: parent.height;
    system: pariticleSystem
    emitRate: 100; //发射率
    lifeSpan: 2000; //寿命宽度
    lifeSpanVariation: 500; //寿命的变化
    size: 16;
    endSize: 50;
    //Tracer {color:“green”}; 这个是一个跟踪元素,用来显示发射器的几何形状
    }
    ImageParticle {
    //color: ‘#FFD700’; //加了一层金色滤镜
    colorVariation: 0.2; //粒子的变化范围是 0.5
    rotation: 15; //每个粒子首先选择15度
    rotationVariation: 5; //在±5之间变化
    rotationVelocity: 45; //每秒45度
    rotationVelocityVariation:15; //变化为15±

    		entryEffect: ImageParticle.scale;
    		//粒子产生时的效果 , 在这里使用一个缩放的效果
    
    		source: "qrc:/jewel_hit_5.png";
    		system: pariticleSystem;
    	}
    	//一个逻辑粒子的可视化使用粒子画笔(在这里使用了 paticalPainter 来实现)
    }
    

    以上代码粒子可以实现 原地起来的效果了
    如果定义了粒子的轨道运行:速度 + 粒子随机方向 + 加速度指定
    三种方法指明方向:
    点:
    velocity: PointDirection {
    x : 100;
    y : 0;
    xVariation: 0;
    yVariation: 100/6
    }
    角度:
    velocity: AngleDirection {
    angle:-45; //方向向下x轴45度
    angleVariation: 15; //角度变化正负15度之间
    magnitude: 100; //初始速度
    //magnitudeVariation: 50; 这个就不能要啦
    }
    acceleration: AngleDirection {
    angle:90;
    magnitude: 25;
    }
    目标方向:
    velocity: TargetDirection {
    targetX: 100;
    targetY: 0;
    targetVariation: 100/6;
    magnitude: 100;
    }

    粒子画笔:之前用的是基于图像的粒子可视化,Qt也提供了一些其他的粒子画笔
    粒子项:粒子画笔的代理
    自定义粒子:基于粒子画笔的着色器

  18. 多媒体框架;
    多媒体是使用 QtMultimedia模块中的multinedia元素播放和记录信息的,声音视频或者图片
    ,解码和编码的操作由特定的后台完成。
    例如:Linux上的 gstreamer框架,windows上的DirectShow等
    使用 MediaPlayer 元素可以完成它,如果源是一个图片或者视频,可以选择结合
    VideoOutput 元素,MediaPlayer 元素的一个 sourse属性指向需要播放需要播放的媒体
    调用play函数就可以播放了

  19. Qt再续前缘
    (1)Qt的风格
    系统自带的风格:工具->Form Editor->Preview in->在这其中就可以选择项了
    在代码中使用
    #include
    a . setStyle(QStyleFactory::create(“fusion”)); 整体就会变换一个大的风格的。

(2)调色板:
Qt中所有部件都包含一个调色板,使用该调色板绘制自身,一个调色板包含三种状态:激活,未激活,失效
Active 用于获得键盘焦点的窗口
Inactive 用于其他没有获得键盘焦点的窗口
Disabled 用于一些原因而不可用的的部件

步骤:获取调色版
		  设置调色板
QPalette palerre1 = ui->pushButton -> palette();		获取调色板
palette1.setColor(QPalette::ButtonText,Qt::red);		设置其中的参数
palette1.setColor(QPalette::Button,Qt::green);
setColor 中的第一个参数是设置  颜色角色,就是哪个部件的意思
ui->pushButton->setPalette(platte1);							设置调色板

ui->spinBox->setDisabled(true);									设置微调框为不可用状态
QPalette palette2 = ui->spinBox->palette();				获取
palette2.setColor(QPalette::Disabled,QPalette::Base,Qt::blue);			更改参数
ui->spinBox->setPalette(palette2);								设置微调框

QPaleete 类的主要的颜色角色
QPalette::Window		一般的背景颜色
QPalette::WindowText 		一般的前景颜色
QPalette::Base					主要是作为输入背景的背景色
QPalette:;AlternateBase	在交替行颜色的视图中作为交替背景色
QPalette::ToolTipBase		作为提示图的背景色出现
QPalette::ToolTipText		作为提示图的前景色出现
QPalette::Text						和base 一起使用,作为前景色使用
QPalette::Button				按钮部件的背景色
QPalette::ButtonText			按钮部件的前景色
QPalette::BrightText			一种与深色对比较大的文本颜色,一般用于当Text或者WindowText的对比度较差时

(3)样式表:
除了那些能够子类化QStyle更改的外观,其余的都可以使用Qt样式表来进行美化,受到了HTML的层叠样式表的启发,Qt的样式表应用于部件的世界
QPushButton { //选择器
background:red //说明 = 属性 + 值
//属性又可分为某个属性下的特定属性 : background - image 背景下的特定属性
}
一般选择器可以指定相同的声明
QPushButton , QLineEdit , QComboBox{color:red}

QPushButton {													//选择器
	color:red;														//属性和值 有多个则用分号分隔开
	background-color:color:white;
}
在Qt中选择器 有7种选择器存在,常用的选择器 就是其上的类型选择器了,或者是固定不变的那种 指定部件为选择器的了;

子控件:对与一些复杂的部件修改样式,会访问谈们的子空间,例如QComboBox的下拉按钮,QSpinBox的向下和向下箭头等!
选择器可以包含特定子控件来对部件的特定子控件应用规则:
子控件用两个 :: 号
QComboBox :: drop-down{image:url(dropdown.png)}

伪状态,选择器可以包含为伪装态来限制在部件的指定状态上的应用,伪状态出现在选择器之后
QPushButton:hover{color:white}						//选择器中的某一个小环节使用 : 向着个一样的,在属性中用- 
QPushButton:!hover{color:white}					也可以进行取反操作的哈
伪装态还可以连用的:   例如当鼠标悬停在一个被选中的QCheckBox:horver:checked{color:white}
伪装态与子控件的连用:QCheckBox::drop-down:hover{image:url(图片资源路径)};
这种伪装态的需要注意了,因为在单个部件的样式表设置的时候,是不能在弄一个伪装态的,在弄个伪装态,那不是设置两个样式表了吗!

帮助文档:List of Pseudo - States
帮助文档:The Style sheet Syntax

冲突解决:
特殊的优先:单一属性设置比全体类对象设置优先
伪装态的比没有伪装态的优先
自己的样式表优先于祖先的样式表

盒子模型
使用样式表时每一个部件都是一个盒子模型,初始都为0,所以是重叠的!
margin 矩形			外边距
border 矩形			边框
padding 矩形			内边距,填充,填衬
content 矩形			内容,整个页面
  1. QWidget只支持background、background-clip和background-origin属性。

  2. Qtcreator 中常用快捷键和技巧
    =Qtcreator中常用快捷键总结===============
    F1 查看帮助

    F2 跳转到函数定义(和Ctrl+鼠标左键一样的效果)
    Shift+F2 声明和定义之间切换
    F4 头文件和源文件之间切换

    Alt+0 显示或者隐藏侧边条,编辑模式下起作用(有时写的函数太长,屏幕不够大,就用这个)
    Ctrl+Space 自动补全(貌似会和输入法的切换冲突)

    ESc 切换到编辑模式

    Alt(按住)+ Enter 将光标移动到h文件中的方法声明。按Alt(按住),再按回车键将在cpp中添加该函数的定义。


    Ctrl+I 自动对齐
    Ctrl+/ 注释行,取消注释行


    Ctrl+B 编译工程
    Ctrl+R 运行工程
    F5 开始调试
    Shift+F5 停止调试
    F9 设置和取消断点
    F10 单步前进
    F11 单步进入函数
    Shift + F11 单步跳出函数

    Qtcreator中常用小技巧============

  3. Qt获取字符串的像素的宽与高
    //设置字体
    QFont font;
    font.setFamily(“Microsoft YaHei”);
    font.setPointSize(8);
    QFontMetrics fm(font);
    QRect rec = fm.boundingRect(“这是要获取宽度和高度的字符串”);
    //字符串所占的像素宽度,高度
    int textWidth = rec.width();
    int textHeight = rec.height();

  4. 颜色转化为字符串的故事
    QString BackColorstr = QString(“background-color:rgba(%1,%2,%3,%4)”)
    .arg(mBackColor.red())
    .arg(mBackColor.green())
    .arg(mBackColor.blue())
    .arg(mBackColor.alpha());
    this->setStyleSheet(BackColorstr);

  5. 一定要注意
    在paintEvent事件里
    一定不要有
    this->setStyleSheet(“background-color:argb()”); 这种式子

  6. 子类发送信号,父类接受信号,并显示出来
    connect(parent,SIGNAL(send(const QString&)),this,SLOT(getMsg(const QString&)));//这里发

  7. 阻塞式延时和非阻塞式延时:

    非阻塞式延时:
    void QSleepTimeSet::Delay_MSec(unsigned int msec)
    {
    QTime _Timer = QTime::currentTime().addMSecs(msec);

    while( QTime::currentTime() < _Timer )
    
    QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
    

    }
    其中的msec为需要延时的毫秒数,例如,你要实现5秒延时,则msec的值就是 :5000

    阻塞式延时:
    void QSleepTimeSet::Delay_MSec_Suspend(unsigned int msec)
    {
    QTime _Timer = QTime::currentTime();
    QTime _NowTimer;
    do{
    _NowTimer=QTime::currentTime();
    }while (_Timer.msecsTo(_NowTimer)<=msec);
    }
    其中的msec为需要延时的毫秒数,例如,你要实现5秒延时,则msec的值就是 :5000

    Qt下的延时函数 Sleep 函数;
    QT下使用sleep函数比较费劲,常用的几个头文件里都没有这个函数。在用于单元测试的QTest类中有一个sleep,可以通过:

    #include < QTest >

    QTest::qSleep ( 100 );
    这种方式来调用。帮助文档上说,qSleep实际上是调用了操作系统自带的sleep函数,比如在Linux上调用nanosleep(),在windows则是Sleep()
    当然我们也可以自己使用操作系统自带的sleep来实现休眠,通过Q_OS_WIN32、 Q_OS_LINUX来实现条件编译

  8. QSocketNotifier 用来监听系统文件操作,将操作转换为Qt事件进入系统的消息循环队列。并调用预先设置的事件接受函数
    发生了一个socket event 他都会发出activated() 信号。连接这个activated() 信号到你槽,你可以据此来处理你的socket notifier根据不同的
    事件类型的相对应的反应

  9. Qt 的构造函数, 只是执行一遍而已, 所谓的事件循环, 只是一种监听的一种状态而已

  10. QXmlStreamReader 接口
    创建一个 QXmlStreamReader 的类对象
    通过 setDevice() 设置好要处理的XML文件
    通过 readNext() 挨个读入节点
    通过isStartElement()和isEndElement()判断是节点的开始和结束.
    通过name()得到当前节点名字
    通过readElementText()访问当前节点的内容

    通过attributes()获取含有属性的节点的属性

    QXmlStreamReader::TokenType type = reader.readNext(); 用来获取下一个节点类型

    QXmlStreamReader::StartDocument 文件开始
    reader.documentEncoding() 编程格式
    reader.documentVersion() 版本
    QXmlStreamReader::StartElement 元素开始
    reader.name() 获取元素名
    reader.attributes().hasAttribute(“id”) 属性.返回指示当前节点是否具有属性的布尔值 有这个在 是判断 id 的;
    QXmlStreamReader::Characters && ! reader.isWhitespace() 字符集且并不是空白格

    // 以上 总结 跨越一行的时候,需要移动两个节点,如果是一行的 话是一个节点哈
    // <> 表示一个节点 >< 中间的文字也是一个节点 哈哈
    // 这个里有两个节点 啊啊啊 如果要是换行,则需要三条才能走了
    灰常重要!
    // 如果我们没有给 xml 加一个头,他将自己创建的 一个 QXmlStreamReader::TokenType type = reader.readNext(); 标题头啦
    // 根元素, 也是一行 type = reader.readNext(); 就走啦! 一行就行,去另一行的时候,就需要两个移动啦

  11. extern 使用的问题
    如果在 main.cpp 中定义全局变量以后,若包含其他文件, 在其它文件中使用这些变量。
    在其他文件中, 也是可以使用这些变量的, 使用方法 extern 声明一下, 在main 中定义的变量就可以啦! 然后这个 声明的位置可以是
    .cpp 文件中, 也可以是 .h 文件中,但是最好是 .h 文件中进行声明!

如果在 其他文件中定义, 在 main 中使用,使用 extern 声明一下, 也是可以使用的哈!
main.cpp 中 , 引用这些文件,然后在 这些文件中是定义

main.cpp      						#include<文件>   		
引用者:声明						被引用:定义					注意:这个应该放在 .cpp 文件中,要不会重复包含, 除非设置不能重复包含	
引用者:定义						被引用:声明					注意:这个 .cpp 和 .h 文件中都是可以的!
不同的包含级别中使用是可以的!

#include<文件>					#include<文件>
无引用关系
文件1:定义或者声明			文件2:声明或者定义		 这个是都可以的, 注意好不包含就行
同级之间的使用是可以的!

综上看出, 一个程序,其实可以看出,就是, 一篇文章而已,它只不过是翻译过去的罢了
  1. QT 多线程编程

  2. GUI线程与工作线路
    每个线程启动后的第一个线程是主线程,Qt 所有的组件和几个相关类只能在GUI线程,不能工作在次线程,次线程即工作线程,主要负责处理GUI 线程卸下的工作
    在线程中 最好是在里面是实现逻辑的编程, 不能创建 图形化显示界面的元素

  3. Qt 的信号量是,是当某个值 存在可以读取的时候, 其他的值才可以动的那种, 就是它被锁到那里了吗! 哇哈哈

如果使用 qmake 来构建项目,则需要将 Qtcore 包含在内
#include <QtCore>

每个线程都是有事件循环的
初始化线程使用 QCoreApplication::exec() 来开启它的事件循环,在一个 线程中使用事件循环, 使得该线程可以使用那些需要事件循环的非 GUI 类。例如:
	QTimer, QTcpSocket 和 QProcess 等

跨线程的信号与槽
	Auto Connection 默认。 如果信号发射和信号接受的对象在同一个线程中, 那么执行方式与Direct Connection 形同。 否则, 执行方式与QUeued Connection 相同

在线程中使用信号与槽进行通信时, 需要注意的是必须使用元数据类型
Qt 内生的元数据类型, 如int  double QString 等
  1. connect 函数的第五个参数代表信号与槽的连接模式
    Qt::AutoConnection: 默认值,使用这个值则连接类型会在信号发送时决定。如果接收者和发送者在同一个线程,则自动使用Qt::DirectConnection类型。如果接收者和发送者不在一个线程,则自动使用Qt::QueuedConnection类型。

    Qt::DirectConnection:槽函数会在信号发送的时候直接被调用,槽函数运行于信号发送者所在线程。效果看上去就像是直接在信号发送位置调用了槽函数。
    这个在多线程环境下比较危险,可能会造成奔溃。

    Qt::QueuedConnection:槽函数在控制回到接收者所在线程的事件循环时被调用,槽函数运行于信号接收者所在线程。发送信号之后,槽函数不会立刻被调用,
    等到接收者的当前函数执行完,进入事件循环之后,槽函数才会被调用。多线程环境下一般用这个。

    Qt::BlockingQueuedConnection:槽函数的调用时机与Qt::QueuedConnection一致,不过发送完信号后发送者所在线程会阻塞,直到槽函数运行完。接收
    者和发送者绝对不能在一个线程,否则程序会死锁。在多线程间需要同步的场合可能需要这个。

    Qt::UniqueConnection:这个flag可以通过按位或(|)与以上四个结合在一起使用。当这个flag设置时,当某个信号和槽已经连接时,再进行重复的连接就
    会失败。也就是避免了重复连接。

  2. C++ 引起线程安全的共享资源只有两种, 全局变量和静态变量
    Qt 在使用 QMutex 上锁 的时候, 需要在其他同处文件中,引用其他地方定义的锁,这个就是 比较麻烦了,我认为

    void* pthread_one(void *)
    {
    while(1)
    {
    //pthread_mutex_lock(&work_mutex);
    for(int i= 0;i<5;i++)
    {
    printf("===================== 1 :n");
    }
    //pthread_mutex_unlock(&work_mutex);
    //sleep(0.01); 当调用 sleep函数的时候,走的就是 比较妥当, 如果不调用了, 就会很长一段时间才换内容显示
    }
    }

    void* pthread_two(void *)
    {
    while(1)
    {
    //pthread_mutex_lock(&work_mutex);
    for(int i= 0;i<5;i++)
    {
    printf("===================== 2 :n");
    }
    //pthread_mutex_unlock(&work_mutex);
    //sleep(0.01);
    }
    }

    int main()
    {
    pthread_t id;
    pthread_t idd;

    pthread_mutex_init(&work_mutex,NULL);
    
    pthread_create(&id, NULL, pthread_one, NULL);
    pthread_create(&idd, NULL, pthread_two, NULL);
    
    pthread_join(id, NULL);
    pthread_join(idd, NULL);
    
    return 0;
    

    }

    死锁是指:永远互相等待的进程,就是 在其他 某个地方 将 资源扣住了,在某个地方 资源被释放不出来了, 就造成死锁了

    线程中的程序互不干扰, 是一定会执行的!

    信号量其实也是 一种对情况的判断吧! 我认为哈,只有在某种情况下成立, 才能继续走某种情况
    信号量有一种信号与槽的感觉,哈哈

    #include <stdio.h>
    #include <pthread.h>
    #include <unistd.h>

    pthread_t t1;
    pthread_t t2;
    pthread_mutex_t mutexx;
    pthread_cond_t cond;

    int i=0;

    void* child1(void *)
    {
    while(1)
    {
    pthread_mutex_lock(&mutexx);
    i++;
    if(i%5 == 0) //
    {
    pthread_cond_signal(&cond); //如果等于的话, 就发送信号啦
    }
    else {
    printf("================ false 5 ================ :%d n",i);
    }
    pthread_mutex_unlock(&mutexx);
    usleep(1000000);
    }
    }

    void* child2(void *)
    {
    while(1)
    {
    pthread_mutex_lock(&mutexx);
    pthread_cond_wait(&cond, &mutexx);
    printf(“xian cheng 2 ============= 5 de bei shu %dn”, i);
    pthread_mutex_unlock(&mutexx);
    usleep(500000);
    }
    }

    int main()
    {
    pthread_cond_init(&cond, NULL);
    pthread_mutex_init(&mutexx, NULL);

    pthread_create(&t1, NULL, child1, NULL);
    pthread_create(&t2, NULL, child2, NULL);
    
    //pthread_join(t1, NULL);
    pthread_join(t2, NULL);								如果只堵塞一个,效果也是一样的!哈哈
    
    return 0;
    

    }

    总结:
    线程的创建:【id , create , 以及 函数地址】(返回类型与参数都应该是指针的)
    互斥量, 信号量, 条件变量, 读写锁:都需要; 【id, 初始化, 以及使用】,其 id 的创建最好是在文件头部!
    在 信号量 与 条件变量中 还会使用 互斥锁
    读写锁, 单独进行就行了

    条件变量的使用, 需要 条件执行的时候 发一次信号,去执行一次。就是 就这样子的

  3. Qt 的进程
    QProcess 用来启动一个外部程序并与其通信
    启动进程 使用 start 函数
    开始运行时 , 进入 Starting 状态 , 当程序已经运行后, QProcess 进入Running 状态, 并发射 started() 信号。
    当进程退出后, QProcess 重新进入 NotRunning 状态并发出 finished() 的信号

    #include
    QProcess myProcess; 创建进程类
    myProcess.start(“notepad.exe”); 直接启动 记事本程序,因为他在Windows 的系统目录下, 该目录已经加在了系统 PATH 环境变量中,所以不需要写具体
    路径

    void showResult();
    void showState(QProcess::ProcessState);
    void showError();
    void showFinished(int, QProcess::ExitStatus);

  4. 文本文件和二进制文件
    1)文本文件:这类文件以文本的ASCII码形式存储在计算机中。它是以"行"为基本结构的一种信息组织和存储方式。
    2)二进制文件:这类文件以文本的二进制形式存储在计算机中,用户一般不能直接读懂它们,只有通过相应的软件才能将其显示出来。二进制文件一般是可执行
    程序、图形、图像、声音等等。

  5. 字符串相互转换
    1.QString转换String
    string s = qstr.toStdString();
    2.String转换QString
    QString qstr2 = QString::fromStdString(s);

    QString 与 char * 的转换
    QString str;
    char* ch;
    QByteArray ba = str.toLatin1(); // must
    ch=ba.data();

  6. 文件操作
    QFileInfo 可以指向一个文件
    makeAbsolute() 将一个相对路径 转换为绝对路径
    QFile file(“D:OpenDoorAcc.txt”); 定义文件
    if(!file.open(QIODevice::WriteOnly | QIODevice::Text)) 打开文件,打开方式使用open的方式去打开 就行了
    qDebug() << file.errorString();
    file.write(“hello Qt! asdddddd”); 读文件
    file.close();

    QFileInfo info(file); 定义文件信息类
    qDebug() << QObject::trUtf8(“绝对路径:”) << info.absoluteFilePath() << endl
    << QObject::trUtf8(“文件名:”) << info.fileName() << endl
    << QObject::trUtf8(“基本名称:”) << info.baseName() << endl
    << QObject::trUtf8(“后缀:”) << info.suffix() << endl
    << QObject::trUtf8(“创建时间:”) << info.created() << endl
    << QObject::trUtf8(“大小:”) << info.size() << endl;
    if(!file.open(QIODevice::ReadOnly | QIODevice::Text))
    qDebug() << file.errorString();
    qDebug() << QObject::trUtf8(“文件内容:”) <<endl << file.readAll();
    qDebug() << QObject::trUtf8(“当前位置:”) << file.pos();
    file.seek(0); 定义文件指针的位置 每一个 字符 一个位置
    QByteArray array;
    array = file.read(5); 读取几个值
    qDebug() << QObject::trUtf8(“前五个字符:”) << array
    << QObject::tr(“当前位置:”) << file.pos();
    file.seek(15);
    array = file.read(5); 读取 15 - 5以后的值
    qDebug() << QObject::trUtf8(“第 16 - 20 个字符”) << array;
    file.close();

    当以文本 方式 写数据的时候, 会将

    使用文本流读/写文本文件
    QTextStream 类提供了一个方便的接口来读/写文本 QIODevice, QByteArray 和 QString 上进行操作
    对于文本生成,QTextStream 对字段填充,对齐和数字格式提供了格式选项支持

  7. Qt 提供了一些顺序容器:QList , QLinkedList 连接列表 , QVector 容器 , QStack 栈, QQueue 队列
    Qt 提供的关联容器 : QMap , QMultiMap , QHash , QMultiHash 与 QSet

    QList::append() 和 QList::prepend() 在列表的两端添加项目
    QList::insert() 在列表中间插入项目

    QVector 它在内存的相邻位置存储给定类型的值的一个数组。 在vector 的前面或者中间插入项
    QVector 的一个便捷子类,提供了 后进先出的语义。 push() pop()函数 top等函数

    QMap<Key, T> 它提供了一个字典, 将Key类型的键值映射到T类型的值上
    QHash<Key,T> 它与QMap拥有基本相同的接口, 但是它的查找速度更快, QHash的数据是以任意的顺序存储的

  8. INCLUDEPATH += /usr/include/gstreamer-1.0 引用路径 GStreamer
    #include <gst/gst.h> 可以在这里使用了

    INCLUDEPATH += /usr/include/gstreamer-1.0
    /usr/include/glib-2.0
    /usr/lib/x86_64-linux-gnu/glib-2.0/include
    /usr/lib/x86_64-linux-gnu/gstreamer-1.0/include
    编译用的 -

    缺什么 就用 find /(根目录) -name(名字搜索) 文件名 去查那个东西在哪里 — 找到路径以后 将路径复制下来
    将路径 直接 引用到 Qt pro 文件下就可以了

    LIBS += -L /usr/lib/x86_64-linux-gnu/ -lgstreamer-1.0
    /usr/lib/x86_64-linux-gnu/ -lgobject-2.0 – 专业性的说了一些 gobject 的东西
    库连接 前面 一定要加上 -L 后面也一定要加 -l
    这个 也可以
    LIBS += -L /usr/lib/x86_64-linux-gnu/ -lgstreamer-1.0 貌似这个是需要空格的哈

    元件组成管道 衬垫可以连接管道
    gst_init() 必须是第一个GStreamer 的命令
    初始化所有内部结构
    检查哪些插件可用
    执行任何针对的命令行选项

    gst_parse_launch() 搭建管道用的
    媒体从源 流入到 我的计算机:这其中 必须借助于管道 - 然后咱们可以自己去搭建管道,当然 它的库也有一个比较简单的管道,就是上面的函数了
    playbin 是一个特殊的元素,充当源和接受器,是一个完整的管道

    视频地址的选择 找url 就行!

    GStreamer 的管道能被 GUI 编辑器编辑, 能够以xml文件来保存,
    GStreamer 核心库函数是一个处理插件,数据流和媒体流的框架

    GSteamer 中最重要的一个概念就是 GstElement 对象。 元件是一个构建一个媒体管道的基本块、 所以上层部件都源自 GstElemnet对象 , 任何人
    一个解码器码, 分离器, 视频。音频输出部件实际上都是一个 GstElement 对象

    源元件为管道产生数据,不接受数据 只是产生数据

    过滤器 多个输入衬端,一个输出衬端
    转换器
    分流器 一个输入衬端,多个输出衬端
    整流器
    编解码器 一个输入衬垫 , 一个输出衬垫

    元件是盒子 衬垫可以嵌入其两端进行程序的输入和输出使用
    接受元件:用来显示作用

    元件通过 衬垫连接起来,就成了管道: 源元件 -> 显示元件

    创建元件对象
    GstElement *element;
    element = gst_element_factory_make(“fakeesrc” , “source”); 这个函数使用一个已存在的工厂对象名和一个新的元件名来创建元件
    if(!element)
    {
    printf(“创建未能成功!”);
    }
    不用的时候,请对其进行销毁操作:
    gst_object_unref(GST_OBJECT(element));

    工厂对象有一种磨具的感觉, 直接使用工厂对象去创建
    GstElementFactory *factory;
    GstElement *element;

    factory = gst_element_factory_find(“fakesrc”);
    if(factory)
    {
    printf(“工厂对象创建未成功!”);
    }
    element = gst_element_factory_create(factory , “source”);
    if( !element )
    {
    printf(“工厂对象创建未成功!”);
    }
    gst_object_unref(GST_ONJECT(element));
    }

    gst_object_set_name 设置对象的属性
    gst_object_get_name 得到一个名字属性

    找出元件所包含的衬垫:暗指就是这些衬垫所支持的媒体类型

    连接元件:先创建管道和元素
    pipeline = gst_pipeline_new (“my-pipeline”); 先创建管道
    /* create elements */
    source = gst_element_factory_make (“fakesrc”, “source”); 在创建元素
    filter = gst_element_factory_make (“identity”, “filter”); 在创建元素
    sink = gst_element_factory_make (“fakesink”, “sink”); 在创建元素

    源元件 - 其他种类元件 - 接受元件 ; 连接在一起
    gst_bin_add_many(GST_BIN(pipeline), source, filter, sink, NULL); 先要添加到管道之中
    gst_element_link_many(source, filter, sink, NULL); 连接管道内的元素

    一个元件被创建后不会执行任何操作;元件有4种状态
    GST_STATE_NULL: 默认状态
    GST_STATE_READY: 准备状态
    GST_STATE_PAUSED:
    GST_STATE_PLAYING:
    通过使用 gst_element_set_state() 来改变一个元件的状态!

    箱柜:它是一种容器元件。可以往箱柜中添加元素它本身也是一种元件,所以可以像普通元件一样,操纵箱柜
    箱柜允许你将一组有链接的元件组合成一个大的逻辑元件。
    然也有一些更便利的函数来创建箱柜— (gst_bin_new() 和 gst_pipeline_new ())。你可以使用 gst_bin_add()往箱柜中增加元
    件,使用 gst_bin_remove()移除箱柜中的元件。

    每一个管道默认包含一个总线,所以应用程序不需要再创建总线。

    /---------------------------------------------------- 直接播放视频的地方 ------------------------------------------/
    GstElement *pipeline;
    GstBus *bus;
    GstMessage *msg;

    gst_init(&argc, &argv);

    pipeline = gst_parse_launch(“playbin uri=http://ivi.bupt.edu.cn/hls/cctv6hd.m3u8”,NULL);
    gst_element_set_state(pipeline, GST_STATE_PLAYING);

    bus = gst_element_get_bus(pipeline);

    msg = gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE,
    GST_MESSAGE_EOS);

// gst_message_unref(msg);
// gst_object_unref(bus);
// gst_element_set_state(pipeline,GST_STATE_NULL);
// gst_object_unref(pipeline);

Streamer 是 GNOME 桌面环境下用来构建流媒体应用的开源多媒体框架(framework)
GstElement对象,唯一的办法是借助于工厂对象GstElementFactory。由于GStreamer框架提供了多种类型的GstElement对象,因此

对应地提供了多种类型的GstElementFactory对象,它们是通过特定的工厂名称来进行区分的。
例如通过代码:gst_element_factory_find() 函数获得了一个名为 mad 的工厂对象,它之后可以用来创建与之对应的MP3解码器元件
GstElementFactory *factory;
factory = gst_element_factory_find(“mad”);
成功的创建完工厂对象以后,就可以 通过 gst_element_factory_create() 函数来创建特定的 GstElement 对象了,该函数在调用时有两个参数,分别是
需要用到的工厂对象,以及即将创建的元件名称。元件名称可以用查询的办法获得,也可以通过传入空指针 NULL 来生成工厂对象的默认元件
GstElement *element;
elemnt = gst_element_factory_factory(factory , “decoder”);
当创建的 GstElement 不能使用的时候,必须将其销毁, 销毁函数是
gst_element_unref(element);

/---------------------------------------------------------------------------------------/
衬垫:就是端口,与外界进行交流的唯一的接口   (衬垫是在根据不同的工厂对象去创建元件以后 , 元件自动带有的端口)
创建完成元件对象以后,可以通过 gst_element_get_pad() 获得该元件的指定衬垫
GstPad  *srcpad;
srcpad = gst_element_get_pad(element , "src");
这个代码将返回 element 元件中 名为 src 的衬垫;
GList *pads;
pads = gst_element_get_pad_list(element);
while(pads)
{
	Gstpad *pad = GST_PAD(pads -> data);
	g_print ("pad name is : %sn" , gst_pad_get_name(pad) );
	pads = g_list_next(pads);
}
st_element_get_pad_list, 这个语句是查询 这个元件中的所以 衬垫(衬垫名字是系统自带的哈!);
与元件一样,衬垫的名称也能够动态设置或者读取, 通过调用 gst_pad_set_name();	gst_pad_get_name();
利用 gst_pad_get_direction() 可以获得指定衬垫的类型
调用 gst_pad_get_parent()     可以获得指定衬垫所属的元件, 该函数的返回值是一个指向 GstElement 的指针
衬垫可以看出是元件的代言人,因为他要负责向外界描述该元件所具有的能力
struct _GstCaps {													用来描述元件所具有的能力 - 可以说它是元件的代言人,去用它说元件的属性
	gchar *name; /* the name of this caps */		这个衬垫的名字
	guint16 id; /* type id (major type) */				类型ID
	guint refcount; /* caps are refcounted */		
	GstProps *properties; /* properties for this capability */    此功能的属性
	GstCaps *next; /* caps can be chained together */				帽子可以用链子连在一起
}
例如:对mad 元件的能力描述
Pads:
SINK template: ’sink’						元件的输入端口
Availability: Always
Capabilities:
mad_sink’:
MIME type: ’audio/mp3’:
SRC template: ’src’							元件的输出端口
Availability: Always
Capabilities:
    mad_src’:
    MIME type: ’audio/raw’:
    format: String: int
    endianness: Integer: 1234
    width: Integer: 16
    depth: Integer: 16
    channels: Integer range: 1 - 2
    law: Integer: 0
    signed: Boolean: TRUE
    rate: Integer range: 11025 - 48000	

GStreamer 框架中的每个衬垫 都能对应与多个能力描述 , 可以通过函数 gst_pad_get_caps() 来获得
GstCaps *caps;
caps = gst_pad_get_caps (pad);
g_print ("pad name is: %sn", gst_pad_get_name (pad));
while (caps) {
  g_print (" Capability name is %s, MIME type is %sn",
  gst_caps_get_name (cap),
  gst_caps_get_mime (cap));
  caps = caps->next;
}

/---------------------------------------------------------------------------------------/
箱柜 是容器元件,其本身 也是 GstElement 的对象,则也可以被其他的箱柜所包含, 利用箱柜可以将需要处理的多个元件组合成一个逻辑元件,由于
不再需要对箱柜中的元件逐个进行操作,因此能够很容易地利用它来构造更加复杂的管道
在 GStreamer 应用程序中使用的箱柜主要有两种类型:
GstPipeline 管道是最常用到的容器 , 对与一个 GStreamer 应用程序来讲, 其顶层箱柜必须是一条管道
GstThread 线程的作用在于能够提供同步处理能力,如果GStreamer应用程序需要进行严格的音视频同步,一般都需要用到这种类型的箱柜。
Gstremer  框架提供了两种方法来创建 箱柜:一种是借助与工厂方法 , 第二种是使用特定的函数
GstElement *thread , *pipeline;
//根据线程对象,同时为其指定唯一的名称
thread = gst_element_factory_make("thread", NULL);		使用工厂的磨具 thread
//根据给定的名称,创建一个特定的管道对象
pipeline = gst_pipeline_new("pipeline_name");

箱柜成功创建以后,就可以调用 gst_bin_add() 函数将已经存在的元件添加到其中了
GstElement *element;
GstElement *bin;
bin  = gst_bin_new("bin_name");   		//创建一个箱柜
element = gst_element_factory_make("mpg123" , "decoder");
gst_bin_add ( GST_BIN(bin),  element );
从箱柜中找到特定的元件也是可以的,使用函数 gst_bin_by_name() 函数实现
GstElement  *elemnet;
elemnet = gst_bin_get_by_name(GST_BIN(bin) , "decoder");
GStreamer框架中的一个箱柜能够添加到另一个箱柜之中,因此有可能会出现箱柜嵌套的情况,gst_bin_get_by_name()函数在查
找元件时会对嵌套的箱柜作递归查找。元件有添加到箱柜之中以后,在需要的时候还可以从中移出,这是通过调用gst_bin_remove()函数来完成的:
GstElement *element;
gst_bin_remove (GST_BIN (bin), element);
因为 衬垫的问题, 箱柜中引入了 精灵衬垫的概念
具有精灵衬垫的箱柜行为与元件是完全相同的, 所以元件具有的属性它都具有 , 所以针对元件等够进行的操作也可以对箱柜进行,则向箱柜中加入

精灵衬垫
GstElement *bin;
GstElement *element;
element = gst_elemnent_factory_create(“mad”, “decoder”);
bin = gst_bin_new( “bin_name” );
gst_bin_add( GST_BIN(bin) , element );
gst_element_add_ghost_pad ( bin, gst_element_get_pad(element , “sink”) , “sink” );

/---------------------------------------------------------------------------------------/
元件连接:
在引入了元件和衬垫的概念之后,GStreamer对多媒体数据的处理过程就变得非常清晰了:通过将不同元件的衬垫依次连接起来构成一条媒体处
理管道,使数据在流经管道的过程能够被各个元件正常处理,最终实现特定的多媒体功能。
元件的基本使用方法:
三个基本元件构成:数据源元件只负责产生数据,它的输出衬垫与过滤器元件的输入衬垫相连;过滤器元件负责从自己的输入衬垫中获取数据,
并在经过特定的处理之后,将结果通过输出衬垫传给与之相连的接收器元件;接收器元件只负责接收数据,它的输入衬垫与过滤器元件的输出
衬垫相连,负责对最终结果进行相应的处理。
GstPad *srcpad, *sinkpad;
srcpad = gst_element_get_pad(element1 , "src");     //获取 1 元件的输入衬垫
sinpad = gst_element_get_pad(element2 ,  "sink");  //获取 2 元件的输出衬垫
gst_pad_link(srcpad , sinkpad);
//连接
gst_pad_unlink(srcpad , sinkpad);
//断开

/---------------------------------------------------------------------------------------/
元件状态
当GStreamer框架中的元件通过管道连接好之后,它们就开始了各自的处理流程,期间一般会经历多次状态切换,其中每个元件在特定时刻
将处于如下四种状态之一:
NULL 		 这是所有元件的默认状态,表明它刚刚创建,还没有开始做任何事情。
READY 	 表明元件已经做好准备,随时可以开始处理流程。
PAUSED   表明元件因某种原因暂时停止处理数据。
PLAYING  表明元件正在进行数据处理。
依次经历NULL、READY、PAUSED、PLAYING等状态间的转换。元件当前所处的状态可以通过调用gst_element_set_state()函数进行切换
GstElement *bin;
gst_element_set_state(bin , GST_STATE_PLAYIND);
默认情况下,管道及其包含的所有元件在创建之后将处于NULL状态,此时它们不会进行任何操作。当管道使用完毕之后,不要忘记重新将管道的状态切换回NULL状态,让其中包含的所有元件能够有机会释放它们正在占用的资源。

管道真正的处理流程是从第一次将其切换到READY状态时开始的,此时管道及其包含的所有元件将做好相应的初始化工作,来为即将执行的数据
处理过程做好准备。对于一个典型的元件来讲,处于READY状态时需要执行的操作包括打开媒体文件和音频设备等,或者试图与位于远端的媒体
服务器建立起连接。

处于READY状态的管道一旦切换到PLAYING状态,需要处理的多媒体数据就开始在整个管道中流动,并依次被管道中包含的各个元件进行处理,
从而最终实现管道预先定义好的某种多媒体功能。GStreamer框架也允许将管道直接从NULL状态切换到PLAYING状态,而不必经过中间的READY状态。

正处于播放状态的管道能够随时切换到PAUSED状态,暂时停止管道中所有数据的流动,并能够在需要的时候再次切换回PLAYING状态。如果需要插
入或者更改管道中的某个元件,必须先将其切换到PAUSED或者NULL状态,元件在处于PAUSED状态时并不会释放其占用的资源。



/------------------------------------------- Linux 输入命令行 --------------------------------------------/
gst-insert  >d:/c.txt 文件中	txt文件中,这个命令在你想要查找某个 ekement 但有不确定其全名时很有用

gst-launch 构建链路的用法
最开始的构建使用方法:playbin , playbin2 , decodebin , decodebin2 , uridecodebin

视频流的推送采用 UDP 传输!

gst-launch-1.0   playbin   uri=file://多媒体路径				就可以播放了     自动建立管道的指令
gst-play-1.0		多媒体路径												也是可以播放的  用来测量 多媒体 好不好用是最正好的了

创建管道的方法;
gst_pipeline_new:
gst_parse_launch:

gst-launch-1.0  filesrc  location=/home/ssa/Music/tianyang.mp3 ! mad ! alsasink   可以进行播放			相对上边的自动建立管道,这个是 手动建立管道
gst-launch-1.0   用于创建 通道
filesrc    是源头	location 是它的 属性
mad    	 解码器
alsaink   输出流
!          代表连接
缺少 mad 播放是会失败的!

gst-launch-1.0  uridecodebin uri=http://网络地址  ! audioconvert ! autoaudiosink  播放网络连接的视频中的声音
gst-launch-0.10 videotestsrc pattern=11 ! ffmpegcolorspace ! autovideosink		  这个会播放一个同心圆, pattern=11  属性=值  多个属性将用空格隔开
gst-launch-0.10 videotestsrc ! ffmpegcolorspace ! tee name=t ! queue ! autovideosink t. ! queue ! autovideosink			name属性是用来设置名称的, 

uri 在播放网络 地址的时候,不需要 加 file://		 但是他在播放本地程序的时候,一定要 uri=file://本地地址
location 的使用 			直接是  location=地址   就可以了
  1. 测试代码
    GstElement *sourse;
    GstElement *sink;
    GstElement *decode;
    GstElement *pipeline;

    gst_init(&argc, &argv);

    sourse = gst_element_factory_make(“filesrc”, “source”);

    sink = gst_element_factory_make(“alsasink”, “sink”);
    decode = gst_element_factory_make(“mad”, “decode”);

    pipeline = gst_pipeline_new(“pipeline”); 创建管道了

    g_object_set(G_OBJECT(sourse), “location”, “/home/ssa/Music/tiantang.mp3”, NULL); 注意这里面的 不能用 file://路径 那么去写 这么写 就行了

    if(!sourse || !sink || !decode || !pipeline)
    {
    printf(“元件创建失败!出现问题n”);
    }

    gst_bin_add_many(GST_BIN(pipeline), sourse,decode, sink, NULL); 将原件都连起来,如果是 多输入的 或者 多输出的 这么做就不太好了
    if(!gst_element_link_many(sourse, decode, sink, NULL))
    {
    printf(“元件链接失败!n”);
    }

// if(!gst_element_link(sourse, sink))
// {
// printf(“起见链接失败!n”);
// }

gst_element_set_state(pipeline, GST_STATE_PLAYING);	

while(gst_bin_iterate_sinks(GST_BIN(pipeline))); 			 一定要有这段话,但是 因为 这段话 线程就会被卡死啦!  播放用的,产生流的 主要代码,应该就是了
  1. 注意在使用 vlc 的时候, 使用 udp 推流的时候!
    VLC 使用技巧以及教程:
    转换任何格式的文件:
    打开多个文件 -> 添加 -> 右下角播放那里的转换 -> 在目标文件中选择游览即可 -> 将改好的文件进行保存
    下载视频用(通过将网络地址视频 转换成本地的 mp4 视频)
    打开媒体 进入极端的先例或标签 -> 选择uri -> 为了保存而不是放置位置 -> 转换 -> 游览地址 -> 进行保存

  2. QVideoWidget 用来显示其他的视频, 视频最后的输出口 可以说是
    player = new QMediaPlayer;

    videoWidget = new QVideoWidget;
    player->setVideoOutput(videoWidget); 就可以输出视频到这个 窗口中了,然后 在窗口上可以进行显示

  3. GDK+ 也是一个图形化界面编程库, 其类似与 Qt 这样的库

  4. 直接播放 internet 上的文件而不在本地保存就被称为 流播放

最后

以上就是羞涩哈密瓜为你收集整理的Qt基础知识大全Mouse Release(%1,%2)Mouse Move(%1,%2)Mouse is enterMouse is leave告诉 qmake 这是哪种项目,由于构建的是一个应用程序,因此使用 app 模板声明了要从 C++ 使用的 Qt 库构建项目需要一个 C++11 兼容的编译器列出了应该编译的所有源文件,类似的变量 HEADERS 可用于头文件。告诉 qmake 有一个资源集合,应该被内置到可执行文件中。的全部内容,希望文章能够帮你解决Qt基础知识大全Mouse Release(%1,%2)Mouse Move(%1,%2)Mouse is enterMouse is leave告诉 qmake 这是哪种项目,由于构建的是一个应用程序,因此使用 app 模板声明了要从 C++ 使用的 Qt 库构建项目需要一个 C++11 兼容的编译器列出了应该编译的所有源文件,类似的变量 HEADERS 可用于头文件。告诉 qmake 有一个资源集合,应该被内置到可执行文件中。所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(33)

评论列表共有 0 条评论

立即
投稿
返回
顶部