QT中调用外部程序的方法 QProcess类

QT4对于界面编程无疑是一个很方便的工具。但是由于它界面开发专项特性,可能导致了某些方面的不足(到目前为止暂时没有使用到这类复杂功能,所以只能是推测)。这样当整个程序需要某些功能时,就需要外部模块的支持。为了能够与外部程序相互联系,Qt4提供了强大的外部程序调用类。先说说QProcess类,目前主要用到程序调用函数。官方说明如下:

(引用自ttp://qt.nokia.com/doc/4.5/qprocess.html#execute-2)

  

#include

int QProcess::execute ( const QString & program, const QStringList & arguments )   [static]
Starts the program program with the arguments arguments in a new process, waits for it to finish, and then returns the exit code of the process. Any data the new process writes to the console is forwarded to the calling process.

The environment and working directory are inherited by the calling process.

On Windows, arguments that contain spaces are wrapped in quotes.

int QProcess::execute ( const QString & program )   [static]
This is an overloaded function.

Starts the program program in a new process. program is a single string of text containing both the program name and its arguments. The arguments are separated by one or more spaces.

  

   这两个函数使用起来是很简单的,很方便就可以调用外部程序。

   但是有一点是值得注意的,当外部函数被调用以后,主程序的进程就会被调用的函数阻塞,导致无法继续对操作做出反映。要解决这个问题,可以利用QThread类为调用的外部程序建立一个新进程,建立方法如下:

例如需要在窗口中打开注册表编辑器

    1、明确打开文件的位置和名称,注册表编辑器名称为regedit

    2、建立一个类MyThread,用于继承QThread类,并声明虚函数run(),该函数用于程序调用该进程时自动调用。

      

       #include

       class MyThread : public QThread

       {

        public

            void run();

       };

    3、在MyTread::run()函数中添加需要该进程执行的内容(本例子中要利用QProcess类调用regedit)

       #include

       void MyThread::run()

       {

            QProcess process;

 

           

            process.execute("regedit");

        }

     经过以上的处理后,在运行regedit的时候主窗口就不会因阻塞而无响应了。

     这只是个简单的实现外部函数调用的方法,至于进程如何同步的问题,还在继续研究中


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/robin7513/archive/2009/11/22/4850826.aspx

 

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

 

问题:
    我做的那个小软件的图形界面是基于QT3.2的,在主界面的命令行编辑框输入命令以后要执行别人已经写好的可执行文件。这些可执行文件执行的时间比较长,在终端上运行时会显示一些运行的信息,最后才显示执行结果。我的界面上有一个文本框,我想把它们在后台执行过程中的信息不断添加到文本框中,相当于实时显示吧,不过要求也不是那么高。

    我说我现在怎么做的吧,我在一个叫做QGUI_CommandWidget类(属于主窗口)中定义了一个命令行编辑框输入命令,定义一个QTextEdit对象用来显示那些执行信息,定义了一个自定义的MyThread类对象用来执行外部程序,在这个线程的run函数里我调用fork,execv函数执行外部程序,把可执行程序的标准输出重定向到管道,然后从管道读那些信息,再把这些信息用QApplication::postEvent()函数传回主线程,由主线程把这些信息append到文本框中。

    我现在的疑问是:
        第一,执行外部程序,用fork、execv函数是不是不行,非要用QProcess不可?为什么呢?论坛上讲的也不是很清楚。具体怎么做呢?在那个QGUI_CommandWidget类创建一个QProcess类对象还是在我MyThread类对象里再创建一个QProcess类对象?
        第二,基于qt3的GUI线程和非GUI线程的通信,应该怎么做?那个外部程序我是不能更改的,它什么时候结束我也不知道。用QProcess的话它的输出信息我要怎么样才能读到然后回显在我的主窗口的文本框中?怎么知道可执行程序结束然后杀死该线程?
        第三,我在《C++ GUI programming with qt3》中看到:“ QTimer 类以及应用于网络的QFtp, QHttp, QSocket, and QSocketNotifier 类都是基于消息事件循环的,所以也不能用在非GUI线程中。”这是为什么呢?还有我看了别人用QQSocketdevice的例子里都用到了QSocketNotifier。在你的博客说到用Qthread、QQSocketdevice、QWaitCondition可以完成视频采集,你是否也用到QSocketNotifier?

回答:
1)完全可以使用fork,execv函数,其实QProcess类只是对这些底层函数的封装而
已,但是考虑到使用QProcess的话,不需要自己处理程序管道,也不需要自己处理
windows下的情况,可以省去很多时间,因此还是推荐使用QProcess,他们的效果
将是一样的。

2)照你的需求,完全可以不需要使用线程,因为QProcess已经自己处理掉这些事
了,在使用QProcess的start函数执行外部程序后,这个函数不会被阻塞,另外
QProcess也会以事件的方式自动将外部程序传回的信息反馈回来。具体看以下这个
简单的例子:

class enstCdRecord : public QObject
...{
  。。。。。。。。。。。。
  QProcess mProcess;
};

enstCdRecord::enstCdRecord(QWidget *pParent)
...{
  mParent = pParent;
  connect(&mProcess, SIGNAL(readyReadStandardError()), this,
  SLOT(ReadProcessOutput())); //连接readyReadStandardError事件,这样就可以
    得到程序StdErr中的信息了,同样也可以连接其 readyReadOutput事件。
}

bool enstCdRecord::CreateCd(const QString &pImageFile)
...{
  QStringList cmdlist;
  cmdlist.append("-v");
  cmdlist.append("speed=2");
  cmdlist.append(pImageFile);

  mProcess.start("cdrecord.exe", cmdlist);
  while (! mProcess.waitForFinished(300)) ...{ //启动程序后,用循环等待其结
    束,如果对程序何时结束并不关心,以下代码可以不需要。
  if (mProcess.state() == QProcess::NotRunning) ...{ //process failed
    QMessageBox::critical(mParent, SYSTEMNAME, tr("Error when record cd."));
    return false;
  }
  qApp->processEvents(); //防止UI死锁,一般情况下,用这种等一小段时间(这
    里是300ms),让UI响应一次的办法,已经足够使用了。
  }
  if (mProcess.exitCode() != 0) ...{ //error when run process
    QMessageBox::critical(mParent, SYSTEMNAME, tr("Error when record cd."));
    return false;
  }
  return true;
}

void enstCdRecord::ReadProcessOutput()
...{
  QMessageBox::critical(mParent, SYSTEMNAME,
  mProcess.readAllStandardError()); //将程序的StdErr信息显示出来。
}

外部程序究竟使用StdOut还是使用StdErr来作为运行时状态的输出,各个程序的处
理方式都不一样,甚至可能根本没有输出,这个需要自己试验。

3)一般网络程序中只要在主线程中使用QSocket和QSocketNotifier,就可以完成
数据的发送和接收了,它们不会造成程序界面死锁。在我写的blog的情况下,我的
程序在从网络上接收到数据后,需要做一些计算处理和保存工作,由于数据量很
大,并且程序对性能的要求比较高,因此只能将整个网络数据接收功能放到线程中
了,在那种情况下,QSocket并不适用,而必须使用同步的QSocketDevice。

其实,QT3下提供两种网络访问功能,一类是QFtp, QHttp, QSocket, and
QSocketNotifier等,它们都会在接收到数据后,以事件方式进行通知。另一类是
QSocketDevice,它不会主动发出任何通知事件,而是必须靠外部程序来查询,或
者等待其接收到数据,才能知道何时有数据被收到。

《C++ GUI programming with qt3》中的那句话没有错,(但是它是针对QT3说的,
在QT4中根本就没有这几个类了,并且QT4中Thread也可以用事件了)。在QT3中,
只有 UI线程在可以使用事件,在其它辅助线程中是无法使用的,因此不能使用靠
事件进行通知的那几个类了。

我的程序中没有使用QSocketNotifier,正如前面说的,这个类只是配合QSocket使
用的,它是考事件进行通知的。我的程序使用的是 QSocketDevice,并且靠其Wait
功能,来等待数据到达。

你可能感兴趣的:(QProcess,Qt)