Qt5开发及实例V2.0-第二章Qt模板库工具类及控件

news2024/9/24 3:24:48

Qt5开发及实例V2.0-第二章Qt模板库工具类及控件

  • 第2章 Qt 5模板库、工具类及控件
    • 2.1 字符串类
      • 2.1.1 操作字符串
      • 2.1.2 查询字符串数据
      • 2.1.3 字符串的转换
    • 2.2 容器类
      • 2.2.1 QList类、QLinkedList类和QVector类
      • 2.2.2 QMap类和QHash类
    • 2.3 QVariant类
    • 2.4 算法及正则表达式
      • 2.4.1 Qt 5常用算法
      • 2.4.2 基本的正则表达式
    • 2.5 控件
      • 2.5.1 按钮组(Buttons)
      • 2.5.2 输入部件组(Input Widgets)
      • 2.5.3 显示控件组(Display Widgets)
      • 2.5.4 空间间隔组(Spacers)
      • 2.5.5 布局管理组(Layouts)
      • 2.5.6 容器组(Containers)
      • 2.5.7 项目视图组(Item Views)
      • 2.5.8 项目控件组(Item Widgets)
    • L2.1 字符串类QString:概念解析
    • L2.5 Qt 5控件:概念解析
  • 本章相关例程源码下载
    • 1.Qt5开发及实例_CH201.rar 下载
    • 2.Qt5开发及实例_CH202.rar 下载
    • 3.Qt5开发及实例_CH203.rar 下载
    • 4.Qt5开发及实例_CH204.rar 下载
    • 5.Qt5开发及实例_CH205.rar 下载
    • 6.Qt5开发及实例_CH206.rar 下载
    • 7.Qt5开发及实例_CH207.rar 下载
    • 8.Qt5开发及实例_CH208.rar 下载
    • 9.Qt5开发及实例_CH209.rar 下载
    • 10.Qt5开发及实例_CH210.rar 下载

第2章 Qt 5模板库、工具类及控件

2.1 字符串类

2.1.1 操作字符串

字符串有如下几个操作符。
(1)QString提供了一个二元的“+”操作符用于组合两个字符串,并提供了一个“+=”操作符用于将一个字符串追加到另一个字符串的末尾,例如:

QString str1 = "Welcome ";
str1=str1+"to you! ";        		//str1=" Welcome to you! "
QString str2="Hello, ";
str2+="World! ";             		//str2="Hello,World! "

其中,QString str1 = "Welcome "传递给QString一个const char*类型的ASCII字符串“Welcome”,它被解释为一个典型的以“\0”结尾的C类型字符串。这将会导致调用QString构造函数,来初始化一个QString字符串。其构造函数原型为:

QT_ASCII_CAST_WARN_CONSTRUCTOR QString::QString(const char* str)

(2)QString::append()函数具有与“+=”操作符同样的功能,实现在一个字符串的末尾追加另一个字符串,例如:

QString str1 = "Welcome ";
QString str2 = "to ";
str1.append(str2);         	//str1=" Welcome to"
str1.append("you! ");      	//str1="Welcome to you! "

(3)组合字符串的另一个函数是QString::sprintf(),此函数支持的格式定义符和C++库中的函数sprintf()定义的一样。例如:

QString str;
str.sprintf("%s"," Welcome ");          		//str="Welcome "
str.sprintf("%s"," to you! ");           		//str="to you! "
str.sprintf("%s %s"," Welcome ", "to you! ");	//str=" Welcome to you! "

(4)Qt还提供了另一种方便的字符串组合方式,使用QString::arg()函数,此函数的重载可以处理很多的数据类型。此外,一些重载具有额外的参数对字段的宽度、数字基数或者浮点数精度进行控制。通常,相对于函数QString::sprintf(),函数QString::arg()是一个比较好的解决方案,因为它类型安全,完全支持Unicode,并且允许改变"%n"参数的顺序。例如:

QString str;
str=QString("%1 was born in %2.").arg("John").arg(1998);//str="John was born in 1998."

(5)QString也提供了一些其他组合字符串的方法,包括如下几种。
① insert()函数:在原字符串特定的位置插入另一个字符串。
② prepend()函数:在原字符串的开头插入另一个字符串。
③ replace()函数:用指定的字符串代替原字符串中的某些字符。
(6)很多时候,去掉一个字符串两端的空白(空白字符包括回车字符“\n”、换行字符“\r”、制表符“\t”和空格字符“ ”等)非常有用,如获取用户输入的账号时。
① QString::trimmed()函数:移除字符串两端的空白字符。
② QString::simplified()函数:移除字符串两端的空白字符,使用单个空格字符“ ”代替字符串中出现的空白字符。
例如:

QString str="  Welcome \t to \n you!     ";
str=str.trimmed();                    //str=" Welcome \t to \n you! "

2.1.2 查询字符串数据

查询字符串数据有多种方式,具体如下。
(1)函数QString::startsWith()判断一个字符串是否以某个字符串开头。此函数具有两个参数。第一个参数指定了一个字符串,第二个参数指定是否大小写敏感(默认情况下,是大小写敏感的),例如:

QString str="Welcome to you! ";
str.startsWith("Welcome",Qt::CaseSensitive); 	//返回true
str.startsWith("you",Qt::CaseSensitive);      	//返回false

(2)函数QString::endsWith()类似于QString::startsWith(),此函数判断一个字符串是否以某个字符串结尾。
(3)函数QString::contains()判断一个指定的字符串是否出现过,例如:

QString str=" Welcome to you! ";
str.contains("Welcome",Qt::CaseSensitive);   	//返回true

(4)比较两个字符串也是经常使用的功能,QString提供了多种比较手段。
① operator<(const QString&):比较一个字符串是否小于另一个字符串。如果是,则返回true。
② operator<=(const QString&):比较一个字符串是否小于等于另一个字符串。如果是,则返回true。
③ operator==(const QString&):比较两个字符串是否相等。如果相等,则返回true。
④ operator>=(const QString&):比较一个字符串是否大于等于另一个字符串。如果是,则返回true。
⑤ localeAwareCompare(const QString&,const QString&):静态函数,比较前后两个字符串。如果前面字符串小于后面字符串,则返回负整数值;如果等于则返回0;如果大于则返回正整数值。该函数的比较是基于本地(locale)字符集的,而且是平台相关的。
⑥ compare(const QString&,const QString&,Qt::CaseSensitivity):该函数可以指定是否进行大小写的比较,而大小写的比较是完全基于字符的Unicode编码值的,而且是非常快的,返回值类似于localeAwareCompare()函数。

2.1.3 字符串的转换

(1)QString::toInt()函数将字符串转换为整型数值,类似的函数还有toDouble()、toFloat()、toLong()、toLongLong()等。下面举个例子说明其用法:

QString str="125";		//初始化一个"125"的字符串
bool ok;
int hex=str.toInt(&ok,16);       	//ok=true,hex=293
int dec=str.toInt(&ok,10);       	//ok=true,dec=125

其中,int hex=str.toInt(&ok,16):调用QString::toInt()函数将字符串转换为整型数值。函数QString::toInt()有两个参数。

(2)QString提供的字符编码集的转换函数将会返回一个const char类型版本的QByteArray,即构造函数QByteArray(const char)构造的QByteArray对象。QByteArray类具有一个字节数组,它既可以存储原始字节(raw bytes),也可以存储传统的以“\0”结尾的8位的字符串。在Qt中,使用QByteArray比使用const char*更方便,且QByteArray也支持隐式共享。转换函数有以下几种。
① toAscii():返回一个ASCII编码的8位字符串。
② toLatin1():返回一个Latin-1(ISO8859-1)编码的8位字符串。
③ toUtf8():返回一个UTF-8编码的8位字符串(UTF-8是ASCII码的超集,它支持整个Unicode字符集)。
④ toLocal8Bit():返回一个系统本地(locale)编码的8位字符串。

下面举例说明其用法:

QString str=" Welcome to you! ";		//初始化一个字符串对象
QByteArray ba=str.toAscii();	 		//(a)
qDebug()<<ba;				//(b)
ba.append("Hello,World! ");			//(c)
qDebug()<<ba.data();			 	//输出最后结果

其中,
(a) QByteArray ba=str.toAscii():通过QString::toAscii()函数,将Unicode编码的字符串转换为ASCII码的字符串,并存储在QByteArray对象ba中。
(b) qDebug()<<ba:使用qDebug()函数输出转换后的字符串(qDebug()支持输出Qt对象)。
© ba.append(“Hello,World!”):使用QByteArray::append()函数追加一个字符串。

一个NULL字符串就是使用QString的默认构造函数或者使用“(const char*)0”作为参数的构造函数创建的QString字符串对象;而一个空字符串是一个大小为0的字符串。一个NULL字符串一定是一个空字符串,而一个空字符串未必是一个NULL字符串。例如:

QString().isNull();       			//结果为true
QString().isEmpty();      		//结果为true
QString("").isNull();     			//结果为false
QString("").isEmpty();   		//结果为true

2.2 容器类

这样的数据类型包含了通常使用的大多数数据类型,包括基本数据类型(如int和double等)和Qt的一些数据类型(如QString、QDate和QTime等)。不过,Qt的QObject及其他的子类(如QWidget和Qdialog等)是不能够存储在容器中的,例如:

QList<QToolBar> list;

上述代码是无法通过编译的,因为这些类(QObject及其他的子类)没有复制构造函数和赋值操作运算符。
一个可代替的方案是存储QObject及其子类的指针,例如:

QList<QToolBar*> list;

Qt的容器类是可以嵌套的,例如:

QHash<QString, QList<double> >

Qt的容器类为遍历其中的内容提供了以下两种方法。
(1)Java风格的迭代器(Java-style iterators)。
(2)STL风格的迭代器(STL-style iterators),能够同Qt和STL的通用算法一起使用,并且在效率上也略胜一筹。

2.2.1 QList类、QLinkedList类和QVector类

表2.1列出了QList、QLinkedList和QVector容器的时间复杂度比较。
在这里插入图片描述
其中,“Amort.O(1)”表示,如果仅完成一次操作,可能会有O(n)行为;但是如果完成多次操作(如n次),平均结果将会是O(1)。

1.QList类
QList是迄今为止最常用的容器类,它存储给定数据类型T的一列数值。继承自QList类的子类有QItemSelection、QQueue、QSignalSpy及QStringList和QTestEventList。
QList不仅提供了可以在列表中进行追加的QList::append()和Qlist::prepend()函数,还提供了在列表中间完成插入操作的函数QList::insert()。相对于任何其他的Qt容器类,为了使可执行代码尽可能少,QList被高度优化。
QList维护了一个指针数组,该数组存储的指针指向QList存储的列表项的内容。因此,QList提供了基于下标的快速访问。

对于不同的数据类型,QList采取不同的存储策略,存储策略有以下几种。
(1)如果T是一个指针类型或指针大小的基本类型(即该基本类型占有的字节数和指针类型占有的字节数相同),QList会将数值直接存储在它的数组中。
(2)如果QList存储对象的指针,则该指针指向实际存储的对象。
下面举一个例子:

#include <QDebug>
int main(int argc,char *argv[])
{
	QList<QString> list;					//(a)
	{
		QString str("This is a test string");
		list<<str;					//(b)
	}						//(c)
	qDebug()<<list[0]<< "How are you! ";
	return 0;
}

2.QLinkedList类
QLinkedList是一个链式列表,它以非连续的内存块保存数据。
QLinkedList不能使用下标,只能使用迭代器访问它的数据项。与QList相比,当对一个很大的列表进行插入操作时,QLinkedList具有更高的效率。
3.QVector类
QVector在相邻的内存中存储给定数据类型T的一组数值。在一个QVector的前部或者中间位置进行插入操作的速度是很慢的,这是因为这样的操作将导致内存中的大量数据被移动,这是由QVector存储数据的方式决定的。
QVector既可以使用下标访问数据项,也可以使用迭代器访问数据项。继承自QVector类的子类有QPolygon、QPolygonF和QStack。

4.Java风格迭代器遍历容器
对于每一个容器类,Qt都提供了两种类型的Java风格迭代器数据类型,即只读访问和读写访问,其分类见表2.2。
在这里插入图片描述
(1)QList只读遍历方法。
【例】(简单)(CH201)通过控制台程序实现QList只读遍历方法。
其具体代码如下:

#include <QCoreApplication>	
#include <QDebug>			//(a)
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);		//(b)
    QList<int> list;			//创建一个QList<int>栈对象list
    list<<1<<2<<3<<4<<5;			//用操作运算符“<<”输入五个整数
    QListIterator<int> i(list);		//(c)
    for(;i.hasNext();)			//(d)
        qDebug()<<i.next();
    return a.exec();
}

其中,
(a) 头文件中已经包含了QList的头文件。
(b)Qt的一些类,如QString、QList等,不需要QCoreApplication的支持也能够工作,但是,在使用Qt编写应用程序时,如果是控制台应用程序,则建议初始化一个QCoreApplication对象,Qt 5.8创建控制台项目时生成的main.cpp源文件中默认就创建了一个QcoreApplication对象;如果是GUI图形用户界面程序,则会初始化一个QApplication对象。
© QListIterator i(list):以该list为参数初始化一个QListIterator对象i。此时,迭代点处在第一个列表项“1”的前面(注意,并不是指向该列表项)。
(d) for(;i.hasNext()😉:调用QListIterator::hasNext()函数检查当前迭代点之后是否有列表项。
最后程序的运行结果为:
1 2 3 4 5

上例是QListIterator对列表进行向后遍历的函数,而对列表进行向前遍历的函数有如下几种。
QListIterator::toBack():将迭代点移动到最后一个列表项的后面。
QListIterator::hasPrevious():检查当前迭代点之前是否具有列表项。
QListIterator::previous():返回前一个列表项的内容并将迭代点移动到前一个列表项之前。
除此之外,QListIterator提供的其他函数还有如下几种。
toFront():移动迭代点到列表的前端(第一个列表项的前面)。
peekNext():返回下一个列表项,但不移动迭代点。
peekPrevious():返回前一个列表项,但不移动迭代点。
findNext():从当前迭代点开始向后查找指定的列表项,如果找到,则返回true,此时迭代点位于匹配列表项的后面;如果没有找到,则返回false,此时迭代点位于列表的后端(最后一个列表项的后面)。
findPrevious():与findNext()类似,不同的是它的方向是向前的,查找操作完成后的迭代点在匹配项的前面或整个列表的前端。

(2)QListIterator是只读迭代器,它不能完成列表项的插入和删除操作
读写迭代器QMutableListIterator除了提供基本的遍历操作(与QListIterator的操作相同)外,还提供了insert()插入操作函数、remove()删除操作函数和修改数据函数等。

【例】(简单)(CH202)通过控制台程序实现QList读写遍历方法。
具体代码如下:

#include <QCoreApplication>
#include <QDebug>
int main(int argc,char *argv[])
{
	QCoreApplication a(argc, argv);
	QList<int> list;				//创建一个空的列表list
	QMutableListIterator<int> i(list);		//创建上述列表的读写迭代器
	for(int j=0;j<10;++j)
		i.insert(j);				//(a)
	for(i.toFront();i.hasNext();)			//(b)
		qDebug()<<i.next();
	for(i.toBack();i.hasPrevious();)			//(c)
	{
		if(i.previous()%2==0)
			i.remove();
		else
	        i.setValue(i.peekNext()*10);		//(d)
	}
	for(i.toFront();i.hasNext();)			//重新遍历并输出列表
		    qDebug()<<i.next();
	return a.exec();
}

其中,
(a) i.insert(j):通过QMutableListIterator::insert()插入操作,为该列表插入10个整数值。
(b) for(i.toFront();i.hasNext()😉、qDebug()<<i.next():将迭代器的迭代点移动到列表的前端,完成对列表的遍历和输出。
© for(i.toBack();i.hasPrevious()😉{…}:移动迭代器的迭代点到列表的后端,对列表进行遍历。如果前一个列表项的值为偶数,则将该列表项删除;否则,将该列表项的值修改为原来的10倍。
(d) i.setValue(i.peekNext()*10):函数QMutableListIterator::setValue()修改遍历函数next()、previous()、findNext()和findPrevious()跳过的列表项的值,但不会移动迭代点的位置。对于findNext()和findPrevious()有些特殊:当findNext()(或findPrevious())查找到列表项的时候,setValue()将会修改匹配的列表项;如果没有找到,则对setValue()的调用将不会进行任何修改。
最后编译,运行此程序,程序运行结果如下:
0 1 2 3 4 5 6 7 8 9
10 30 50 70 90

5.STL风格迭代器遍历容器
对于每一个容器类,Qt都提供了两种类型的STL风格迭代器数据类型:一种提供只读访问;另一种提供读写访问。由于只读类型的迭代器的运行速度要比读写迭代器的运行速度快,所以应尽可能地使用只读类型的迭代器。STL风格迭代器的两种分类见表2.3。
在这里插入图片描述

【例】(简单)(CH203)使用STL风格迭代器。
实现代码如下:

#include <QCoreApplication>
#include <QDebug>
int main(int argc,char *argv[])
{
	QCoreApplication a(argc, argv);
	QList<int> list;			//初始化一个空的QList<int>列表
	for(int j=0;j<10;j++)
		list.insert(list.end(),j);	//(a)
	QList<int>::iterator i;
				//初始化一个QList<int>::iterator读写迭代器
	for(i=list.begin();i!=list.end();++i)	//(b)
	{
		   qDebug()<<(*i);
		   *i=(*i)*10;
	}
	//初始化一个QList<int>:: const_iterator读写迭代器
	QList<int>::const_iterator ci;
	//在控制台输出列表的所有值
	for(ci=list.constBegin();ci!=list.constEnd();++ci)
		    qDebug()<<*ci;
	return a.exec();
}

其中,
(a) list.insert(list.end(),j):使用QList::insert()函数插入10个整数值。此函数有两个参数:第一个参数是QList::iterator类型,表示在该列表项之前插入一个新的列表项(使用QList::end()函数返回的迭代器,表示在列表的最后插入一个列表项);第二个参数指定了需要插入的值。
(b) for(i=list.begin();i!=list.end();++i){…}:在控制台输出列表的同时将列表的所有值增大10倍。这里用到两个函数:QList::begin()函数返回指向第一个列表项的迭代器;QList::end()函数返回一个容器最后列表项之后的虚拟列表项,为标记无效位置的迭代器,用于判断是否到达容器的底部。
最后编译、运行此应用程序,输出结果如下:
0 1 2 3 4 5 6 7 8 9
0 10 20 30 40 50 60 70 80 90

2.2.2 QMap类和QHash类

QMap类和QHash类具有非常类似的功能,它们的差别仅在于:
 QHash具有比QMap更快的查找速度。
 QHash以任意的顺序存储数据项,而QMap总是按照键Key的顺序存储数据。
 QHash的键类型Key必须提供operator==()和一个全局的qHash(Key)函数,而QMap的键类型Key必须提供operator<()函数。
二者的时间复杂度比较见表2.4。
在这里插入图片描述
其中,“Amort.O(1)”表示,如果仅完成一次操作,则可能会有O(n)行为;如果完成多次操作(如n次),则平均结果将是O(1)。

1.QMap类
QMap<Key,T>提供了一个从类型为Key的键到类型为T的值的映射。
通常,QMap存储的数据形式是一个键对应一个值,并且按照键Key的顺序存储数据。为了能够支持一键多值的情况,QMap提供了QMap<Key,T>::insertMulti()和QMap<Key,T>::values()函数。存储一键多值的数据时,也可以使用QMultiMap<Key,T>容器,它继承自Qmap

2.QHash类
QHash<Key,T>具有与QMap几乎完全相同的API。QHash维护着一张哈希表(Hash Table),哈希表的大小与QHash的数据项的数目相适应。
QHash以任意的顺序组织它的数据。当存储数据的顺序无关紧要时,建议使用QHash作为存放数据的容器。QHash也可以存储一键多值形式的数据,它的子类QMultiHash<Key,T>实现了一键多值的语义。

3.Java风格迭代器遍历容器
对于每一个容器类,Qt都提供了两种类型的Java风格迭代器数据类型:一种提供只读访问;另一种提供读写访问。其分类见表2.5。
在这里插入图片描述

【例】(简单)(CH204)在QMap中的插入、遍历和修改。
实现代码如下:

#include <QCoreApplication>
#include <QDebug>
int main(int argc,char *argv[])
{
	QCoreApplication a(argc, argv);
	QMap<QString,QString> map;			//创建一个QMap栈对象
	//向栈对象插入<城市,区号>对
	map.insert("beijing","111");
	map.insert("shanghai","021");
	map.insert("nanjing","025");
	QMapIterator<QString,QString> i(map);		//创建一个只读迭代器
	for(;i.hasNext();)							//(a)
		qDebug()<<"  "<<i.key()<<"  "<<i.next().value();
	QMutableMapIterator<QString,QString> mi(map);
	if(mi.findNext("111"))				//(b)
		mi.setValue("010");
	QMapIterator<QString,QString> modi(map);
	qDebug()<<"  ";
	for(;modi.hasNext();)				//再次遍历并输出修改后的结果
		qDebug()<<" "<<modi.key()<<"  "<<modi.next().value();
	return a.exec();
}

其中,
(a) for(;i.hasNext()😉、qDebug()<<" “<<i.key()<<” "<<i.next().value():完成对QMap的遍历输出。在输出QMap的键和值时,调用的函数是不同的。因为在输出键的时候,不需要使迭代点移动到下一个位置,所以调用了QMapIterator<T,T>::key();而在输出值的时候调用了QMapIterator <T,T>::next()。
(b) if(mi.findNext(“111”))、mi.setValue(“010”):首先查找某个<键,值>对,然后修改值。Java风格的迭代器没有提供查找键的函数。因此,在本例中通过查找值的函数QMutableMapIterator<T,T>::findNext()来实现查找和修改。
最后编译、运行此程序,程序运行结果如下:

"beijing"   	"111"
"nanjing"   	"025"
"shanghai" 	"021"
"beijing"  	"010"
"nanjing"  	"025"
"shanghai" 	"021"

4.STL风格迭代器遍历容器
对于每一个容器类,Qt都提供了两种类型的STL风格迭代器数据类型:一种提供只读访问;另一种提供读写访问。其分类见表2.6。
在这里插入图片描述
【例】(简单)(CH205)功能与使用Java风格迭代器的例子基本相同。不同的是,这里通过查找键来实现值的修改。
实现代码如下:

#include <QCoreApplication>
#include <QDebug>
int main(int argc,char *argv[])
{
	QCoreApplication a(argc, argv);
	QMap<QString,QString> map;
	map.insert("beijing","111");
	map.insert("shanghai","021");
	map.insert("nanjing","025");
		QMap<QString,QString>::const_iterator i;
	for(i=map.constBegin();i!=map.constEnd();++i)
		qDebug()<<"  "<<i.key()<<"  "<<i.value();
	QMap<QString,QString>::iterator mi;
	mi=map.find("beijing");
	if(mi!=map.end())
		mi.value()="010";				//(a)
	QMap<QString,QString>::const_iterator modi;
	qDebug()<<"  ";
	for(modi=map.constBegin();modi!=map.constEnd();++modi)
		qDebug()<<"  "<<modi.key()<<"  "<<modi.value();
	return a.exec();
}

2.3 QVariant类

【例】(简单)(CH206)QVariant类的用法。
新建Qt Widgets Application(详见1.3.1节),项目名称为“myVariant”,基类选择“QWidget”,类名保持“Widget”不变,取消选择“创建界面”复选框。建好项目后,在widget.cpp文件中编写代码,具体内容如下。

其中,
(a) QVariant v(709):声明一个QVariant变量v,并初始化为一个整数。此时,QVariant变量v包含了一个整数变量。
(b) qDebug()<<v.toInt():调用QVariant::toInt()函数将QVariant变量包含的内容转换为整数并输出。
© QVariant w("How are you! "):声明一个QVariant变量w,并初始化为一个字符串。
(d) qDebug()<<w.toString():调用QVariant::toString()函数将QVariant变量包含的内容转换为字符串并输出。
(e) QMap<QString,QVariant>map:声明一个QMap变量map,使用字符串作为键,QVariant变量作为值。
(f) qDebug()<<map[“color”]<< map[“color”].value():在QVariant变量中保存了一个QColor对象,并使用模板QVariant::value()还原为QColor,然后输出。

(g) if(slv.type()==QVariant::StringList):QVariant::type()函数返回存储在QVariant变量中的值的数据类型。QVariant::StringList是Qt定义的一个QVariant::type枚举类型的变量,其他常用的枚举类型变量见表2.7。
在这里插入图片描述
最后,运行上述程序的结果如下:

709
"How are you! "
QVariant(int,709) 709
QVariant(double,709.709) 709.709
QVariant(QString, "How are you! ") "How are you! "
QVariant(QColor, QColor(ARGB 1,1,0,0)) QColor(ARGB 1,1,0,0)
"A"
"B"
"C"
"D"

2.4 算法及正则表达式

2.4.1 Qt 5常用算法

【例】(简单)(CH207)几个常用算法。

#include <QCoreApplication>
#include <QDebug>
int main(int argc,char *argv[])
{
	QCoreApplication a0(argc, argv);
	double a=-19.3,b=9.7;
	double c=qAbs(a);        				//(a)
	double max=qMax(b,c);    				//(b) 
	int bn=qRound(b);        				//(c)
	int cn=qRound(c);        	
	qDebug()<<"a="<<a;
	qDebug()<<"b="<<b;
	qDebug()<<"c=qAbs(a)= "<<c;
	qDebug()<<"qMax(b,c)= "<<max;
	qDebug()<<"bn=qRound(b)= "<<bn;
	qDebug()<<"cn=qRound(c)= "<<cn;
	qSwap(bn,cn);							//(d)
	//调用qDebug()函数输出所有的计算结果
	qDebug()<<"qSwap(bn,cn):"<<"bn="<<bn<<" cn="<<cn;
	return a0.exec();
}

其中,
(a) double c=qAbs(a):函数qAbs()返回double型数值a的绝对值,并赋值给c(c=19.3)。
(b) double max=qMax(b,c):函数qMax()返回两个数值中的最大值(max=c=19.3)。
© int bn=qRound(b):函数qRound()返回与一个浮点数最接近的整数值,即四舍五入返回一个整数值(bn=10,cn=19)。
(d) qSwap(bn,cn):函数qSwap()交换两数的值。
最后,编译运行上述程序,输出结果如下:

a= -19.3
b= 9.7
c=qAbs(a)= 19.3
qMax(b,c)= 19.3
bn=qRound(b)= 10
cn=qRound(c)= 19
qSwap(bn,cn):  bn= 19   cn= 10

2.4.2 基本的正则表达式

正则表达式由表达式(expressions)、量词(quantifiers)和断言(assertions)组成。
(1)最简单的表达式是一个字符。字符集可以使用表达式如“[AEIOU]”,表示匹配所有的大写元音字母;使用“[^AEIOU]”则表示匹配所有非元音字母,即辅音字母;连续的字符集可以使用表达式如“[a-z]”,表示匹配所有的小写英文字母。
(2)量词说明表达式出现的次数,如“x[1,2]”表示“x”可以至少有一个,至多两个。
在计算机语言中,标识符通常要求以字母或下画线(也称下划线)开头,后面可以是字母、数字和下画线。满足条件的标识符表示为:

" [A-Za-z_]+[A-Za-z_0-9]* "

其中,表达式中的“+”表示“[A-Za-z_]”至少出现一次,可以出现多次;“*”表示“[A-Za-z_0-9]”可以出现零次或多次。
类似的正则表达式的量词见表2.8。
在这里插入图片描述
(3)“^”、“$”、“\b”都是正则表达式的断言,正则表达式的断言见表2.9。
在这里插入图片描述

2.5 控件

2.5.1 按钮组(Buttons)

按钮组(Buttons)如图2.1所示。
在这里插入图片描述

【例】(简单)(CH208)以QPushButton为例介绍按钮的用法。
(1)新建Qt Widgets Application(详见1.3.1节),项目名为“PushButtonTest”,基类选择“QWidget”选项,类名命名为“MyWidget”,取消“创建界面”复选框的选中状态。
(2)在头文件“mywidget.h”中的具体代码如下:

#ifndef MYWIDGET_H
#define MYWIDGET_H
 
#include <QWidget>
 
class MyWidget : public QWidget
{
    Q_OBJECT
 
public:
    MyWidget(QWidget *parent = 0);
    ~MyWidget();
};
 
#endif // MYWIDGET_H

(3)在源文件“mywidget.cpp”中的具体代码如下:

#include "mywidget.h"
#include <qapplication.h>
#include <qpushbutton.h>
#include <qfont.h>
MyWidget::MyWidget(QWidget *parent)
    : QWidget(parent)
{
       setMinimumSize( 200, 120 );
       setMaximumSize( 200, 120 );
       QPushButton *quit = new QPushButton( "Quit", this);
       quit->setGeometry( 62, 40, 75, 30 );
       quit->setFont( QFont( "Times", 18, QFont::Bold ) );
       connect( quit, SIGNAL(clicked()), qApp, SLOT(quit()) );
}
MyWidget::~MyWidget()
{
}

(4)在源文件“main.cpp”中的具体代码如下:

#include "mywidget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MyWidget w;
    w.setGeometry( 100, 100, 200, 120 );
    w.show();
    return a.exec();
}

(5)运行结果如图2.2所示。
在这里插入图片描述

2.5.2 输入部件组(Input Widgets)

输入部件组(Input Widgets)如图2.3所示,组中各个部件的名称依次解释如下。
在这里插入图片描述
1.QDateTime类
Date/Time Edit对应于QDateTime类,在Qt 5中可以使用它来获得系统时间。通过QDateTime::currentDateTime()来获取本地系统的时间和日期信息。可以通过date()和time()来返回datetime中的日期和时间部分,典型代码如下:

QLabel * datalabel =new QLabel();
QDateTime *datatime=new QDateTime(QDateTime::currentDateTime());
datalabel->setText(datatime->date().toString()); 
datalabel->show();

2.QTimer类
定时器(QTimer)的使用非常简单,只需要以下几个步骤就可以完成定时器的应用。
(1)新建一个定时器。

QTimer *time_clock=new QTimer(parent);

(2)连接这个定时器的信号和槽,利用定时器的timeout()。

connect(time_clock,SIGNAL(timeout()),this,SLOT(slottimedone()));

即定时时间一到就会发送timeout()信号,从而触发slottimedone()槽去完成某件事情。
(3)开启定时器,并设定定时周期。
定时器定时有两种方式:start(int time)和setSingleShot(true)。其中,start(int time)表示每隔“time”秒就会重启定时器,可以重复触发定时,利用stop()将定时器关掉;而setSingleShot(true)则是仅启动定时器一次。工程中常用的是前者,例如:

time_clock->start(2000);

2.5.3 显示控件组(Display Widgets)

显示控件组(Display Widgets)如图2.4所示。
显示控件组(Display Widgets)中各个控件的名称依次解释如下。
 Label:标签。
 Text Browser:文本浏览器。
 Graphics View:图形视图。
 Calendar Widget:日历。
 LCD Number:液晶数字。
 Progress Bar:进度条。
 Horizontal Line:水平线。
 Vertical Line:垂直线。
 OpenGL Widget:开放式图形库工具。
 QQuickWidget:嵌入QML工具。
在这里插入图片描述

1.Graphics View
Graphics View对应于QGraphicsView类,提供了Qt 5的图形视图框架。
2.Text Browser
Text Browser对应于QTextBrowser类。QTextBrowser类继承自QTextEdit,而且仅是只读的,对里面的内容并不能进行更改,但是相对于QTextEdit来讲,它还具有链接文本的作用。QTextBrowser的属性有以下几点:

modified : const bool          //通过布尔值来说明其内容是否被修改
openExternalLinks : bool
openLinks : bool
readOnly : const bool
searchPaths : QStringList
source : QUrl
undoRedoEnabled : const bool

通过以上的属性设置,可以设定QTextBrowser是否允许外部链接,是否为只读属性,外部链接的路径及链接的内容,是否可以进行撤销等操作。
QTextBrowser还提供了几种比较有用的槽(SLOTS),即

virtual void backward()
virtual void forward()
virtual void home()

可以通过链接这几个槽来达到人们常说的“翻页”效果。

3.QQuickWidget
这是Qt 5.3发布的一个组件,传统QWidget程序可以用它来嵌入QML代码,为Qt开发者将桌面应用迁移到Qt Quick提供了方便,但目前在QML中尚不能嵌入其他非QML窗口,因为QML的渲染机制和QWidget的是不一样的。

2.5.4 空间间隔组(Spacers)

空间间隔组(Spacers)如图2.5所示。
在这里插入图片描述
空间间隔组(Spacers)中各个控件的名称依次解释如下。
 Horizontal Spacer:水平间隔。
 Vertical Spacer:垂直间隔。

2.5.5 布局管理组(Layouts)

布局管理组(Layouts)如图2.6所示。
在这里插入图片描述
布局管理组(Layouts)中各个控件的名称依次解释如下。
 Vertical Layout:垂直布局。
 Horizontal Layout:横向(水平)布局。
 Grid Layout:网格布局。
 Form Layout:表单布局。

2.5.6 容器组(Containers)

容器组(Containers)如图2.7所示。
容器组(Containers)中各个控件的名称依次解释如下。
Group Box:组框。
 Scroll Area:滚动区域。
 Tool Box:工具箱。
 Tab Widget:标签小部件。
 Stacked Widget:堆叠部件。
 Frame:帧。
 Widget:小部件。
 MDI Area:MDI区域。
 Dock Widget:停靠窗体部件。
 QAxWidget:封装Flash的ActiveX控件。
在这里插入图片描述
1.创建窗口
如果Widget未使用父级进行创建,则在显示时视为窗口或顶层Widget。由于顶层Widget没有父级对象类来确保在其不再使用时就删除,所以需要开发人员在应用程序中对其进行跟踪。
例如,使用QWidget创建和显示具有默认大小的窗口:

QWidget *window = new QWidget();
window->resize(320, 240);
window->show();
QPushButton *button = new QPushButton(tr("Press me"), window);	//(a)
button->move(100, 100);
button->show();

其中,
(a) QPushButton *button = new QPushButton(tr(“Press me”), window);:通过将window作为父级传递给其构造器来向窗口添加子Widget:button。在这种情况下,向窗口添加按钮并将其放置在特定位置。

2.使用布局
通常,子Widget是通过使用布局对象在窗口中进行排列的,而不是通过指定位置和大小进行排列的。在此,构造一个并排排列的标签和行编辑框Widget:

QLabel *label = new QLabel(tr("Name:"));
QLineEdit *lineEdit = new QLineEdit();
QHBoxLayout *layout = new QHBoxLayout();
layout->addWidget(label);
layout->addWidget(lineEdit);
window->setLayout(layout);

构造的布局对象管理通过addWidget()函数提供Widget的位置和大小。布局本身是通过调用setLayout()提供给窗口的。

由于Widget可包含其他Widget,所以布局可用来提供按不同层次分组的Widget。这里,要在显示查询结果的表视图上方、窗口顶部的行编辑框旁,显示一个标签:

QLabel *queryLabel = new QLabel(tr("Query:"));
QLineEdit *queryEdit = new QLineEdit();
QTableView *resultView = new QTableView();
QHBoxLayout *queryLayout = new QHBoxLayout();
queryLayout->addWidget(queryLabel);
queryLayout->addWidget(queryEdit);
QVBoxLayout *mainLayout = new QVBoxLayout();
mainLayout->addLayout(queryLayout);
mainLayout->addWidget(resultView);
window->setLayout(mainLayout);

除QHBoxLayout和QVBoxLayout外,Qt还提供了QGridLayout和QFormLayout类用于协助实现更复杂的用户界面。

2.5.7 项目视图组(Item Views)

项目视图组(Item Views)如图2.8所示。
在这里插入图片描述
项目视图组(Item Views)中各个控件的名称依次解释如下。
 List View:清单视图。
 Tree View:树视图。
 Table View:表视图。
 Column View:列视图。

Widget的区别,其具体区别见表2.10。
在这里插入图片描述
 模型:所有的模型都基于QAbstractItemModel类,该类是抽象基类。
 视图:所有的视图都从抽象基类QAbstractItemView继承。
InterView框架提供了一些常见的模型类和视图类,如QStandardItemModel、QDirModel、QStringListModel、QProxyModel和QColumnView、QHeaderView、QListView、QTableView、QTreeView。

QTableWidget继承自QTableView。QSqlTableModel能够与QTableView绑定,但不能与QTableWidget绑定。例如:

QSqlTableModel *model = new QSqlTableModel;
model->setTable("employee");
model->setEditStrategy(QSqlTableModel::OnManualSubmit);
model->select();
model->removeColumn(0); //不显示 ID
model->setHeaderData(0, Qt::Horizontal, tr("Name"));
model->setHeaderData(1, Qt::Horizontal, tr("Salary"));
QTableView *view = new QTableView;
view->setModel(model);
view->show();

视图与模型绑定时,模型必须使用new创建,否则视图不能随着模型的改变而改变。

下面是错误的写法:

QStandardItemModel model(4,2);
model.setHeaderData(0, Qt::Horizontal, tr("Label"));
model.setHeaderData(1, Qt::Horizontal, tr("Quantity"));
ui.tableView->setModel(&model);
for (int row = 0; row < 4; ++row) 
{
	for (int column = 0; column < 2; ++column) 
	{
		QModelIndex index = model.index(row, column, QModelIndex());
		model.setData(index, QVariant((row+1) * (column+1)));
	}
}

下面是正确的写法:

QStandardItemModel *model;
model = new QStandardItemModel(4,2);
ui.tableView->setModel(model);
model->setHeaderData(0, Qt::Horizontal, tr("Label"));
model->setHeaderData(1, Qt::Horizontal, tr("Quantity"));
for (int row = 0; row < 4; ++row) 
{
	for (int column = 0; column < 2; ++column) 
	{
		QModelIndex index = model->index(row, column, QModelIndex());
		model->setData(index, QVariant((row+1) * (column+1)));
	}
}

2.5.8 项目控件组(Item Widgets)

项目控件组(Item Widgets)如图2.9所示。
在这里插入图片描述
项目控件组(Item Widgets)中各个控件的名称依次解释如下。
 List Widget:清单控件。
 Tree Widget:树形控件。
 Table Widget:表控件。

【例】(难度中等( CH209 ) 创建具有复选框的树形控件。
在Qt中,树形控件称为QTreeWidget,而控件里的树节点称为QTreeWidgetItem。这种控件有时很有用处。例如,利用飞信软件群发短信时,选择联系人的界面中就使用了有复选框的树形控件,如图2.10所示。
在这里插入图片描述

要实现这种界面其实很简单。首先在Qt的设计器中,拖曳出一个QTreeWidget,然后在主窗口中编写一个函数init初始化界面,连接树形控件的节点改变信号itemChanged(QTreeWidgetItem* item, int column),实现这个信号即可。
实现步骤如下。
(1)新建Qt Widgets Application(详见1.3.1节),项目名称为“TreeWidget”,基类选择“QWidget”,类名保持“Widget”不变,保持“创建界面”复选框的选中状态。
(2)双击“widget.ui”文件,打开Qt的设计器,拖曳出一个QTreeWidget控件。
(3)在头文件“widget.h”中添加代码:
#include
在类Widget声明中添加代码:

public:
    void init();
    void updateParentItem(QTreeWidgetItem* item);
public slots:
    void treeItemChanged(QTreeWidgetItem* item, int column);

(4)在源文件“widget.cpp”中的类Widget构造函数中添加代码:

init();
connect(ui->treeWidget,SIGNAL(itemChanged(QTreeWidgetItem*, int)),
            this, SLOT(treeItemChanged(QTreeWidgetItem*, int)));

在此文件中实现各个函数的具体代码。
函数treeItemChanged()的具体实现代码。
函数updateParentItem()的具体实现代码。
(5)运行结果如图2.10所示。

L2.1 字符串类QString:概念解析

L1 隐式共享
隐式共享可以降低对内存和CPU资源的使用率,提高程序的运行效率。它使得在函数中(如参数、返回值)使用值传递更有效率。
QString类采用隐式共享技术,将深拷贝和浅拷贝有机地结合起来。
下面通过一个例子来具体介绍隐式共享是如何工作的。

QString str1="data";		//初始化一个内容为“data”的字符串
QString str2=str1;        	//(a)
str2[3]= 'e';             		//(b)
str2[0]= 'f';             		//(c)
str1=str2;			//(d)

其中,
(a) QString str2=str1:将该字符串对象str1赋值给另一个字符串str2(由QString的复制构造函数完成str2的初始化),此时str2=“data”。在对str2赋值的时候,将发生一次浅拷贝,导致两个QString对象都指向同一个数据结构。
(b) str2[3]= ‘e’:对QString对象str2的修改,将会导致一次深拷贝,使得str2对象指向一个新的、不同于str1所指的数据结构(该数据结构的引用计数为1,因为只有str2指向这个数据结构),同时修改原来的str1指向的数据结构,设置它的引用计数为1(此时,只有QString对象str1指向该数据结构)。
© str2[0]= ‘f’:进一步对QString对象str2进行修改,但这个操作不会引起任何形式的复制,因为str2指向的数据结构没有被共享。此时,str2=“fate”,str1=“data”。
(d) str1=str2:将str2赋值给str1。此时,str1将它指向的数据结构的引用计数器的值修改为0,也就是说,没有QString对象再使用这个数据结构了。
Qt中支持隐式共享的类,还包括:
 所有的容器类;
 QByteArray、QBrush、QPen、QPalette、QBitmap、QImage、QPixmap、QCursor、QDir、QFont和QVariant等。

L2 内存分配策略
QString在一个连续的内存块中保存字符串数据。当字符串的长度不断增长时,QString需要重新分配内存空间,以便有足够的空间保存增加的字符串。QString使用的内存分配策略如下。
 每次分配4个字符空间,直到大小为20。
 在20~4 084之间,QString分配的内存块大小以2倍的速度增长。
 从4 084开始,每次以2 048个字符大小(4 096字节,即4KB)的步长增长。
下面举例具体说明QString在后台是如何运行的:

QString test()
{
	QString str;
	for(int i=0;i<9000;++i)
		str.append("a");
	return str;
}

L2.5 Qt 5控件:概念解析

Qt::WindowFlags枚举类型
Qt::WindowFlags枚举类型有以下几种形式。
 Qt::Widget:QWidget构造函数的默认值,如果新的窗口部件没有父窗口部件,则它是一个独立的窗口,否则就是一个子窗口部件。
 Qt::Window:无论是否有父窗口部件,新窗口部件都是一个窗口,通常有一个窗口边框和一个标题栏。
 Qt::Dialog:新窗口部件是一个对话框,它是QDialog构造函数的默认值。
 Qt::Sheet:新窗口部件是一个Macintosh表单(sheet)。
 Qt::Drawer:新窗口部件是一个Macintosh抽屉(drawer)。
 Qt::Popup:新窗口部件是一个弹出式顶层窗口。
 Qt::Tool:新窗口部件是一个工具(tool)窗口,它通常是一个用于显示工具按钮的小窗口。
 Qt::ToolTip:新窗口部件是一个提示窗口,没有标题栏和窗口边框。
 Qt::SplashScreen:新窗口部件是一个欢迎窗口(splash screen),它是QSplashScreen构造函数的默认值。
 Qt::Desktop:新窗口部件是桌面,它是QDesktopWidget构造函数的默认值。
 Qt::SubWindow:新窗口部件是一个子窗口,而无论该窗口部件是否有父窗口部件。
 Qt::MSWindowsFiredSizeDialogHint:为Windows系统上的窗口装饰一个窄的对话框边框,通常这个提示用于固定大小的对话框。
 Qt::MSWindowsOwnDC:为Windows系统上的窗口添加自身的显示上下文(display context)菜单。
 Qt::X11BypassWindowManagerHint:完全忽视窗口管理器,它的作用是产生一个根本不被管理的无窗口边框的窗口(此时,用户无法使用键盘进行输入,除非手动调用QWidget::activateWindow()函数)。
 Qt::FramelessWindowHint:产生一个无窗口边框的窗口,此时用户无法移动该窗口和改变它的大小。
 Qt::CustomizeWindowHint:关闭默认的窗口标题提示。
 Qt::WindowTitleHint:为窗口装饰一个标题栏。
 Qt::WindowSystemMenuHint:为窗口添加一个窗口系统菜单,并尽可能地添加一个关闭按钮。
 Qt::WindowMinimizeButtonHint:为窗口添加一个“最小化”按钮。
 Qt::WindowMaximizeButtonHint:为窗口添加一个“最大化”按钮。
 Qt::WindowMinMaxButtonsHint:为窗口添加一个“最小化”按钮和一个“最大化”按钮。
 Qt::WindowContextHelpButtonHint:为窗口添加一个“上下文帮助”按钮。
 Qt::WindowStaysOnTopHint:告知窗口系统,该窗口应该停留在所有其他窗口的上面。
 Qt::WindowType_Mask:一个用于提取窗口标识中的窗口类型部分的掩码。

枚举类型Qt::WindowFlags低位的1个字节用于定义窗口部件的窗口类型, 0x00000000~0x00000012共定义了11个窗口类型。Qt::WindowFlags的高位字节定义了窗口提示,窗口提示能够进行位或操作,例如:

Qt:: WindowContextHelpButtonHint | Qt:: WindowMaximizeButtonHint

当Qt:: WindowFlags的窗口提示部分全部为0时,窗口提示不起作用。当有一个窗口提示被应用时,若要其他的窗口提示起作用,则必须使用位或操作(如果窗口系统支持这些窗口提示的话)。例如:

Qt:: WindowFlags  flags = Qt:: Window;
widget->setWindowFlags(flags);

widget窗口部件是一个窗口,它有一般窗口的外观(有窗口边框、标题栏、“最小化”按钮、“最大化”按钮和“关闭”按钮等),此时窗口提示不起作用。例如:

flags  |= Qt:: WindowTitleHint;
widget->setWindowFlags(flags);

在Windows系统中,如果需要添加一个“最小化”按钮,则必须重新设置窗口部件的窗口标识(在红旗Linux工作站和SUSE系统上,下面的窗口提示也被忽略了),具体如下:

flags  |= Qt:: WindowMinimizeButtonHint;
widget->setWindowFlags(flags);

如果要取消设置的窗口0提示,则具体代码如下:

flags  &= Qt:: WindowType_Mask;
widget->setWindowFlags(flags);

本章相关例程源码下载

1.Qt5开发及实例_CH201.rar 下载

Qt5开发及实例_CH201.rar

2.Qt5开发及实例_CH202.rar 下载

Qt5开发及实例_CH202.rar

3.Qt5开发及实例_CH203.rar 下载

Qt5开发及实例_CH203.rar

4.Qt5开发及实例_CH204.rar 下载

Qt5开发及实例_CH204.rar

5.Qt5开发及实例_CH205.rar 下载

Qt5开发及实例_CH205.rar

6.Qt5开发及实例_CH206.rar 下载

Qt5开发及实例_CH206.rar

7.Qt5开发及实例_CH207.rar 下载

Qt5开发及实例_CH207.rar

8.Qt5开发及实例_CH208.rar 下载

Qt5开发及实例_CH208.rar

9.Qt5开发及实例_CH209.rar 下载

Qt5开发及实例_CH209.rar

10.Qt5开发及实例_CH210.rar 下载

Qt5开发及实例_CH210.rar

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1019775.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spring编程常见错误50例-Spring Bean依赖注入常见错误(下)

Value没有注入预期的值 问题 对于Value可以装配多种类型的数据&#xff1a; 装配对象&#xff1a; Value("#{student}") private Student student;Bean public Student student(){Student student createStudent(1, "xie");return student; }装配字符…

【Nuxt3】Vue3 + Element-plus 打包后报错 @popperjs/core

问题&#xff1a; 更新 Element-plus 后&#xff0c;运行时需要安装 popperjs/core 依赖。 如果正常执行 npm install popperjs/core &#xff0c;那么&#xff0c;打包时&#xff0c;就会出现下面报错。 Named export ‘placements’ not found. The requested module ‘poppe…

Python | 为FastAPI后端服务添加API Key认证(分别基于路径传参和header两种方式且swagger文档友好支持)

文章目录 01 前言02 路径传参方式添加API Key2.1 完整代码2.2 请求示例2.3 swagger文档测试 03 请求头Header方式传入API Key&#xff08;推荐&#xff09;3.1 完整代码3.2 请求示例3.3 swagger文档测试 01 前言 FastAPI&#xff0c;如其名所示&#xff0c;是一个极为高效的框…

云计算的未来:云原生架构和自动化运维的崭露头角

文章目录 云计算的演进云原生架构1. 容器化2. 微服务3. 自动化部署和扩展4. 故障恢复 自动化运维1. 基础设施即代码&#xff08;IaC&#xff09;2. 运维自动化示例&#xff1a;使用Ansible自动化配置管理 3. 自动化监控和报警 未来展望1. 更多的自动化2. 多云混合云3. 边缘计算…

华为+苹果的“科技春晚”背后,“自主创新+实在技术”遥遥领先!

过去的24小时里&#xff0c;科技春晚迎来“双主角”&#xff1a;12日下午&#xff0c;华为发布会&#xff0c;13日凌晨&#xff0c;苹果发布会。 尽管苹果一向以其创新和高端的形象而闻名&#xff0c;但与昔日苹果发布会后有关新品的词条霸屏微博热搜不同&#xff0c;当天在发…

初步了解华为的MTL(市场到线索)流程的基本概念和来龙去脉

前两天&#xff0c;有读者给华研荟发私信&#xff0c;说在学习华为资料的时候看到华为有一个MTL流程&#xff0c;想了解下这个MTL流程和LTC流程有什么区别&#xff1f;既然有了LTC流程&#xff0c;为什么还要MTL流程呢&#xff1f; 为此&#xff0c;今天华研荟给大家简要介绍华…

让电子制造厂提高生产率的方法,学会受用终生!

在现代工业领域&#xff0c;工厂的生产运营离不开复杂的设备和关键的基础设施。然而&#xff0c;工厂在日常运营中常常面临着各种风险&#xff0c;其中之一就是水浸事件。 水浸监控不仅仅是一种反应性的措施&#xff0c;更是一种预防性的安全策略。通过使用高度先进的传感技术和…

前端使用H5中draggable实现拖拽排序效果 两种实现效果

文章目录 一、实现效果①1、实现代码2、效果演示 二、实现效果②1.实现代码2.效果演示 一、实现效果① 将一个节点拖到另一个节点之前或之后 1、实现代码 <!DOCTYPE html> <style>* {padding: 0;margin: 0;}body {display: flex;width: 100%;height: 100vh;just…

Matlab中关于 : 的使用

设&#xff0c;mat 这个矩阵的规格是 n*m&#xff0c;temp mat( i , j ) 矩阵的行和列的下标从1开始 在这个矩阵中&#xff0c;a:b 代表的含义是范围是从 a--b 则&#xff0c;当 a 和 b 被省略时&#xff0c;代表的范围就是最大范围&#xff08;1--n&#xff09; or &#…

卡奥斯第二届1024程序员节重磅预告!

一场属于程序员的狂欢! 第二届卡奥斯1024程序员节重磅来袭。 提前做好活动攻略&#xff0c;欢欢喜喜大奖抱回家&#xff01; 本次活动设置4个活动分会场: 低代码分会场、开源分会场、知识分会场和产品分会场&#xff0c;共12个奖项&#xff0c;1100多个奖品&#xff0c;雷神9…

IP归属地在金融行业的应用场景

IP归属地查询在各大行业当中的利用率可以说非常的高了&#xff0c;提供了各种的保障&#xff0c;比如安全保障、数据保障、性能保障等等。今天我就来详细说一说IP归属地在金融行业的应用场景有哪些&#xff1f; 用途一&#xff1a;通过解析用户IP地址所处的区县位置与表单填写位…

Re-Learn Linux Part1

1. Linux的目录结构 在Linux文件系统中有两个特殊的目录&#xff1a; 一个用户所在的工作目录&#xff0c;也叫当前目录&#xff0c;可以使用一个点 . 来表示&#xff1b;另一个是当前目录的上一级目录&#xff0c;也叫父目录&#xff0c;可以使用两个点 .. 来表示。 . &#…

关于激光探测器光斑质心算法在FPGA硬件的设计

目录 0引言 1CCD采集图像质心算法 2基于FPGA的图像质心算法 3仿真结果与分析 4结论 0引言 在一些姿态检测的实际应用中&#xff0c;需要在被测对象上安装激光探测器[1]&#xff0c;利用CCD相机捕捉激光光斑来检测观测对象的实际情况&#xff0c;光斑图像质心坐标的提取是图…

机器学习——SVM(支持向量机)

0、前言&#xff1a; SVM应用&#xff1a;主要针对小样本数据进行学习、分类和回归&#xff08;预测&#xff09;&#xff0c;能解决神经网络不能解决的过学习问题&#xff0c;有很好的泛化能力。&#xff08;注意&#xff1a;SVM算法的数学原理涉及知识点比较多&#xff0c;所…

grep多行匹配以及一些问题

测试文本, a.txt 123 456789这里是简单的文本 使用grep多行匹配 grep -Pzo "123\s456" a.txt-P: 启用Perl正则表达式模式。 -z: 允许多行匹配&#xff0c;即使匹配跨越了换行符的行。 -o: 只输出匹配的部分。 这里能匹配到 123 456但是有的时候也匹配不到&#…

表演复读生的王炸班型——薪火表演·独角兽班开课介绍

我们拥有同样的目标——大院名校 薪火独角兽班计划 最懂复读生的地方 不想上大课&#xff0c;只想1对1? 录制费用高&#xff0c;不愿增加父母经济压力? 稿件烂大街? 专业没人管? 这些都不是问题! 一站式解决复读生难题 选薪火独角兽班&#xff01; ---------ifire.ar…

利用前端和后端技术,海豚物流实现高效物流管理系统

随着信息技术的快速发展&#xff0c;前端和后端技术在物流行业中扮演着越来越重要的角色。海豚物流充分利用前后端技术&#xff0c;实现了物流管理的无缝协作&#xff0c;大大提升了运输效率和客户满意度。 前端技术在物流管理中扮演着用户界面的角色。通过优化用户界面&#x…

【产品运营】你真的懂B端大客户吗?来试试这8个棘手的需求问题

在与B端客户交流的过程中&#xff0c;有很多需要注意的问题&#xff0c;在产品的不同风格阶段&#xff0c;客户都会提出很多需求&#xff0c;而对于客户的需求产品经理需要有判断以及解决的能力&#xff1b; 本文主要讨论做需求时的棘手问题&#xff0c;在职责上与项目经理有些…

crypto++下载、安装(VS2017)及加解密使用

crpto 下载按个人喜好下载&#xff0c;我使用了图中框选的8.8.0 Release.解压 安装打开修改以适应本机配置整理至标准库 调用加解密使用 Crypto&#xff08;也称为Crypto Library或Crypto STL&#xff09;是一个C密码学库&#xff0c;它提供了各种密码学算法和安全编程工具&…

20230917后台面经总结

1.ping底层原理 Ping 是 ICMP 的一个重要应用&#xff0c;主要用来测试两台主机之间的连通性。Ping 的原理是通过向目的主机发送 ICMP Echo 请求报文&#xff0c;目的主机收到之后会发送 Echo 回答报文。Ping 会根据时间和成功响应的次数估算出数据包往返时间以及丢包率。 基…