[急切求助] 关于QT内转码以及QT线程问题

62 views
Skip to first unread message

Kitty Wu

unread,
Sep 28, 2011, 11:04:55 PM9/28/11
to xiyoulinux, fcctt, 王伦, xyli...@groups.163.com

最近在做英特尔的比赛,我们做的是基于wifi的文件传输,
现在遇到了些问题,向大家寻求帮助指导,问题阐述如下:

1,QT内转码问题,
描述: 传输文件,文件名出现乱码,(文件名是英文或者中文,都出现乱码),但是文件内容是正确的:

我们使用的文件传输协议的tftp协议,
tftp包格式是:| Opcode | Filename | 0 | Mode | 0 | 第一个包,
从第二个包开始传输文件内容,按字节传输,每个块512B

使用linuxC代码实现,通过qt调用进行文件传输,在qt中声明了C, 代码如下:

#ifndef TFTPC_H_
#define TFTPC_H_

#ifdef __cplusplus
extern "C" {
#endif

unsigned int tftp_client_send_file(const char *url, const char *hostaddr ,const int targetport);


#ifdef __cplusplus
};
#endif

#endif // TFTPC_H

然后在qt中的一个类方法中调用tftp_send_file(), 问题就在这里,qt中我们获得url类型是QString,在传参时我们已将url的类型进行了转换,
尝试了几种转换但是传输的文件,文件名依然是乱码,  尝试的转换类型有url.toAscii(), url.toLocal8bit(), 一直尝试着把QString转换成char*类型然后调用C接口.
但是都以失败告终...想知道..这个是否牵扯到Qt的内转码问题? 应该如何解决?

2,关于Qt UI冻结问题:
问题阐述:
在qt 的主进程中调用了从c++的一个方法,此方法中使用qthread创建了一个线程去跑上面我提到的tftp传输函数,
这ui在传输过程中冻结了...

我知道Qt中解决ui冻结的最好方法是使用信号-槽机制,但是现在由于我的上层界面使用的是qml写的(还不是很熟),我正在尝试在qml中发送信号,在C++中接收并创建线程去跑传输,

我想要询问:如果不使用信号槽,使用线程,是否可以?个人想法如下:
1,使用moveToThread()把这个传输线程抛到另一个线程中去运行,有人知道如何使用moveToThread方法么?找了些资料,但是说的很范,不会使用. 还有这个线程应该是由谁去创建?主进程?
2,在当前已创建的线程上再创建线程去跑传输...这个就是线程上再创建线程,,,可是第二个线程的父亲是谁?它使用的是谁的资源... ui主线程?
这样做ui还是会freez,对么?


PS:附加一个关于qml的问题,希望了解qml的童鞋帮忙解答一下...

1,qml中接收C++信号问题..
   当我们文件传输完毕后,会发送一个信号(filesent()),有qml接收,并在图形界面显示相关信息, 成功/失败,
现在出现的问题是: C++发送的signal, qml中没有接收到.
使用的是Connections{}属性, onFileSent:触发qml动作,    Connections{ } 放置在需要响应的qml元素中,某个Rectangle

结果是qml无法响应C++信号.. 


希望我已经把问题描述清楚了,求助解答...
明天就提交复赛作品了,还有这几个问题..木有解决~~
请高手指导呀~~
拜谢先~~

--

Regards~

吴云
~~~~
               use it , or u'll lose it...
                                       ~00~

Kitty Wu

unread,
Sep 29, 2011, 5:06:05 AM9/29/11
to Kermit, xiyoulinux, fcctt, 王伦, xyli...@groups.163.com


2011/9/29 Kermit <kermi...@gmail.com>
On Thu, Sep 29, 2011 at 11:04:55AM +0800, Kitty Wu wrote:
> 最近在做英特尔的比赛,我们做的是基于wifi的文件传输,
> 现在遇到了些问题,向大家寻求帮助指导,问题阐述如下:
>
> 1,QT内转码问题,
> 描述: 传输文件,文件名出现乱码,(文件名是英文或者中文,都出现乱码),但是文件内容是正确的:

   可能是你的文件名的编码出问题了(Utf8和GBK之间的转换),这个问题一般使用QTextCodec解决的,你看看这个类。


> 我们使用的文件传输协议的tftp协议,
> tftp包格式是:| Opcode | Filename | 0 | Mode | 0 | 第一个包,
> 从第二个包开始传输文件内容,按字节传输,每个块512B
>
> 使用linuxC代码实现,通过qt调用进行文件传输,在qt中声明了C, 代码如下:
>
>
> #ifndef TFTPC_H_
>
> #define TFTPC_H_
>
>  #ifdef __cplusplus
>
> extern "C" {
>
> #endif
>
>  unsigned int tftp_client_send_file(const char *url, const char
> *hostaddr ,const int targetport);
>
>
>  #ifdef __cplusplus
>
> };
>
> #endif
>
>  #endif // TFTPC_H
>
>
> 然后在qt中的一个类方法中调用tftp_send_file(),
> 问题就在这里,qt中我们获得url类型是QString,在传参时我们已将url的类型进行了转换,
> 尝试了几种转换但是传输的文件,文件名依然是乱码,  尝试的转换类型有url.toAscii(), url.toLocal8bit(),

光toXXX不行,还要看看你fromXXX的时候对不对。

> 一直尝试着把QString转换成char*类型然后调用C接口.
> 但是都以失败告终...想知道..这个是否牵扯到Qt的内转码问题? 应该如何解决?

还是看:QTextCodec。



> 2,关于Qt UI冻结问题:
> 问题阐述:
> 在qt 的主进程中调用了从c++的一个方法,此方法中使用qthread创建了一个线程去跑上面我提到的tftp传输函数,
> 这ui在传输过程中冻结了...



> 我知道Qt中解决ui冻结的最好方法是使用信号-槽机制,

   信号和槽严格地讲不是解决UI冻结的,是使用QApplication::processEvents()在处理的过程中处理其它的事件。这是个小技巧,但低效,而且不一定适合所有情况。真正处理UI冻结的办法的多线程。

 gmail又有点问题,我们的情况是这样的..
 UI调用了C++的一个方法,这个方法中创建了线程(代码如下),就像您说的ui主线程会和run()中的函数并行的跑,这样ui是应该不会冻结的啊..可是测试..ui是freeze 了..直到这个线程结束....

bool send_file::send_file_to_remote(QString url, QString address, int port)
{
    send_file_thread thread(url);
    thread.set_target(address, port);

    thread.start();
    thread.wait();    

    return true;
}
 

> 但是现在由于我的上层界面使用的是qml写的(还不是很熟),我正在尝试在qml中发送信号,在C++中接收并创建线程去跑传输,

   qml我没有用过,我认为那个东西一般是用作UI美工和程序员沟通和演示用的,真正做界面我绝对不会用它。

> 我想要询问:如果不使用信号槽,使用线程,是否可以?个人想法如下:

当然可以。

> 1,使用moveToThread()把这个传输线程抛到另一个线程中去运行,有人知道如何使用moveToThread方法么?找了些资料,但是说的很范,不会使用.
> 还有这个线程应该是由谁去创建?主进程?

   一般是自己实现一个QThread的子类,尤其是他的run()方法,那个方法里的东西都会在一个新的线程中跑,相当与C语言中在pthread_create()中通过void *(*start_routine) (void *)指定的线程函数一样。
   我没有用过moveToThread(),


> 2,在当前已创建的线程上再创建线程去跑传输...这个就是线程上再创建线程,,,可是第二个线程的父亲是谁?它使用的是谁的资源... ui主线程?
> 这样做ui还是会freez,对么?

它用的是UI主线程的资源,但是主线程不会冻结,他俩并行地跑。你看看QThread就知道了,一般吧要传递给线程的参数和其它资源作为QThread子类的成员,也就是说,你可以使用指针或者引用来访问任何你想要的父类资源。



> PS:附加一个关于qml的问题,希望了解qml的童鞋帮忙解答一下...
>
> 1,qml中接收C++信号问题..
>    当我们文件传输完毕后,会发送一个信号(filesent()),有qml接收,并在图形界面显示相关信息, 成功/失败,
> 现在出现的问题是: C++发送的signal, qml中没有接收到.
> 使用的是Connections{}属性, onFileSent:触发qml动作,    Connections{ }
> 放置在需要响应的qml元素中,某个Rectangle
>
> 结果是qml无法响应C++信号..

   我没有用过qml,但你可以用qml写个最简单的HelloWorld试试,如果不行,可以把代码贴出来我帮你看看。


> 希望我已经把问题描述清楚了,求助解答...
> 明天就提交复赛作品了,还有这几个问题..木有解决~~
> 请高手指导呀~~
> 拜谢先~~
>
> --
>
> Regards~
>
> 吴云


B.R
Kermit

Kitty Wu

unread,
Sep 29, 2011, 5:49:44 AM9/29/11
to Kermit, xiyoulinux, fcctt, 王伦, xyli...@groups.163.com


2011/9/29 Kermit <kermi...@gmail.com>
On Thu, Sep 29, 2011 at 05:06:05PM +0800, Kitty Wu wrote:

>  gmail又有点问题,我们的情况是这样的..
>  UI调用了C++的一个方法,这个方法中创建了线程(代码如下),就像您说的ui主线程会和run()中的函数并行的跑,这样ui是应该不会冻结的啊..可是测试..ui是freeze
> 了..直到这个线程结束....
>
>
> bool send_file::send_file_to_remote(QString url, QString address, int port)
>
> {
>
>     send_file_thread thread(url);
>
>     thread.set_target(address, port);
>
>
>     thread.start();
>
>     thread.wait();
     //你这里的wait()吧ui线程阻塞了,不要加这个。
     //thread结束后会自己发一个finished()信号出来的,通过
     //它去获取相应状态进行处理。

开始我也觉得是wait把线程阻塞了,当去掉此句后,
传输动作出发后,会出现如下错误:

QThread: Destroyed while thread is still running
Segmentation fault

 然后界面就死掉了`~~

还有就是,我的传输信号是在run中通过调用C方法返回值去发出的..(还是看代码好说话 ),所以我想是不是就可以不用考虑thread的结束状态了..让它运行完自己destory掉就好了..还是说必须对其结束状态进行处理?(抱歉..第一次真正用qt开发..很多东西都不清楚..看了很多文档,但还是有点模糊~)

void send_file_thread::run()   // probelm here
{
    int retval;
    qDebug("inner sending thread -------------------------  start");
     retval =  tftp_client_send_file(_url.toAscii(),_host.toAscii(), _port);
   if (retval < 0) {
        qDebug("fail to send file");
        emit failedToSend();
   } else {
        qDebug("send file successfully");
        emit fileSent();
   }
   qDebug()<< "++++++++++++" << qPrintable(_url);
    qDebug("inner sending thread -------------------------    end");

}

>     return true;
>
> }
>


B.R
Kermit

Kitty Wu

unread,
Sep 29, 2011, 10:10:20 PM9/29/11
to Kermit, xiyoulinux, fcctt, 王伦, xyli...@groups.163.com


2011/9/30 Kermit <kermi...@gmail.com>
On Thu, Sep 29, 2011 at 05:49:44PM +0800, Kitty Wu wrote:
> 2011/9/29 Kermit <kermi...@gmail.com>

<snip>

> 开始我也觉得是wait把线程阻塞了,当去掉此句后,
> 传输动作出发后,会出现如下错误:

不用想,肯定是Wait造成的阻塞;出现错误则是另外一个问题。


> QThread: Destroyed while thread is still running
> Segmentation fault
>
>  然后界面就死掉了`~~

你的thread对象是不是局部变量(最好不要使用局部变量来操作QThread),亦或是你手动delete删除了?

恩`~您说的对`~我的thread对象是局部变量~~没有手动delete
ok~~我知道了,我应该在主线程中创建线程... 

> 还有就是,我的传输信号是在run中通过调用C方法返回值去发出的..(还是看代码好说话
> ),所以我想是不是就可以不用考虑thread的结束状态了..让它运行完自己destory掉就好了..还是说必须对其结束状态进行处理?(抱歉..第一次真正用qt开发..很多东西都不清楚..看了很多文档,但还是有点模糊~)


最简单的办法是自己通过finished()信号来处理结果。删除QObject子类的对象时,用deleteLater()方法能够帮助你避开这些问题。

这个我看一下... 感谢



> void send_file_thread::run()   // probelm here
>
> {
>
>     int retval;
>
>     qDebug("inner sending thread -------------------------  start");
>
>      retval =  tftp_client_send_file(_url.toAscii(),_host.toAscii(), _port);
//上面这个函数会阻塞,对么?

是的..这个函数里面是有死循环的...恩~~~
让他跑到主线程创建的线程中应该木有问题吧~~~?

 


>    if (retval < 0) {
>
>         qDebug("fail to send file");
>
>         emit failedToSend();
>
>    } else {
>
>         qDebug("send file successfully");
>
>         emit fileSent();
>
>    }
>
>    qDebug()<< "++++++++++++" << qPrintable(_url);
>
>     qDebug("inner sending thread -------------------------    end");
>
>  }
>
>
> > >     return true;
> > >
> > > }

B.R
Kermit

Kitty Wu

unread,
Sep 30, 2011, 3:13:21 AM9/30/11
to Kermit, xiyoulinux, fcctt, 王伦, xyli...@groups.163.com
ok~~~问题已经全部解决~~

等今天忙完了`~
我整理一下..再晒出解决方法`~~

2011/9/30 Kitty Wu <just....@gmail.com>

Kitty Wu

unread,
Oct 4, 2011, 11:13:28 PM10/4/11
to xiyoulinux, fcctt, 王伦, xyli...@groups.163.com, Kermit
今天稍稍总结一下我前几天提出的问题...
在此谢谢Kermit以及各位帮助我解决问题的同学...

1,关于QT转码问题..
        想起来是我们的一个很愚蠢的疏忽...其实说了我们文件传输部分不是用QT处理的,所以确实和QT的内转码应该是扯不上关系的..最终的bug根源是在C程序中,传输文件时,文件名只被初始化而没有进行赋值操作....所以会导致乱码出现..
这个问题我反思了很久...整合程序时不够耐心,细心,用心.

2,关于QT UI冻结问题:
       解决QT UI冻结问题的根本方法是多线程,虽然当时我也采用了多线程编程,但是有一个致命错误,就是将thread创建为一个局部变量,这样,只要函数返回,新创建的线程必然被迫销毁...正确的做法是在main函数中创建新线程,这样新线程便可以自己运行其他程序,并不会影响到图形界面.
     我的做法是用信号-槽关联,然后在main线程中start新线程.
关于当时提到的MoveTothread(),它的主要作用是将当前线程转移到另一个线程中去运行,这也就是说当前线程已经完全脱离原线程/进程的对象.所以使用时请切记这点..

3,关于qml接收C++信号问题:
     Kermit也说了qml是用来美化UI的..嗯,确实是这样的,由于是在移动终端上做应用程序,所以界面的美化工作也是相当重要的,这就是我们为什么选择选择qml去写界面..用qt去处理事件程序.所以如果想要用qml编程,就必须先了解qml和C++的交互机制.

qml个人觉得其实还蛮强大的...由于很多东西都是新接触的,所以摸索了很久...也遇到了很多抽象的问题..

对于上次提到的,无法在qml中接收C++信号问题,主要是因为没有将signal NOTIFY给qml,这个主要是使用QPROPERTY()宏将C++的信号或者类成员函数/变量暴露给qml,使得qml可以之间使用..但是..qml中发出的信号是可以直接被C++的槽函数接收的...(觉着吧,还挺奇怪的)


Well~ that's all.

2011/9/29 Kitty Wu <just....@gmail.com>
Reply all
Reply to author
Forward
0 new messages