如何在QT下执行shell或外部程序

如何在QT下执行shell或外部程序,第1张

1、设计gui图形界面,创建一button,并在clicked下添加代码

第一种方法(50行)是调用linux C函数库中的system(const char *string)

第二种方法(51行)和第三种方法(53 54行)是调QT里的函数

需要说明的时,上面三种方法都是可以的,但前两种方法会阻塞进程,直到smplayer程序结束,而第三种方法则不会阻塞进程,可以多任务运行。

还有,我们知道神销qt在运行的时候,要启动qws(qtwindows server),如果用前面两种方法,则smplayer运行的时候,要新开启一个qws,否则不能运行;而用第三种方法,则不需要再开启qws,它和HelloQt4共用一个qws,这样,在一个窗口里可以看到这两个程序。

2、新建运行脚本,用来启动smplayer播放器

在上一步中,qt程序执行了

/opt/run_smplayer脚本,但这个脚弊瞎州本是不存在的,我们要新建它,打开开发板的/opt目录,新建一个run_smplayer文件,添加如下内容

#!/bin/sh

#测试用

#cd /opt/

#rm qt_create/

-rf

#sleep 3

#mkdir qt_create

#cd qt_create

#mkdir qt_create1

#cd qt_create1

#mkdir qt_create2

#cd qt_create2

#mkdir ok

#直接调用mplayer播放sdcard里的gq.avi文件

#cd /usr/local/smplayer/bin

#./mplayer /sdcard/gq.avi

#启动友善的smplayer

cd /usr/local/smplayer/bin

./smplayer

3、修改smplayer文件

在友善的根文件系统中,/user/lical/smplayer/bin目录中的smplayer脚本是有问题的,如果直接运行它,会出现鼠标和触摸屏

不能使用的情况,我们要将/bin目录下的smplayer脚本复制过来,并将最后两行中的qws去掉。(前面提到过的,我们要多租蔽任务运行,不需要再开一

个qws)

export HOME=/root

cd /usr/local/smplayer/

exe__c ./smplayer #-qws 1>/dev/null

2>/dev/null

// 此处有屏蔽字,真实没有下划线

#hotplug

4、修改rcS文件,使之开机就运行HelloQt4i程序

rcS文件如下:

#!

/bin/sh

PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin:

runlevel=S

prevlevel=N

umask 022

export PATH runlevel prevlevel

#

#Trap CTRL-C &c

only in

this shell so we

can interrupt subprocesses.

#

trap ":" INT QUIT TSTP

/bin/hostname Crt

[ -e /proc/1 ]

||

/bin/mount -n -t proc none

/proc

[ -e /sys/class ] ||

/bin/mount -n -t sysfs none /sys

[ -e /dev/tty ]

||

/bin/mount

-t ramfs

none /dev

/bin/mount -n -t usbfs none

/proc/bus/usb

echo /sbin/mdev >

/proc/sys/kernel/hotplug

/sbin/mdev -s

/bin/hotplug

# mounting file system specified in

/etc/fstab

mkdir -p /dev/pts

mkdir -p /dev/shm

/bin/mount -n -t devpts none

/dev/pts -o mode=0622

/bin/mount -n -t tmpfs tmpfs /dev/shm

/bin/mount

-n

-t ramfs

none /tmp

/bin/mount -n -t ramfs none

/var

mkdir -p /var/empty

mkdir -p /var/log

mkdir -p /var/lock

mkdir -p /var/run

mkdir -p /var/tmp

/sbin/hwclock -s

syslogd

/etc/rc.d/init.d/netd start

echo "

"

>

/dev/tty1

echo "Starting networking..."

>

/dev/tty1

sleep 1

/etc/rc.d/init.d/httpd start

echo "

"

>

/dev/tty1

echo "Starting web server..."

>

/dev/tty1

sleep 1

/etc/rc.d/init.d/leds start

echo "

"

>

/dev/tty1

echo "Starting leds service..."

>

/dev/tty1

echo "

"

sleep 1

echo "

"

>

/dev/tty1

/etc/rc.d/init.d/alsaconf start

echo "Loading sound card config..."

>

/dev/tty1

echo "

"

/sbin/ifconfig lo 127.0.0.1

/etc/init.d/ifconfig-eth0

#/bin/qt4 &

#echo "

"

>

/dev/tty1

#echo "Starting Qt4 Applications, please

waiting..."

>

/dev/tty1

#/bin/smplayer &

#echo "

"

>

/dev/tty1

#echo "Starting smplayer Applications, please

waiting..."

>

/dev/tty1

/bin/hello_qt4app &

echo "

"

>

/dev/tty1

echo "Starting

hello_qt4 Applications, please

waiting..."

>

/dev/tty1

hello_qt4app脚本如下:

#!/bin/sh

rm /root/.config/

-rf

rm /root/.mplayer/

-rf

if [ -e /etc/friendlyarm-ts-input.conf ] then

. /etc/friendlyarm-ts-input.conf

fi

true

${TSLIB_TSDEVICE:=/dev/touchscreen}

TSLIB_CONFFILE=/etc/ts.conf

export TSLIB_TSDEVICE

export TSLIB_CONFFILE

export TSLIB_PLUGINDIR=/usr/lib/ts

export TSLIB_CALIBFILE=/etc/pointercal

export QWS_DISPLAY=:1

export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH

export PATH=/bin:/sbin:/usr/bin/:/usr/sbin:/usr/local/bin

if [ -c /dev/touchscreen ]then

export

QWS_MOUSE_PROTO="Tslib:${TSLIB_TSDEVICE}

MouseMan:/dev/input/mice"

if [

-e

/etc/pointercal -a !

-s

/etc/pointercal ] then

rm

/etc/pointercal

fi

else

export

QWS_MOUSE_PROTO="MouseMan:/dev/input/mice"

>/etc/pointercal

fi

export QWS_KEYBOARD=TTY:/dev/tty1

export HOME=/root

cd /opt

./hello_qt4

-qws

1>/dev/null

2>/dev/null

hotplug

然后,重启开发板,hello_qt4程序运行了,再点button,播放器也d出来了。

本文介绍的是,对于插件式应用程序的讲解,也很详细,我们废话不多说,先看内容。动态链接库技术使软件工程师们兽血沸腾,它使得应用系统(程序)可以以二进制模块的形式灵活地组建起来。比起源码级别的模块化,二进首茄此制级别的模块划分使得各模块更加独立,各模块可以分别编译和链接,模块的升级不会引起其它模块和主程序的重新编译,这点对于大系统的构建来说更加实用。另一方面,对于商业目的明显的企业,各模块可以独立设置访问权限,开发成员只能访问自己负责的模块,其它模块是不能也不给看到的,这样减少了整个系统泄漏技术的风险。一、动态链接库技术概况动态链接库技术用得很多。事实上,整个Windows就是由一个个动态链接库(DLL)构建起来的,不管是系统内核,或是系统调用的API封装,还是通用工具(如控制面板、ActiveX插件等),都是一个个动态链接库文件。动态链接库并不是微软独有的技术,它是软件工程发展到一定阶段的必然产物。在类Unix系统中,这种二进制可执行模块技术不叫动态链接库,而被称为共享对象或共享库,后缀名一般为.so(即Share Object的简写)。为简便,下文将统称这种动态链接的技术为DLL或共享库。其实,DLL文件跟普通的可执行文件差别不大,都是可执行文件嘛,装载到进程空间后,都是一些机器指令(函数代码)、内存分配(变量)等。在Windows中,这些可执行文件被称作PE/COFF格式文件,在Linux则称为ELF文件。从CPU的角度看来,程序中的各个要素,不管是函数还是变量,它们都是一个个地址,函数是入口地址,变量是访问地址;而C++的所谓类或对象,最后也被编译器肢解成了一个个变量和函数代码(这里是形象的说法,严谨技术解说请搜索C++对象模型)。DLL的装载(指导入进程空间,然后执行)方式比可执行文件的装载稍微复杂,因为它把模块链接过程推迟到了运行时。在动态链接库的装载过程中,首要任务就是解决地址重定向问题。我们知道,DLL装载到进程空间的位置(基址)是不确定的(动态装载嘛),即使DLL内部使用的函数调用和全局变量引用,在装载时都要重新计算其地址。Windows采用基址重定向(Rebasing)技术解决这一问题,而Linux采用地址无关代码(PIC,通过GOT和PLT表实现)技术。这两种技术各有优缺点。二、Qt中的动态链接库编程使用C++面向对象的类编写DLL是要注意很多细节的,主要是二进制(ABI)兼容问题。COM是一个很成功的例子,只要符合COM的规范,我们就能编写出很好的DLL来,然而COM是微软私生的,要想跨平台,我们还得另找它路。Qt的跨平台特性同样令人(至少是我)兽血沸腾。如果你认为QT仅仅是一个跨平台界面库,那就小看它了。我要说的者迅是,它不但是一个通用的跨平台的面向对象的应用程序接口库(包括GUI、数据库、网络、多线程、XML、数据容器和算法等,常用的编辑资源都有封装,就是说,这些都可以跨平台,而不仅仅是界面),更是一种C++语言的扩展,一种编程平台和应用程序框架。信号和槽的机制简化了对象之间的通信,比MFC的消息映射直观多了;界面的布局管理机制使开发人员可以很轻松地编出优雅的窗体;界面语言翻译机制也很方便实用;QObject容器管理可以看到Qt在内存管理方面的努力;扩展的foreach循环结构也向现代语言靠拢……Qt的跨平台特性很好,对于本文的主题——动态链接库的支持也很好。QT对各种平台的动态链接库编程技术都有包装,QT把这种技术统一命名为共享库(Shared Libraries)。通过使用Qt包装过的类和宏,可以编写跨平台的共享库和插件——当然,这只是源代码级别的跨平台,你不要指望用MSVC编译出来的DLL,能集成到ARM平台的Linux程序上面——这是一个很美很美的理想哦。QT使用以下两个宏来实现符号(函数或全局变量/对象)的导出和导入(跨平台不能用def文件了):Q_DECL_EXPORT // 必须添加到符号声明中(共享库项目) Q_DECL_IMPORT // 必须添加到符号声明中(使用共享库的客户项目) Q_DECL_EXPORT // 必须添加到符号声明中(共享库项目)Q_DECL_IMPORT // 必须添加到符号声明中(使用共享库的客户项目)QT使用 QLibrary 类实现共享库的动态加载,即纳知在运行时决定加载那个DLL程序,插件机制使用。三、QT共享库和插件范例本节通过例子,实现一个共享库和一个插件。在Windows平台上开发,使用VS2005编译,QT库版本为4.6.2。本例了将编写以下三类项目:Bil 项目:共享库项目,输出Bil.dll和Bil.lib,基础接口类库,定义一个公共的接口IAnimal(抽象类),供客户项目和插件项目使用;Plugin 类项目:插件类项目,现编写BilDog和BilPanda两插件项目,实现IAnimal的功能,供客户项目加载和测试。两项目输出BilDog.dll和BilPanda.dll;Test 项目:客户应用程序项目,输出Test.exe,界面中可以选择要加载的Animal插件,然后调用Animal的功能函数,完成测试;1. 编写共享库——Bil 项目的实现该项目定义一个抽象的 IAnimal 类作为导出接口,供客户项目和插件项目使用。项目类型为共享库,将生成Bil.lib和Bil.dll两个文件,Bil.lib供Plugin项目和Test 项目引用,而Bil.dll将给Test.exe运行时动态加载。新建一个头文件Bil.h,输入如下代码:view plaincopy to clipboardprint? #ifndef BIL_H #define BIL_H #include <Qt/qglobal.h>// 定义BIL_SHARE,使用者可以不用再处理符号的导入和导出细节 #ifdef BIL_LIB # define BIL_SHARE Q_DECL_EXPORT #else # define BIL_SHARE Q_DECL_IMPORT #endif #endif // BIL_H #ifndef BIL_H #define BIL_H #include <Qt/qglobal.h>// 定义BIL_SHARE,使用者可以不用再处理符号的导入和导出细节 #ifdef BIL_LIB # define BIL_SHARE Q_DECL_EXPORT #else # define BIL_SHARE Q_DECL_IMPORT #endif #endif // BIL_H 你现在可能不知道BIL_SHARE宏有何用处。没关系,请继续看下面的IAnimal接口定义代码:view plaincopy to clipboardprint? #ifndef IANIMAL_H #define IANIMAL_H #include "Bil.h" class BIL_SHARE IAnimal { public: IAnimal()virtual ~IAnimal()public: virtual void Eat() = 0virtual void Run() = 0virtual void Sleep() = 0}#endif // IANIMAL_H #ifndef IANIMAL_H #define IANIMAL_H #include "Bil.h" class BIL_SHARE IAnimal { public: IAnimal()virtual ~IAnimal()public: virtual void Eat() = 0virtual void Run() = 0virtual void Sleep() = 0}#endif 现在知道BIL_SHARE宏的妙用了吧。BIL_SHARE宏会根据项目编译选项BIL_LIB有没有定义,自动声明IAnimal是导出类,还是导入类。所以,使用BIL_SHARE宏,我们只需要向IAnimal插件的开发者提供同一份IAnimal定义文件(IAnimal.h)即可。当然,我们得先在Bil项目的编译选项中定义BIL_LIB宏,使得在Bil项目内,BIL_SHARE就是导出符号的声明。插件项目就不要定义BIL_LIB了,因为在Animal插件项目中,IAnimal是导入符号。编译选项如何定义宏?如果使用Visual Studio工程文件,依次展开:项目属性->配置属性->C/C++->预处理器,在预处理器定义中添加宏BIL_LIB即可;如果是QT工程文件,请在QT工程文件Bil.pro中加入如下定义:DEFINES += BIL_LIB DEFINES += BIL_LIB 在IAnimal接口中,我们定义了三个纯虚函数Eat()、Run()和Sleep(),表示吃、跑和睡眠的动作,这是抽象的,因为不同的动物有不同的吃相和睡眠姿态,而世间的动物何止千千万——无所谓,让这些具体动物的不同表现交给IAnimal插件的编写者发挥吧——这就是接口的魅力,加上插件的思想,整个应用程序就变成开放的,可扩展的了!继续编写Anima类的实现文件Anima.cpp:view plaincopy to clipboardprint? #include "IAnimal.h" IAnimal::IAnimal() { } IAnimal::~IAnimal() { } #include "IAnimal.h" IAnimal::IAnimal() { } IAnimal::~IAnimal() { } 虽然只实现了构造和析构函数,并且什么工作也不做,但这是必要的,我们暂时不要使用内联的构造和析构函数,否则在插件项目实现IAnimal时可能会出现链接错误。好了,我们开始编译吧,生成整个Bil项目。最终我们得到两个输出文件:Bil.lib 和 Bil.dll。我们向Animal插件开发者提供:两个头文件:Bil.h 和 IAnimal.h两个库文件:Bil.lib 和 Bil.dll下面的插件类项目和客户项目就是依赖这些文件实现的,也许你更愿意把Bil看作是一个通用的DLL类库,就像QT或MFC一样——事实上也是如此,Bil就是这样一个动态的共享类库。2. 编写Animal插件——BilDog和BilPanda项目的实现现在,让我们来实现两个小插件。BilDog插件很简单,只是汇报下“我是Dog,我正在啃骨头”;BilPanda也是如此——这里仅仅是测试而已,实现的项目中,你可以尽情的发挥——没错,是在遵循IAnimal接口的前提下。创建BilDog项目,把Bil项目输出的Bil.h、IAnimal.h和Bil.lib加入到工程。创建Dog类的头文件Dog.h: view plaincopy to clipboardprint? #ifndef CLASS_DOG_H #define CLASS_DOG_H #include "IAnimal.h" class Dog : public IAnimal { public: Dog(void)virtual ~Dog(void)public: virtual void Eat()virtual void Run()virtual void Sleep()}#endif // CLASS_DOG_H #ifndef CLASS_DOG_H #define CLASS_DOG_H #include "IAnimal.h" class Dog : public IAnimal { public: Dog(void)virtual ~Dog(void)public: virtual void Eat()virtual void Run()virtual void Sleep()}#endif 创建Dog类的实现文件Dog.cpp:view plaincopy to clipboardprint? #include <QtGui/QMessageBox>#include "Dog.h" Dog::Dog(void) { } Dog::~Dog(void) { } void Dog::Eat() { QMessageBox::information(NULL, "Hello", "Dog eating ...")} void Dog::Run() { QMessageBox::information(NULL, "Hello", "Dog running ...")} void Dog::Sleep() { QMessageBox::information(NULL, "Hello", "Dog sleeping ...")} #include <QtGui/QMessageBox>#include "Dog.h" Dog::Dog(void) { } Dog::~Dog(void) { } void Dog::Eat() { QMessageBox::information(NULL, "Hello", "Dog eating ...")} void Dog::Run() { QMessageBox::information(NULL, "Hello", "Dog running ...")} void Dog::Sleep() { QMessageBox::information(NULL, "Hello", "Dog sleeping ...")} 调用QT的QMessageBox::information()函数d出一个信息提示框。还有一个非常重要的工作,我们得提供一个能够创建(释放)Animal具体对象(这里是Dog)的接口,并且把这些函数导出,让主程序(Test.exe)能够解析这个接口函数,动态创建Animal对象,并访问其功能。新建BilDog.h文件,输入下面的代码:view plaincopy to clipboardprint? #ifndef BILDOG_H #define BILDOG_H #include "Dog.h" // extern "C" 生成的导出符号没有任何修饰,方便主程序找到它 extern "C" { Q_DECL_EXPORT IAnimal * CreateAnimal()Q_DECL_EXPORT void ReleaseAnimal(IAnimal * animal)} #endif // BILDOG_H #ifndef BILDOG_H #define BILDOG_H #include "Dog.h" // extern "C" 生成的导出符号没有任何修饰,方便主程序找到它 extern "C" { Q_DECL_EXPORT IAnimal * CreateAnimal()Q_DECL_EXPORT void ReleaseAnimal(IAnimal * animal)} #endif 这两个函数的工作很简单,直接创建和释放对象即可。

qt

可以通过QGLWidget运行opengl。QGLWidget继承QWidget,能够直接在里面调用opengl的接口。这个在qt文档里有具体说

明,也有相关例子,所以不赘述了。但是无法在正式软件里面执行,为什么?因为正式软件是用QGraphicsScene这个场景类 *** 作和 *** 作一切

item,而用QGraphicsView将其显示出来,而每一个item都是QGraphicsItem的子类。QGLWidget并不是QGraphicsItem类,我曾经尝试用普通的QWidget类那样,通过proxy来加进QGraphicsItem,但是没有成功。或许有方法,但是没有找到。

于是我放弃了用QGLWidget来 *** 作opengl的打算,寻找直接在QGraphicsItem中 *** 作opengl的方法。通过查看文档和示例代码,找到了这个方法:

1 往qt工程文件里添加opengl以及对应的lib。

2

对QGraphicsView进行一个三维对话框的指定,代码如下:

QGLWidget *widget = new

QGLWidget(QGLFormat(QGL::SampleBuffers))

widget->makeCurrent()

QGraphicsView

view

view.setViewport(widget)

上述代码唤唯洞告诉了 QGraphicsView 类当前绘制的对象是支持opengl的。于是所有的场景中的item都将绘制到widget 上。

3

写一个QGraphicsItem的继承类,特别要重写paint函数。代码如下:

void XXX::paint(QPainter

*painter, const QStyleOptionGraphicsItem *option, QWidget

*widget)

{

painter->beginNativePainting()

glColor3f(0.5,1.0,0.2)

glBegin(GL_TRIANGLES)

glVertex3f(100.0,100.0,-100.0)

glVertex3f(150.0, 100.0,

-100.0)

glVertex3f(100.0, 150.0,

-100.0)

glEnd()

painter->endNativePainting()

}

上面这个函数主要是用opengl接口绘制了一个三角形。记住,在opengl绘制之前一定要执行painter->beginNativePainting()以及painter->endNativePainting()这两个语句。

QGraphicsScene、

QGraphicsView和QGraphicsItem的关系可以查阅相关文档,也不赘述了。

不过我按照这个方式画的三角形,怎么也在窗口上显示和枯不出来,找了半天才发现问题在这个函数上QGraphicsItem::boundingRect()。这个函数是

干什么用的呢?主要用来返回该item的初始化大小,这个大小不会轻易改变,后续的改变都可以通过矩山判阵来完成,但是初始大小是不变的。QGraphicsView通过这个矩形来判断当前item是不是需要重绘,如果在重绘区外,则不调用重绘函数了。同时碰撞检测之类,也可以用这个矩形来判断。原来,item本身的矩阵外包框不对,所以才导致了重回不出来,改过来就正确了。

上面说的很潦草,具体怎么改的步骤就不说了。要想正确的绘制,必须得弄清楚坐标系的关系,QGraphicsScene、QGraphicsView以及QGraphicsItem这三个坐标系到底是什么关系。我看了文档,也自己进行了测试,但是感觉文档和测试的结果有些出入。具体出入不说了。说一下自己得心的吧。

先说明:涉及到一切大小和长度,都是像素大小,至少我测试的结果是这样的。

在建立QGraphicsScene

对象的时候,有一个构造函数是矩形,这个矩形是什么含义呢?经过测试,发现这个矩形并没有指定d出窗口的位置,比如,我把矩形的左上角点指定为

-1000,-1000,显示的位置和1000,1000是一样的,而长度则正确指定了(当然,可能会有滚动条)。所以,这个矩形的左上角点并不是显示的

窗口的位置,而是它在逻辑上的左上角点。我们显示一切item,都是以这个逻辑上的坐标系为准来绘制的。比如,左上角点是-1000,-1000,而

item的位置在-500,-500,则这个-500,-500相当于在显示窗口的左上角往下各加500个像素的坐标的位置。

那么 QGraphicsItem的boundingRect是什么意思呢?返回的是什么大小?是以什么坐标系显示的大小?首先,这个大小肯定是以像素为单位的,其次,这个矩形的坐标是以QGraphicsScene的逻辑坐标为准的。当然这个大小是没有任何矩阵叠加的大小。有了矩阵叠加后,实际的矩形可能会发生变化。假如在boundingRect中指定矩形的左上角为100,100,那么最终体现的位置则是QGraphicsScene逻辑坐标100,100的位置,如果QGraphicsScene的左上角点已经指定为-1000,-1000,那么这个位置实际上就是离窗口左上角点1100,1100的位置(由于有滚动条,所以也不一定是这个长度。)

那么在QGraphicsItem的paint函数中进行了opengl绘制用的是什么坐标呢?其实用的也是QGraphicsScene

的逻辑坐标。如上面的例子,绘制的直角三角形直角顶点是0,0,那么显示的位置就是距离显示窗口左上角点1000,1000的位置。不过opengl的所

有绘制都是没有矩阵叠加的基础上,如果用矩阵叠加,则显示的位置肯定和指定的有区别了。比如,我用setPos强制指定一个位置,这个位置将和opengl绘图坐标相叠加,最后显示到窗口上。我推测setPos其实是改变了矩阵,是一个平移矩阵。


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/12564997.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-26
下一篇 2023-05-26

发表评论

登录后才能评论

评论列表(0条)

保存