•(3) 设置"工程选项",在此处输入QT4的qmake和QT设计器的绝对路 径,单击"下一步"按钮,如图4.2.2。
 图4.2.2
•(4) 在".h文件的模板"选项中,可以设置头文件.h的格式。
•(5) 最后单击"完成"按钮,KDevelop会自动生成一个标准C++主程 序。
•(6) 然后根据自己需要在右边的qmake管理器里添加头文件和源文件。
到此,KDevelop中已建立了一个KDevelop工程。也就完成了QT的基本开发环境构建。
6.3 编译工程
(1)qmake -project
(2)qmake
(3)make
(4)./phonebook(运行)
由于bdb与TTS的头文件与库需要加进来,故需要修改Makefile文件:
添加 -ggdb -I/usr/local/BerkeleyDB.4.6/include/到include头文件处(INCPATH后面)(注意格式)
添加 -L/usr/local/BerkeleyDB.4.6/lib/ -ldb -lpthread到LIBS后面。
添加 -lstdc++ -L .到LIBS后面
注意:
这里编译的都是用于pc机上测试的程序,故对于适用于arm上运行的程序移植方法见前面所述。
6.4软件设计简要分析
为了减轻开发负担,本软件采用qt designer设计界面,然后用KDevelop加入设计好的.ui文件,在KDevelop里实现工程设计。
6.4.1界面设计
由于QT designer提供很好的操作环境,这里就不详细介绍界面制作,只对个别问题作简单说明。
(1)使用容器将主窗口与各个分窗口都装入不同的容器,用关闭与打开窗口的方式实现窗口间切换,将主窗口放入frame_1容器,将添加联系人页面 放入addFrame 容器,将修改页面放入Mframe容器。这样就可以通过容器激活方法setVisible激活某一窗口,实现窗口切换。
例如:关闭修改与添加容器,以显示主窗口,即可按如下方式设置:
Mframe->setVisible(false);
frame_1->setVisible(true);
menubar->setEnabled(true);
(2).工具栏需要加入toolTip,当鼠标滑向某一个控件时,则提示操作。
(3)对于控件大小与窗口比例控制,则可以加入一些弹弹簧spacer
(4)对于文本输入控件TextEdit,需要加入Scroll Bar以实现滚动条(直接拖动到TextEdit控件中即可)。
(5)对于icon图标文件,需要加入到资源,否则,程序位置改变后,则图标无法显示。
6.4.2类结构设计
主要是由两个类组成,CphoneBookwindow类是主要的操作与窗口类,而WorkThread类主要是用于语音朗读。
● 主窗口类:
(1)Base Class(基本窗口类是在qt DESIGNER里定义的)
Ui_phoneBookWindow --CPhonebookwindow
(2) Data Members

(3) declaration

(4) declaration File

● WorkThread多线程类
(1) Base class

(2)Data members

(3) declaration

(4) declaration File

6.4.3类定义与个别函数介绍
●主窗口类
class WorkThread;//申明多线程类
//主窗口类定义
//================================================
class CPhonebookwindow : public QMainWindow,
public Ui_phoneBookWindow
{
Q_OBJECT
public:
CPhonebookwindow(QWidget* = 0);
private slots:
//
void showAll();//显示所有记录的实现函数
void showhelp();//帮助
void showAllFind();//显示所有记录的分类判断函数
void showAbout();//关于
void doAdd();//添加
void doFind();//查找
void addClose();//添加记录窗口关闭
void doAddPushBtn();//添加
void doMend();//显示修改前的内容
void inputMeClose();//添加窗口容器的设置
void doDelete();//删除
void mend();//修改
void aa();//鼠标点击QTableWidget信号
void vote();//鼠标取值分类处理标志设置
void classcontacts();//分类显示
void showContacts();//分类显示处理
public:
//berkeley db Parameters
//===============================
DB *dbp;//数据库句柄
DBT key, data;//定义key/data健值对
int ret;//操作结果判断
DBC * cur;//游标
u_int32_t flags;//数据库打开方式
//标志位
//===============================
int mlen;//name长度
char m[20];
int morw,mcolumn;//行列数
bool flagaa;//鼠标是否选择记录标志
int h;//setRowCount的补丁参数
int p;//语音开头控制标志
private:
WorkThread* threadVector;//定义线程类为主窗口类的一个私有成员
};
在这里我们定义线程类为主窗口类的一个私有成员,这样一来,主窗口类里的其它成员就可以很容易的访问多线程类中的成员。
● 多线程类
//多线程类定义
class WorkThread : public QThread
{
protected:
void run();//线程执行函数
public:
void strncpy0(char *dest, const char *source, int size);//自定义拷贝函数
void espeakmain(char *playtext);//朗读函数
public:
struct customer phonebook;//实例化结构体数据结构
int flagspeak;//读取内容选择标志位
};
● 数据结构
//数据处理结构定义
//=========================
typedef struct customer
{
char name[20];//姓名
char phone[20];//电话
char address[30];//地址
char email[20];//邮件
char beizhu[40];//备注
char leibie[10];//类别
};
6.4.4多线程编程方 式
可以直接使用C/C++多线程编程,由于QT作了二次封装,使用起来更加方便,这里就直接使用Qthread类。实现方式非常简单,代码如上所写, 只需要写一个相应的执行函数,当需要执行这一任务时,就调用Qthread的基类start()函数来启动线程执行函数run(),从而使得线程真正运 行。
//线程执行函数,负责语音内容朗读选择
//=================================
void WorkThread::run()
{
char temp[30] = "";
switch(flagspeak)
{ //信息分类朗读
//===============
case 0:
strcpy(temp,"欢迎使用电话管理系统");
espeakmain(temp);
break;
case 1:
strcpy(temp,"请选择要删除,的,记录");
espeakmain(temp);
break;
case 2:
strcpy(temp,"请选择要修改,的,记录");
espeakmain(temp);
break;
case 3:
strcpy(temp,"请输入要查找的姓名");
espeakmain(temp);
break;
case 4:
strcpy(temp,"没有找到您要的记录");
espeakmain(temp);
break;
case 50:
strcpy(temp,"请输入姓名");
espeakmain(temp);
break;
case 51:
strcpy(temp,"请输入电话号码");
espeakmain(temp);
break;
case 52:
strcpy(temp,"请输入地址");
espeakmain(temp);
break;
case 53:
strcpy(temp,"请输入邮件");
espeakmain(temp);
break;
case 54:
strcpy(temp,"请输入备注");
espeakmain(temp);
break;
case 55:
strcpy(temp,"您要输入的名字已存在");
espeakmain(temp);
break;
case 6:
strcpy(temp,"删除成功");
espeakmain(temp);
break;
case 61:
strcpy(temp,"修改成功");
espeakmain(temp);
break;
case 62:
strcpy(temp,"添加成功");
espeakmain(temp);
break;
case 8:
strcpy(temp,"输入太长,请缩减");
espeakmain(temp);
break;
case 7:
char phone[] = "的电话是";
sprintf(temp,"%s,%s,%s",phonebook.name,phone,phonebook.phone);
espeakmain(temp);
break;
}
}
6.5关联窗口信号与相应槽
在程序一启动,初始化时就需要关联相应的信号/槽。
信号和槽机制是QT的核心机制。信号和槽是一种高级接口,应用于对象之间的通信,它是QT的核心特性,也 是QT区别于其它工具包的重要地方。信号和槽是QT自行定义的一种通信机制,它独立于标准的C/C++语言,因此要正确的处理信号和槽,必须借助一个称为 moc(Meta Object Compiler)的QT工具,该工具是一个C++预处理程序,它为高层次的事件处理自动生成所需要的附加代码。
在 我们所熟知的很多GUI工具包中,窗口小部件(widget)都有一个回调函数用于响应它们能触发的每个动作,这个回调函数通常是一个指向某个函数的指 针。但是,在QT中信号和槽取代了这些凌乱的函数指针,使得我们编写这些通信程序更为简洁明了。 信号和槽能携带任意数量和任意类型的参数,他们是类型完全安全的,不会像回调函数那样产生core dumps。
所有从 QObject或其子类(例如Qwidget)派生的类都能够包含信号和槽。当对象改变其状态时,信号就由该对象发射(emit)出去,这就是对象所要做 的全部事情,它不知道另一端是谁在接收这个信号。这就是真正的信息封装,它确保对象被当作一个真正的软件组件来使用。槽用于接收信号,但它们是普通的对象 成员函数。一个槽并不知道是否有任何信号与自己相连接。而且,对象并不了解具体的通信机制。
你可以将很多信号与单个的槽进行连接,也可以将单个的信号与很多的槽进行连接,甚至于将一个信号与另外一个信号相连接也是可能的,这时无论第一个信 号什么时候发射系统都将立刻发射第二个信号。总之,信号与槽构造了一个强大的部件编程机制。//关联窗口信号与相应槽 //============================================================ connect(actAdd,SIGNAL(triggered()),this,SLOT(doAdd())); //操作菜单里的增加->增加槽函数 connect(checkpshBtn,SIGNAL(clicked()),this,SLOT(doFind())); //工具栏上的查找按钮->查找槽函数 connect(actMaend,SIGNAL(triggered()),this,SLOT(doMend())); //操作菜单中的修改->修改槽函数 connect(actDelete_2,SIGNAL(triggered()),this,SLOT(doDelete())); //操作菜单中的删除->删除槽函数 connect(actExit,SIGNAL(triggered()),this,SLOT(close())); //操作菜单中的退回->关闭程序槽函数 connect(cecalPushBtn_2,SIGNAL(clicked()),this,SLOT(addClose())); //添加联系人窗口的取消按钮->关闭添加联系人窗口槽函数 connect(addPushBtn,SIGNAL(clicked()),this,SLOT(doAddPushBtn())); //工具栏中的增加->增加联系人窗口槽函数 connect(MCaelButton_2,SIGNAL(clicked()),this,SLOT(inputMeClose())); //修改前信息插入到修改信息编辑框槽函数 connect(tableWidget,SIGNAL(itemSelectionChanged()),this,SLOT(aa())); //鼠标点击某一个表格,则设置相应标志位,用以判断是否选择了要操作的内容,并显示相应详细信息的槽函数 connect(MpushButton,SIGNAL(clicked()),this,SLOT(mend())); //工具栏上的修改按钮->修改槽函数 connect(pushButton,SIGNAL(clicked()),this,SLOT(showAllFind())); //工具栏上的查询所有信息按钮->查询所有信息槽函数 connect(pushButton_2,SIGNAL(clicked()),this,SLOT(doAdd())); //工具栏上的添加信息按钮->添加联系人槽函数 connect(pushButton_3,SIGNAL(clicked()),this,SLOT(doMend())); //工具栏上的修改信息按钮->修改联系人槽函数 connect(pushButton_4,SIGNAL(clicked()),this,SLOT(doDelete())); //工具栏上的删除信息按钮->删除联系人槽函数 connect(actAbout,SIGNAL(triggered()),this,SLOT(showAbout())); //帮助菜单中的关于->关于槽函数 connect(actUse,SIGNAL(triggered()),this,SLOT(showhelp())); //帮助菜单中的帮助->帮助槽函数 connect(actspeak,SIGNAL(triggered()),this,SLOT(vote())); //操作菜单中的语音开关->语音开关槽函数 connect(leibieboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(classcontacts())); //工具栏上的显示不同类别的所有信息
6.6语音朗读线程启动方式 if(p==1)//如果开关状态为开,则语音提示 { threadVector->flagspeak = x;//这里的x就是对应不同的语音选项 threadVector->start(); }
6.6数据插入表格方法 真正插入就是用setItem方法实现 QTableWidgetItem *name_2=new QTableWidgetItem(QString::fromUtf8(threadVector->phonebook.name)); QTableWidgetItem *phone_2=new QTableWidgetItem(QString::fromUtf8(threadVector->phonebook.phone)); QTableWidgetItem *address_2=new QTableWidgetItem(QString::fromUtf8(threadVector->phonebook.address)); QTableWidgetItem *email_2=new QTableWidgetItem(QString::fromUtf8(threadVector->phonebook.email)); QTableWidgetItem *beizhu_2=new QTableWidgetItem(QString::fromUtf8(threadVector->phonebook.beizhu)); QTableWidgetItem *leibie_2=new QTableWidgetItem(QString::fromUtf8(threadVector->phonebook.leibie)); tableWidget->insertRow(row);//row为插入的行号 tableWidget->setItem(row,name_2); tableWidget->setItem(row,1,phone_2); tableWidget->setItem(row,2,address_2); tableWidget->setItem(row,3,email_2); tableWidget->setItem(row,4,beizhu_2); tableWidget->setItem(row,5,leibie_2);
6.7清除表格数据分类处理 (很重要,否则remove最后一行数据时往往出现异常)
if(ret==0)//如果从BDB中删除成功再在table中作remove操作 { if(p==1)//如果语音开关状态为开 { threadVector->flagspeak = 6;//读取内容分类 threadVector->start();//启动线程 } if(allRowCount>1)//如果表格中有2行以上的数据则用removeRow()直接删除某一行即可 { //qDebug()<<"row1"<<row; //qDebug()<<"row2"<<row; tableWidget->removeRow(row); } else { h=1;//setRowCount的补丁参数,防止鼠标取值事件导致删除异常 tableWidget->clear(); tableWidget->setRowCount(0); h=0; //tableWidget->horizontalHeaderItem(0)->setText(QString::fromUtf8(" 姓名")); }
}
6.8编码处理 本程序全部采用utf-8编码,所有文字处理都需要作必要转换纺一 如: strcpy(threadVector->phonebook.name,mendNameLineEdit->text().trimmed().toUtf8()); 就可以将姓名输入框中内容取出并转换成utf-8格式 对于程序显示,还必须加入字体,否则中文无法正常显示。
第7章 系统测试方案
7.1 基于PC机的设计方案测试
测试基于PC机版本的软件功能是否完善,主要包括对数据的操作,中文显示,语音朗读等等。
7.2 基于ARM宿机的设计方案测试
测试基于ARM版本的软件功能,对比PC主机的实现来测试ARM上软件运行状况。特别注意所需依赖库的交叉编译,与ARM平台系统结构的差异及音频驱动与 音频引擎差异。第8章 测试设备
对于PC主机软件的测试方法与一般软件一样,只是对arm 上的软件测试,需要特别为arm开发板准备输入设备,主要包括键盘和鼠标。还有一个局域网络。第9章 测试数据
所有的测试数据见使用指南一章。
 第10章 结果分析
10.1 基于PC机的软件结果分析
◆ 对联系人信息常用操作功能实现很完善。
◆ 由于QT对行的删除操作的类成员有一定的缺陷,会导致删除最后一行的bug,本软件在此基础上,作出了修正。
◆ 语音朗读效果很好。
◆ 显示界面友好简洁,速度很快,操作简单。
10.2 基于ARM的软件结果分析
◆由于arm上面文件系统版本很旧,一些shell的处理很差,会导致一些异常。导致了语音对中文的朗读出现了异常。
◆由于arm上面的qt视窗界面很旧,无法满足我们软件运行的友好环境要求,所以运行效果受到影响,特别是对输入法的处理。
◆其它都很工作良好。第11章 实现功能
本软件主要用于对联系人的信息管理,由些可以很容易地扩展为一个多功能信息管理软件,而且是可跨平台的,适用于几乎所有的平台。具体的功能见第3章 所述。
第12章 特色
★ 采用了语音合成技术,能智能的语音播报。
★ 采用QT开发,可用于多操作系统(特别是嵌入式操作系统)。
★ 采用嵌入式数据库berkeley db实现了数据库的文件化。第13章使用指南
主窗口如图3.0

图3.0
(1)添加联系人:
a.点击"操作"->"增加",即出现添加信息页面。
b.直接点击工具栏中的添加图标,即出现添加信息页面。
如图3.1:
 图3.1.添加联系人窗口
(2)修改联系人:
a.用鼠标选中表格中的某一行,然后点击工具栏里的修改图标,即可出现信息修改页面。
b.用鼠标选中表格中的某一行,然后点击"操作"->"增加",即可出现信息修改页面。
如图3.2
 图3.2修改联系人窗口
(3)删除联系人:
a.用鼠标选中表格中的某一行,然后点击工具栏里的删除图标,即可出现信息修改页面。
b.用鼠标选中表格中的某一行,然后点击"操作"->"删除",即可出现信息修改页面。
(4)查询特定记录:
在工具栏的查找输入框中输入您需要查找人的姓名,点击它右边的查找按钮即可完成信息查找。
(5)查询所有记录:
直接点击工具栏里的查找所有按钮即可。
(6)查看,复制详细信息:
a.通过左右拉条可以看到所有信息,双击某一表格,右键上下文或者CTRL+C复制信息。
b.点击某一个表格,将会在窗口下文显示该联系人的所有详细信息。
(7)语音控制:
点击"操作"->"语音(开/关)"即可实现语音的开关。
(8)显示某类联系人:
点击工具栏上的下拉列表即可选择要显示的联系人。
(9)注意事项:
将鼠标滑向工具栏上的控件时,即会出现操作提示。
参考文献- [1] 许信顺 贾智平编著, 嵌入式Linux应用编程,机械工业出版社, 2007 年1月
- [2] 蔡志明等编著,精通Qt4编程,电子工业出版社,2008年1月
- [3] 倪继利,Qt及linux 操作系统窗口设计,电子工业出版社,2006年4月
- [4] 杜华,Linux编程技术详解,人民邮电出版社,2007年11月
- [5] 施聪,嵌入式数据库系统Berkeley DB http://www.ibm.com/developerworks/cn/linux/l-embdb/index.html
- [6] eSpeak text to speech ,http://espeak.sourceforge.net/
- [7] 韦东山,嵌入式Linux应用开发完全手册,人民邮电出版社,2008年8月
- [8] Karim Yaghmour , Building Embedded Linux Systems , 中国电力出版社, 2004 年12月
- [9] 孙琼 , 嵌入式Linux应用程序开发详解, 人民邮电出版社, 2006 年7月
- [10] 李亚锋;欧文盛,ARM嵌入式Linux系统开发从入门到精通, 清华大学出版社, 2007 年8月
- [11] STANLEY B.LIPPMAN,JOSEE LAJOIE, C++ PRIMER (3RD)中文版, 中国电力出版社,2005年2月
- [12]谭浩强,C程序设计(第二版),清华大学出版社,1999年12月
文章出处:http://www.rosoo.net/a/embedded_o/201003/8748.html(责任编辑:jacky) |