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;
}

.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可执行程序了

关于Qt显示中文乱码问题

 一直都在代码中使用GBK编码来解决Qt显示中文的问题,即在main()函数中添加下面几句:

QTextCodec::setCodecForLocale(QTextCodec::codecForName("GBK"));
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("GBK"));
QTextCodec::setCodecForTr(QTextCodec::codecForName("GBK"));

然后在发布的应用程序文件夹下建立plugins\codecs,然后将qcncodecs4.dll放到该目录下,也没再出现乱码。但是后来客户反馈说存在乱码。为什么会出现乱码呢?    

    原来如此。比如写了“汉字”两个字,然后以GBK形式保存在计算机的存储设备中(“汉字”的GBK编码是BA、BA、D7、D6)。然后在读取时,计算机中的二进制码“BA、BA、D7、D6”却不是以同样的GBK形式被解释成“汉字”两个字符。比如说以ISO-88591形式被读取,那么“BA、BA、D7、D6”就会被解释为四个西欧文字了。如果将程序发布到一些非简体中文的国家或地区,可能出现对方的机器上根本没有安装任何中文的编码格式,所以就会出现乱码。

    那么,如何彻底解决乱码问题呢?Qt提供了强大的多国语言工具Qt Linguist。

   一、编写源码:

    实现多语言,1)、首先必须保证每一个用户可见的字符串都使用了tr()函数;2)、在应用程序启动时使用QTranslator载入一个翻译文件(.qm)。如:

#include <QtGui/QApplication>
#include <QTranslator>
#include <QMessageBox>
 
int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
 
    //载入翻译文件
    QTranslator translator;
    bool bLoaded = translator.load("readnv_chs");//语言包文件,由linguist工具生成
 
    if (!bLoaded)
    {
    QMessageBox::warning(NULL,QApplication::tr("Load File Failed"), QApplication::tr("Load readnv_chs.qm Failed!"));
    }
 
    app.installTranslator(&translator);
 
    mainwindow w;
    w.show();
 
    return app.exec();
}

注意:翻译文件加载的位置必须在界面实例化之前完成。编写好代码后:

   二、生成翻译文件:

    1)、在.pro文件中添加TRANSLATIONS+=readnv_chs.ts。指明在项目中生成翻译源文件readnv_chs.ts。<.ts是可读的翻译文件,使用简单的XML格式;而.qm是经过.ts转换而成的二进制机器语言>。

     2)、执行命令:lupdate -verbose xx.pro。从应用程序的源代码中提取所有用户可见的字符串,生成相应的.ts文件(readnv_chs.ts)。

         

 3)、使用Qt Linguist翻译该应用程序。使用linguist打开readnv_chs.ts文件,对tr()函数的字符串参数进行翻译,然后点击release,生成相应的.qm文件,即readnv_chs.qm。然后将.qm文件放在应用程序目录下即可。

0x7c92e4ff 处最可能的异常: 0xC0000008: An invalid handle was specified

 遇到一个纠结的问题,先贴代码。

void mainwindow::browseNvFile()
{
    QString fileName;
    fileName =QFileDialog::getSaveFileName(NULL,tr("Save File"), "E:/", tr("Exp Files (*.bin)"));
     
    fileName.trimmed();
    if (!fileName.isEmpty())
    {
    ui.ReadBtn->setEnabled(true);
    strBinFile = fileName;
    ui.NvLineEdit->setText(strBinFile);
    }
}

每次运行到fileName =QFileDialog::getSaveFileName(NULL,tr("Save File"), "E:/", tr("Exp Files (*.bin)"));时就出现:0x7c92e4ff处最可能的异常:0xC0000008:An invalid handle。之后无论是点击“继续”或者“忽略”都能运行,直接找到工程目录下的exe文件也能正常运行,也就是说只在调试的时候才会出现这个错误。代码看来看去都没觉得有问题,然后找了两个人帮忙,都没找到原因,而且奇怪的是之前没问题的代码现在调试都有这个问题了。晕啊!!后来在别的机器上运行发现没有这个问题,于是“找到”了原因:我的Qt库有问题。于是换个Qt的库试试。

   换了Qt的库之后又出现了一个问题:单独执行qmake时没有问题,但是编译程序执行qmake时就出现:系统无法找到指定的程序,可能调用的某个命令出问题了。继续换Qt的库。。。   

   换好之后,第二个问题解决了,第一个仍然存在,重装IDE。。。装完了,问题依旧存在。跟系统有关??换到我的笔记本上现在也存在这个问题了,而之前的都是没问题,很奇怪,问题依旧没有得到解决。先记录下来,找到了原因再更新。或者哪位可以帮忙解决。。。

   有时候还真的老遇到一些奇怪的问题,qt用着用着就来句“qmake不是内部或外部命令”,环境变量并没有改变。但是重新设置一下环境变量就又好了。

    续:

   今天问题终于解决了,好吧,就满足下某人,“感谢高手--李亚科的帮助”,^_^。

   后来用其他程序测试了下,排除了Qt的问题,也曾怀疑过360私自改了系统文件,不过这个后来也被排除了。调试代码,发现调用了Overlaycon.dll,而正是在该处抛出异常。话说,Overlaycon.dll是个神马东东呢?原来是装了wuala之后出现的,仔细想想,这个问题也确实是在装wuala之后才有的。于是卸载了wuala,意料之中,问题得到了解决。其实也用不着卸载wuala,只要卸载掉Wuala OverlayIcons就可以了。应该是wuala为了把自己的软件整合到 explorer中,而 GetSaveFileName 需要调用explorer,所以加载了 overlayicon.dll。 而这个dll竟然存在bug,所以就出现问题了。呃,回家整笔记本去。。。