Qt获取本机IP、主机名及当前时间

获取本机ip:

 

QString m_ip;

QHostInfo host = QHostInfo::fromName(QHostInfo::localHostName());

foreach (QHostAddress address, host.addresses());

m_ip = address.toString();

获取主机名:

 

#pragma comment(lib,"ws2_32.lib")//相当于把ws2_32.lib这个库加入到了工程文件中,同setting中加入库效果一样


//获取计算机名

WSAData data;
if(WSAStartup(MAKEWORD(1,1),&data)!=0)
{
	cout<<"初始化错误,无法获取主机信息..."<<endl ;
}

wchar_t chBuffer[20];
DWORD dwSize=20;
if(!GetComputerName(chBuffer,&dwSize))
{

	QMessageBox::warning(0,QObject::tr("error"), QObject::tr("get computername error!"),QMessageBox::Ok);
}
strName=QString::fromWCharArray(chBuffer);
	

获取当前时间:

 

#include<QDateTime>

void mainwindow::gettime()
{
	QDateTime dateTime = QDateTime::currentDateTime();
	int y=dateTime.date().year();
	int m=dateTime.date().month();
	int d=dateTime.date().day();
	QString strTime=dateTime.time().toString();
	stime=(strTime+"   "+QString::number(y)+"/"+QString::number(m)+"/"+QString::number(d));
}

滚动条保持在最底端:

 

recEdit->moveCursor(QTextCursor::End,QTextCursor::KeepAnchor);
recEdit->verticalScrollBar()->setValue(recEdit->verticalScrollBar()->maximumHeight());

Qt操作串口

    以前写的串口通讯的工具,最近没事整理了一下记录下来。由于Qt没有实现关于串口操作的类,所以一般情况下可以自己写线程实现,也可以使用第三方类。这里使用第三方类。可以到网上去下载,也有关于这个第三方类的介绍。这里不多说了,在win下,主要就是下载这几个文件:qextserialbase.h,qextserialport.h,win_qextserialport.h,qextserialbase.cpp,qextserialport.cpp,win_qextserialport.cpp。如果是在linux下,则把win_qextserialport.h和win_qextserialport.cpp替换为posix_qextserialport.h和posix_qextserialport.cpp这两个文件即可。

    自动识别COM口:通过读注册表实现(当然linux下不可用)。

class mainwindow : public QMainWindow,public Ui_mainwindowClass
{
	Q_OBJECT

	public:
		mainwindow();
		~mainwindow(){};

	public:
		QString getcomm(int index,QString keyorvalue); //读取键名

	private:
		void init_com();
		Win_QextSerialPort *myCom;//声明对象
                QTimer *timer;
		QStringList m_listCommand;	//待发送的命令
		wchar_t subkey[80];
		wchar_t keyname[256]; //键名数组
		char keyvalue[256];  //键值数组
		int indexnum;
		DWORD keysize,type,valuesize;
		HKEY hKey;
        ......
}

 

void mainwindow::init_com()
{
	QString path="HKEY_LOCAL_MACHINE\\HARDWARE\\DEVICEMAP\\SERIALCOMM";
	QSettings *settings=new QSettings(path,QSettings::NativeFormat);
	QStringList key=settings->allKeys();
	QStringList comlist ;
	QStringList Baudlist ;
	QStringList Paritylist ;
	QStringList DataBitslist;
	QStringList StopBitslist;
	QStringList ControlFlowlist;

	int kk = key.size();
	int i;
	comlist.clear();
	for(i=0;i<kk;i++)
	{
		comlist << getcomm(i,"value");
	}
	comboBox->addItems(comlist);

	//波特率
	Baudlist.clear();
	Baudlist<< "300" << "600" << "2400" << "4800" << "9600"<< "19200" << 
			 "56000" << "57600" << "115200"<<"128000"<<"256000"<< "921600";
	baudRateComboBox->addItems(Baudlist);

	......
}

QString mainwindow::getcomm(int index,QString keyorvalue)
{
	QString commresult="";
	QString strkey="HARDWARE\\DEVICEMAP\\SERIALCOMM";//子键路径
	int a=strkey.toWCharArray(subkey);
	subkey[a]=L'\0';
	if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,subkey,0,KEY_READ|KEY_QUERY_VALUE,&hKey)!=0)
	{
		QString error="Cannot open regedit!";
	}

	QString keymessage="";//键名
	QString message="";
	QString valuemessage="";//键值
	indexnum=index;//要读取键值的索引号

	keysize=sizeof(keyname);
	valuesize=sizeof(keyvalue);

	if(::RegEnumValue(hKey,indexnum,keyname,&keysize,0,&type,(BYTE*)keyvalue,&valuesize)==0)
	{
		//读取键名
		for(int i=0;i<keysize;i++)
		{
			message=QString::fromStdWString(keyname);
			keymessage.append(message);
		}
		//读取键值
		for(int j=0;j<valuesize;j++)
		{
			if(keyvalue[j]!=0x00)
			{
				valuemessage.append(keyvalue[j]);
			}
		}

		if(keyorvalue=="key")
		{
			commresult=keymessage;
		}
		if(keyorvalue=="value")
		{
			commresult=valuemessage;
		}
	}
	else
	{
		commresult="nokey";
	}
	::RegCloseKey(hKey);//关闭注册表
	return commresult;
}

接下来便是打开并设置串口,注意,写串口程序时要先打开串口,然后再对它进行设置,否则设置就不会起作用。打开串口时,端口号在9以下的(包括9)与大于9的打开方式不同。

 

QString m_port = port_name.right(port_name.length()-3);
if(m_port.toInt()>9)
{
	QString xx = "\\\\.\\";
	xx.append(port_name);
	myCom->setPortName(xx);
}
else
{
	myCom->setPortName(port_name);
}

myCom->open(QIODevice::ReadWrite);

另外一个就是发送数据后,最好使用这句

 

connect(myCom,SIGNAL(readyRead()),this,SLOT(readMyCom()));//信号和槽关联,等串口缓冲区有数据时再进行读串口操作

等待串口有数据时再进行读。

 

QString str=sendEdit->toPlainText();//将sendEdit内容提取到str中
str.append("\r\n");
QByteArray aa=str.toAscii();
const char * strdata=aa.data();
int rec=myCom->writeData(strdata,qstrlen(strdata));
myCom->flush();

 

void mainwindow::readMyCom()
{	
	char buf[1024];
	memset(buf, 0, sizeof(buf));
	qint64 temp=myCom->readData(buf,sizeof(buf));
	buf[temp+1]=0;
}

面向对象的理解

    过程化编程首先要确定计算机应采取的操作,然后使用编程语言来实现这些操作。c语言理念是将大型程序分解成小型、便于管理的任务。过程性编程强调算法,OOP强调数据。面向对象最重要的是类。在c++中,类是一种规范,它描述了这种新型数据格式,对象是根据这种规范构造的特定数据结构。例如类可以描述公司员工的基本特征(姓名、职位、工资等),而对象则代表特定的员工(小王、工程师、5000¥)。类规定了可以使用哪些数据来表示对象以及可以对这些数据执行哪些操作。 OOP程序设计方法首先设计类,类表示了程序要处理的东西。类定义描述了对每个类可执行的操作。OOP编程不是将重点放在任务上,而是放在表示概念上。 OOP编程不仅是数据和方法合并为类定义,还有助于创建可重用的代码。

    面向对象包括3个特征:继承、封装、多态。

    面向对象的主要目的之一就是提供可重用的代码。类继承,它能够从已有的类(基类)派生出新类,而派生类继承了基类的特征,包括方法。可以通过继承完成的工作:1、可以在已有类的基础上添加功能;2、可以给类添加数据;3、可以修改类方法的行为。

    封装是指类把所有的操作都封闭起来,仅仅提供接口供他人使用。使用的人没必要弄清楚类里面的操作,只需懂得操作接口就可以了。 信息隐藏可以保护数据,使其免受不当的访问。

    多态可以为操作符和函数创建多个定义,通过上下文确定使用哪个定义。旨在能够用同名的函数来完成相同的基本操作。多态与重载指的是同一回事,通常使用重载。

    面向对象设计的原则:

    1、“开闭”原则:

      一个软件实体应该对扩展开放,对修改关闭。即设计一个模块的时候,应当使这个模块可以在不被修改的前提下被扩展。在面向对象中,不允许更改的是系统的抽象层,而允许扩展的是系统的实现层。实现开闭原则的关键步骤是抽象化,基类和子类之间的继承关系就是抽象化的体现。

    2、里氏代换原则:

      如果对每一个类型为T1的对象O1,都有类型为T2的对象O2,使得以T1定义的所有程序P在所有的对象O1都替换为O2时,程序P的行为没有变化,那么类型T2是类型T1的子类型。也就是说,在软件里面,把基类都替换成它的子类,程序的行为没有变化。反过来不成立,如果一个软件实体使用的是一个子类的话,那么它不一定适用于基类。里氏代换原则是对实现抽象化的具体步骤的规范。

    3、依赖倒转原则:

      依赖倒转原则就是依赖于抽象,不要依赖于实现。要针对接口编程,不要针对实现编程。传统的过程性编程的设计方法倾向于使高层次的模块依赖于低层次的模块,抽象层次依赖于具体层次。倒转原则就是把这个错误的依赖关系倒转过来。

    4、合成/聚合复用原则:

      在一个新的对象里面使用一些已有的对象,使之成为新对象的一部分;新的对象通过向这些对象的委派达到复用这些对象的目的。聚合表示整体和部分的关系,表示“拥有”,合成是一种更强的拥有,部分和整体的生命周期一样。

    5、迪米特法则:

      一个软件实体应当尽可能少的与其他实体发生相互作用,这样,当一个模块修改时,就会尽量少的影响其他模块。

    6、接口隔离原则:

      使用多个专门的接口比使用单一的总接口好,也就是说,一个类对另外一个类的依赖性应当使建立在最小的接口上。

    对面向对象设计的原则的理解还不是很深刻,以后在实践中慢慢理解^_^

    

    

.pro文件的写法(转)

我们在编译QT的工程的时候,一般都会让qmake自动生成,但有时我们需要定制我们的工程,那么就必须改写pro文件。
要自己全部写pro文件又有点麻烦,所以,一般都是先运行  qmake -project来生成基本的pro文件。
      例如你有一个工程目录为backup,那么在这个目录下就会生成backup.pro文件。
对一般的工程,我们只需要修改几个基本的常用的选项,下面说说怎么修改。
      假设我们有个目录,名字为backup。下面有a.ha.cppb.hb.cppmain.cpp等文件。
首先我们可以在backup目录下运行qmake -project生成backup.pro文件。
1、第一种常用方式:
#模块设置,一般设置为app(生成应用程序,默认),subdirs(subdirs模板可以编译子目录里的目标文件),lib(生成库文件)
TEMPLATE= app
#指定生成的应用程序放置的目录
DESTDIR+= ../bin
#指定生成的应用程序名
TARGET= pksystem
#添加或减少CONFIG的配置模块,一般采用默认即可,但是除去debug_and_release模块不会生成debug和release文件夹
#CONFIG+= release
CONFIG-= debug_and_release
#指定uic命令将.ui文件转化成ui_*.h文件的存放的目录
UI_DIR+= forms
#指定rcc命令将.qrc文件转换成qrc_*.h文件的存放目录
RCC_DIR+= ../tmp
#指定moc命令将含Q_OBJECT的头文件转换成标准.h文件的存放目录
MOC_DIR+= ../tmp
#指定目标文件的存放目录
OBJECTS_DIR+= ../tmp
#程序编译时依赖的相关路径
DEPENDPATH+= . forms include qrc sources
#头文件包含路径
INCLUDEPATH+= .
#qmake时产生的信息,

$${a}读取变量a的字符串,

$$(PATH)读取环境变量PATH
#message($$(PATH))
#源文件编码方式
CODECFORSRC= GBK
# Input
#工程中包含的头文件
HEADERS+= include/painter.h
#工程中包含的.ui设计文件
FORMS+= forms/painter.ui
#工程中包含的源文件
SOURCES+= sources/main.cpp sources/painter.cpp
#工程中包含的资源文件
RESOURCES+= qrc/painter.qrc

2第二种常用方式,用于子文件夹的编译:
#设定模块为子文件夹编译方式
TEMPLATE= subdirs
#子文件夹目录,可用\换行
SUBDIRS= src1 \
         src2
在backup.pro里已经包含了几个基本的选项,如
    TEMPLATE,TARGET,INCLUDEPATH,HEADS,SOURCES等选项。
下面说明一下几个经常修改的选项。
1)、HEADS
我们工程中头文件如下:
HEADS += a.h \
                    b.h

2)、SOURCES:
我们工程中的cpp文件,如下:
SOURCES += a.cpp \

                          b.cpp \

                          main.cpp

    上面的两个选项的文件分行是用反斜线\来分行,最后一个不用,如果是同一行的文件可以空格分开,我们在执行qmake -project的时候,qmake已经自动帮我们写上了,省去我们这些麻烦,不过以后要增加文件可以在这里增加。 3)、INCLUDEPATH
    这个选项可以指定我们#include语句要包含头文件的目录,如果你有其它的不在当前目录的头文件需要包含进来,并又不想在自己的源文件中使用绝对路径或相对路径来包含头文件,那么我就可以在这里把这个头文件所在的路径包含进来,例如在backup目录的兄弟目录里有个目录为image的目录,里面有个头文件为image.h,我们的b.h里要用到,因此我们在backup.pro文件中设置INCLUDEPATH
4)、 INCLUDEPATH += ../image
这样,我们在b.h里只需要#include "image.h"就可以了。
5)、 CONFIG
CONFIG经常用到的一个是就是设置release版本或是debug或是release和debug的版本信息。如果我们要调试可以这样设置。
    CONFIG += debug
    或CONFIG+= release (release版本)
    下面是CONFIG的几个版本的选项:
release The project is to be built in release mode. This is ignoredif debug   is also specified. 
debug The project is to be built in debug mode. 
debug_and_release The project is built in both   debug andrelease modes. This can have some unexpected side effects (see below for moreinformation). 
build_all If debug_and_release   is specified, the projectis built in both debug and release modes by default. 
ordered When using the subdirs   template, this optionspecifies that the directories listed should be processed in the order in whichthey are given. 
precompile_header Enables support for the use of precompiledheaders   in projects. 
warn_on The compiler should output as many warnings as possible.This is ignored if warn_off   is specified. 
warn_off The compiler should output as few warnings as possible.

6)、LIBS:
这里可以选择我们要包含的库,例如我们的工程要用到libz.so的一个压缩库,我可以怎么写:
    LIBS += -lz
或是用到我们image目录下的libimage.so库,那么可以这么写:
    LIBS += -L../image/image
7)、 DEFINES:
DEFINES又是我们一个常用的定要,它相当于我们用gcc的-D定义。例如,我们的backup工程需要对大文件进行读写就可以这样定义:
DEFINES += _LARGEFILE64_SOURCE   _FILE_OFFSET_BITS=64
8)、 RESOURCES
定义我们的资源描述文件,我们工程里需要很多图片,那么这些图片的定义都可以放在backup.qrc文件中进行描述,那么这里就可以指出我们的qrc文件。
RESOURCES += backup.qrc
9)、TARGET
这个选项可以让我们定义我们生成的目标文件的名字,例如我们执行我们这个backup工程是默认生成backup的执行文件,但我们想让我们的执行的文件名为abcbackup,我们就可以这样写
TARGET = abcbackup
10)、 OBJECTS_DIR
          一般我们在编译我们的工程的时候会生成许多的中间文件,如.o文件(linux下)或.obj(windows下),这样我们的工程就很乱,所以我们可以定义这个选择,我们可以这样定义:
OBJECTS_DIR += ./objs
这样,我们的这些中间文件就全都在backup/objs目录下了。
      一般,我们不会在我们的工程里直接编译,这样的话,工程比较乱,我们可以在backup目录下建立一个目录,为bakcup-build目录,我们在这个目录下编译,这样其他的临时文件就在这个目录下,这样我们的工程看起来就不会那么乱了。
      我们进入bakcup-build目录,然后运行
            qmake -o Makefile ../bakcup.pro
      这样我们就在当前目录下生成了一个Makefile。在这个目录下执行make就可以生成我们的abcbackup可执行程序了

函数参数传递规则

1、函数参数传递规则

    函数接口的两个要素是参数和返回值,c中传递方式:值传递和地址传递(即指针传递);c++中:值传递,地址传递和引用传递。

    规则一:不论是函数的原型还是定义,都要明确写出每个参数的类型和名字,如果函数没有参数,那么使用void而不要空着。因为标准c把空的参数列表解释为可以接受任何类型和个数的参数,而标准c++则把空的参数列表解释为不可以接受任何参数。在移植c/c++程序时尤其要注意这方面的不同。

    规则二:参数命名要恰当。输入参数与输出参数的顺序要合理,参数的顺序遵循程序员的习惯。一般,输出放在前面,输入参数放在后面,并且不要交叉出现输入输出参数。

    规则三:如果参数是指针,且仅做输入用,则应在类型前加const,以防止该指针指向的内存单元在函数体内无意中被修改。

2、返回值规则

    规则一:不要省略返回值类型,如果没有返回值,则应声明为void类型。

    规则二:函数名字与返回值类型在语义上不可冲突。例外:getchar();返回类型是int,而不是char。

3、函数内部实现规则

    1)、在函数体的“入口处”,对参数的有效性进行检查。断言assert。

    2)、在函数体的“出口处”,对return语句的正确性和效率进行检查。如果函数有返回值,那么函数的“出口处”是return语句。

    注意:1、return语句不可返回指向堆栈内存的指针或引用,因为该内存单元在函数体结束时被自动释放。

          2、要搞清楚返回的究竟是对象的值、对象的指针还是对象的引用。

          3、如果函数返回值是一个对象,要考虑return语句的效率。return string(s1+s2);与string result(s1+s2);return result;不等价。前者提高了效率。

4、函数堆栈用途

    1)、在进入函数前保存环境变量和返回地址;

    2)、在进入函数时保存参数的拷贝;

    3)、在函数体内保存局部变量。