posts - 319, comments - 22, trackbacks - 0, articles - 11
  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

QT也可以像VS那样使用预编译头文件来加速编译器的编译速度。首先在.pro文件中加入:

CONFIG += precompiled_header

然后定义需要预编译的头文件:

PRECOMPILED_HEADER = pch.h

其中pch.h头文件即为自定义的预编译头文件。

posted @ 2011-04-15 23:02 RTY 阅读(879) | 评论 (0)编辑 收藏

Qt元类型(MetaType)注册门

      昨天调试项目时,突然发现如下消息:

QObject::connect: Cannot queue arguments of type 'ERROR_LEVEL'
(Make sure 'ERROR_LEVEL' is registered using qRegisterMetaType().)

其中ERROR_LEVEL只是我定义的枚举类型即enum ERROR_LEVEL。然后在Qt的信号-槽函数的参数中使用了这个枚举型,在发送信号时就出现了上述警告。上面警告的大概意思是信号队列中无法使用 ERROR_LEVEL类型,要使用qRegisterMetaType()注册该类型后方可使用。

      通常使用的connect,实际上最后一个参数使用的是Qt::AutoConnection类型:

bool QObject::connect ( const QObject * sender, const char * signal, const QObject * receiver, const char * method, Qt::ConnectionType type = Qt::AutoConnection )

Qt支持6种连接方式,其中3中最主要:

  • Qt::DirectConnection(直连方式)

      当信号发出后,相应的槽函数将立即被调用。emit语句后的代码将在所有槽函数执行完毕后被执行。(信号与槽函数关系类似于函数调用,同步执行

  • Qt::QueuedConnection(排队方式)

      当信号发出后,排队到信号队列中,需等到接收对象所属线程的事件循环取得控制权时才取得该信号,调用相应的槽函数。emit语句后的代码将在发出信号后立即被执行,无需等待槽函数执行完毕。(此时信号被塞到信号队列里了,信号与槽函数关系类似于消息通信,异步执行

  • Qt::AutoConnection(自动方式)

      Qt的默认连接方式,如果信号的发出和接收这个信号的对象同属一个线程,那个工作方式与直连方式相同;否则工作方式与排队方式相同。

      我的项目中的确跨线程使用了ERROR_LEVEL为参数类型的信号,因此使用的应当是排队方式的信号-槽机制,出现“队列中无法使用ERROR_LEVEL类型”的警告信息就可以理解了。放狗搜了一圈,有篇文章提供了个这样的解决方案:

connect(cm, SIGNAL(sendLog(QUuid, QByteArray, bool)),
            this,SLOT(sendRes(QUuid,QByteArray,bool)));
改为:
connect(cm, SIGNAL(sendLog(QUuid, QByteArray, bool)),
            this,SLOT(sendRes(QUuid,QByteArray,bool)), Qt::DirectConnection);

这样做的确能使警告信息消失,因为Qt官方文档写了:

With queued connections, the parameters must be of types that are known to Qt's meta-object system, because Qt needs to copy the arguments to store them in an event behind the scenes.

即使用排队方式的信号-槽机制,Qt的元对象系统(meta-object system)必须知道信号传递的参数类型。这里手动改为直连方式,Qt的元对象系统就不必知道参数类型了,于是警告信息消失。但这样做是不安全的,见Qt官方文档:

Be aware that using direct connections when the sender and receiver live in different threads is unsafe if an event loop is running in the receiver's thread, for the same reason that calling any function on an object living in another thread is unsafe.

      因此,咱还是老老实实地用qRegisterMetaType()注册类型吧,见代码:

头文件

/*! \file errorlevel.h*/
#ifndef ERRORLEVEL_H
#define ERRORLEVEL_H

/*! \enum ERROR_LEVEL
 * 错误等级的定义。通常用来在传递错误消息时标记错误的等级。
 */
enum ERROR_LEVEL
{
    NORMAL,  /*!< 普通错误,通常不需要处理,可以记录或者显示错误消息。*/
    CRITICAL /*!< 严重错误,需要紧急处理,如果没有妥善处理,可能导致后续操作失败。*/
};

#endif // ERRORLEVEL_H

cpp文件

/*! \file errorlevel.cpp*/
#include "errorlevel.h"

/*! 模板函数显式实例化,注册ERROR_LEVEL到元对象系统。这样才可以在信号-槽
 * 队列里使用ERROR_LEVEL类型参数。
 */
int i = qRegisterMetaType<ERROR_LEVEL>("ERROR_LEVEL");
元类型注册方法受益于这篇文章

posted @ 2011-04-15 22:56 RTY 阅读(330) | 评论 (0)编辑 收藏

Registering custom types

February 15th, 2009

Just a note here, if you would have to pass custom data types between threads in Qt. As we know, a signal-slot connection is then (by default) of type Qt::QueuedConnection. Because in such a situation Qt needs to store passed parameters for a while, it creates their temporary copies. If it doesn’t recognize the passed data type, throws out an error:

 

QObject::connect: Cannot queue arguments of type 'MyType'
            

 

So custom data types have to be registered using qRegisterMetaType(), like in the example:

 

qRegisterMetaType<MyType>( "MyType" );
            

 

And this example is literal ⇒ when your class is called MyType, you register it as "MyType". Lastly I did something similar to this:

 

  1
              2
              3
            
typedef QMap<QString,QImage> MapStringImage;
            (...)
            qRegisterMetaType<MapStringImage>( "images" );
            

 

I didn’t get the error from QObject::connect (!), but also didn’t get things working. Wasted few hours hacking QMetaType class with no effect, and then more by accident than design changed "images" to "MapStringImage" and woo-hoo! That was my only problem… That’s why I’m stressing this naming issue, especially that documentation doesn’t tell a lot about it.

BTW I needed to use typedef because otherwise Qt didn’t have a clue what to do with such a complex type.




原文:http://hi.baidu.com/cyclone/blog/item/01108bd40599b00fa18bb793.html


基本理解

  • Q_DECLARE_METATYPE
    • 如果要使自定义类型或其他非QMetaType内置类型在QVaiant中使用,必须使用该宏。
    • 该类型必须有公有的 构造、析构、复制构造 函数
  • qRegisterMetaType 必须使用该函数的两种情况
    • 如果非QMetaType内置类型要在 Qt 的属性系统中使用
    • 如果非QMetaType内置类型要在 queued 信号与槽 中使用

二者关系

二者的代码:

  • Q_DECLARE_METATYPE 展开后是一个特化后的类 QMetaTypeId<TYPE>

  • qRegisterMetaType 将某类型注册中 MetaType 系统中

二者的联系:

  • QMetaTypeId<TYPE>的类中的成员包含对qRegisterMetaType的调用

  • 我们知道类中的成员函数并不一定会被调用(即,该宏并不确保类型被注册到MetaType)。

  • 通过qRegisterMetaType可以确保类型被注册

两个qRegisterMetaType 的联系

  • 无参的qRegisterMetaType函数会通过该成员调用带参数的qRegisterMetaType()

这两个东西真难理清,不妨看看源码吧。

Q_DECLARE_METATYPE

代码来源:src/corelib/kernel/qmetatype.h

#define Q_DECLARE_METATYPE(TYPE)                                        \
QT_BEGIN_NAMESPACE \
template <> \
struct QMetaTypeId< TYPE > \
{ \
enum { Defined = 1 }; \
static int qt_metatype_id() \
{ \
static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); \
if (!metatype_id) \
metatype_id = qRegisterMetaType< TYPE >(#TYPE); \
return metatype_id; \
} \
}; \
QT_END_NAMESPACE

  • 宏展开是一个在Qt的命名空间中的一个类模板的特化 QMetaTypeId<TYPE>

  • 该类含一个enum和一个返回!QMetaType的id的成员函数

qRegisterMetaType(const char *typeName)

代码来源:src/corelib/kernel/qmetatype.h

template <typename T>
int qRegisterMetaType(const char *typeName)
{
typedef void*(*ConstructPtr)(const T*);
ConstructPtr cptr = qMetaTypeConstructHelper<T>;
typedef void(*DeletePtr)(T*);
DeletePtr dptr = qMetaTypeDeleteHelper<T>;

return QMetaType::registerType(typeName, reinterpret_cast<QMetaType::Destructor>(dptr),
reinterpret_cast<QMetaType::Constructor>(cptr));
}
  • 该函数的核心就是调用了registerType 函数
  • 两个Helper模板函数分别对构造和析构函数进行封装

registerType

代码来源:src/corelib/kernel/qmetatype.cpp

int QMetaType::registerType(const char *typeName, Destructor destructor, Constructor constructor)

函数功能:

  • 根据类型名查找其MetaType类型,如果已存在,则直接返回;否则创建后返回。

  • 创建一个 !QCustomTypeInfo 对象
  • 该对象包含要类型的构造、析构信息,已经规范化后的类型名
  • 该对象存入一个全局的!QVector中

qRegisterMetaType()

看manual,可以知道,qRegisterMetaType 还有一个无参的重载函数。

template <typename T>
inline int qRegisterMetaType()
{
return qMetaTypeId(static_cast<T *>(0));
}
  • 函数看起来和带参数的那个似乎区别很大(难道不是么?)。
  • 手册中告诉我们,执行这个的时候,模板参数T必须用 Q_DECLARE_METATYPE() 声明过
  • 能猜到原因吗?注意看前面 Q_DECLARE_METATYPE() 代码,
  • 对了。类中的成员函数qt_metatype_id中包含对qRegisterMetaType(typeName)的调用
  • 这儿就是辗转调用了这个带参数的qRegisterMetaType函数 

unregisterType(const char *typeName)

函数的作用是取消自己先前注册的某个metatype类型。

前面提到注册信息在一个全局的 QVector<QCustomTypeInfo>中,当取消注册的时候是怎么样的呢?直接删除Vector中相应的项么?源码告诉我们,不是的。

实际是查找到相应的项,清空该项的内容。

for (int v = 0; v < ct->count(); ++v)
 {

 if (ct->at(v).typeName == typeName)
 {

 QCustomTypeInfo &inf = (*ct)[v];
 inf.typeName.clear();
 inf.constr = 0;
 inf.destr = 0;
 inf.alias = -1;
 }
}

 

    posted @ 2011-04-15 22:34 RTY 阅读(2818) | 评论 (0)编辑 收藏

         摘要:   阅读全文

    posted @ 2011-04-15 22:20 RTY 阅读(2831) | 评论 (0)编辑 收藏

    一、基本分类:
    qDebug : 调试信息提示
    qWarning: 一般的警告提示
    qCritical: 严重错误提示
    qFatal: 致命错误提示

    二、如何截获这些信息

    Qt提供了qInstallMsgHandler 方法用来定制消息发生后如何来处理。
    qInstallMsgHandler 是一个回调函数,主要是由qDebug、qWarnng、qCritical、qFatal这些函数进行触发,
    也就是说,qDeubg这些函数处理的消息文本会被qInstallMsgHandler 所指向的回调函数截获,这样就允许用户自己来处理这些消息文本。
    例如,你完全可以将这些消息文本输出并保存到相关的日志文件中。请看下面的示例!

    三、将qDebug()\qWarning()\qCritical()\qFatal() 信息输出到指定文件中

     1 #include <QtDebug>
     2 #include <QFile>
     3 #include <QTextStream>
     4 
     5 void customMessageHandler(QtMsgType type, const char *msg)
     6 {
     7         QString txt;
     8         switch (type) {
     9         //调试信息提示
    10         case QtDebugMsg:
    11                 txt = QString("Debug: %1").arg(msg);
    12                 break;
    13 
    14         //一般的warning提示
    15         case QtWarningMsg:
    16                 txt = QString("Warning: %1").arg(msg);
    17         break;
    18         //严重错误提示
    19         case QtCriticalMsg:
    20                 txt = QString("Critical: %1").arg(msg);
    21         break;
    22         //致命错误提示
    23         case QtFatalMsg:
    24                 txt = QString("Fatal: %1").arg(msg);
    25                 abort();
    26         }
    27 
    28         QFile outFile("debuglog.txt");
    29         outFile.open(QIODevice::WriteOnly | QIODevice::Append);
    30         QTextStream ts(&outFile);
    31         ts << txt << endl;
    32 }
    33 
    34 int main( int argc, char * argv[] )
    35 {
    36         QApplication app( argc, argv );
    37 
    38         //先注册自己的MsgHandler
    39         qInstallMsgHandler(customMessageHandler);        
    40         
    41         //以后就可以像下面这样直接打日志到文件中,而且日志也会包含时间信息
    42         qDebug("This is a debug message at thisisqt.com");
    43         qWarning("This is a warning message  at thisisqt.com");
    44         qCritical("This is a critical message  at thisisqt.com");
    45         qFatal("This is a fatal message at thisisqt.com");
    46 
    47         return app.exec();
    48 }


    四、如何取消信息处理呢?
    简单:
    还是用qInstallMsgHandler.
    只要执行qInstallMsgHandler(0) 就可以了

    posted @ 2011-04-10 14:14 RTY 阅读(9133) | 评论 (0)编辑 收藏

    http://www.webresourcesdepot.com/

    http://htmlhelp.com/zh/reference/css/

    现在开始样式表!
    仅仅改变一个文件就可以改变数百个网页的外观......个性化的表现而不损失访问者......所有这些都因为网页样式表的强大和灵活特性。
    CSS 速成
    层叠样式表的基础入门。
    CSS 结构和规则
    各种选择符、伪类、伪元素和层叠顺序的入门。
    CSS 属性
    各种层叠样式表级别一有效的属性的描述。
    将样式表加入到HTML中
    各种将样式表加入到HTML文本中的方法。
    依赖样式表
    怎样会是滥用样式表和使你的网页难以处理。
    CSS 参考
    连接到介绍CSS的规范和其它方面的文章。

     

    posted @ 2011-04-10 12:14 RTY 阅读(145) | 评论 (0)编辑 收藏

    这只是一个布局实例,学习CSS有用处,因为这个用来修饰图片的边框做的不错,主要是想了解如何用CSS实现这种布局,在相对、绝对定位,或者是在多种浏览器不失真、不变形,从事WEB前端设计的朋友有空可参考一下。


    网址:http://www.jb51.net/jiaoben/22250.html

    posted @ 2011-04-10 11:57 RTY 阅读(270) | 评论 (0)编辑 收藏

    风格类似Vista的纯CSS菜单栏,超漂亮的菜单,因使用了不少的资源文件,因此一并打包,方便你下载,效果可以看上图,黑色与蓝色调配合,大气,沉稳。





    网址:http://www.jb51.net/jiaoben/20333.html

    posted @ 2011-04-10 11:53 RTY 阅读(273) | 评论 (0)编辑 收藏

    CSS完成一个漂亮的登录框效果,而且还是仿Windows XP的样式,只不过是经典风格的XP,包含完整的资源文件,你下载后直接把相关文件拷贝就可用啦,先看看效果图在上边,是不是很美丽?


    网址:http://www.jb51.net/jiaoben/28880.html

    posted @ 2011-04-10 11:51 RTY 阅读(908) | 评论 (1)编辑 收藏

    50个css做的button弄完了,说了早上给大家下载的,中午有事情在忙,所以现在才弄完,图片和CSS已经打包好了,大家可以下载,因为时间关系,有些button没有做成可伸缩的,如果需要的话自己改一下就行了,我没时间改了,另外如果想要PSD源文档的,可以留下Email。另外声明:本站所有脚本、图片、教程、程序等等全属个人原创,转载请保留版权。


    网摘:http://www.jb51.net/jiaoben/21699.html

    posted @ 2011-04-10 11:49 RTY 阅读(801) | 评论 (0)编辑 收藏

    仅列出标题
    共31页: First 23 24 25 26 27 28 29 30 31