<zt>QString, wchar_t *, TCHAR, CString和其他字符或字符串类型的转换

yanboo 发表于 2011-03-08 15:18:54

转自http://klniu.com/post/qstring-wchar_t-tchar-and-other-types-of-conversion-characters-or-strings/

这篇文章是在Blogspot上看到的一篇文章,能够解决QString, wchar_t *, TCHAR和其他字符或字符串类型之间的转换,方便在使用Windows API的时候转换的麻烦。

原文地址:http://tkrotoff.blogspot.com/2010/04/code-snippets-about-qstring-wchart.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
//QString to wchar_t *:
const wchar_t * encodedName = reinterpret_cast<const wchar_t *>(fileName.utf16());
 
//QString to char * given a file name:
QByteArray fileName = QFile::encodeName(aFileName);
const char * encodedName = fileName.constData(); //Valid as long as fileName exists
 
//QString to char * (general case):
const char * tmp = str.toUtf8().constData();
[/code]
Windows 数据类型: http://msdn.microsoft.com/en-us/library/aa383751.aspx
[code lang="cpp"]
//TCHAR:
#ifdef UNICODE
typedef wchar_t TCHAR;
#else
typedef char TCHAR;
#endif
 
//LPCTSTR:
#ifdef UNICODE
typedef LPCWSTR LPCTSTR;
#else
typedef LPCSTR LPCTSTR;
#endif
 
//LPCSTR:
typedef const char * LPCSTR;
 
//LPCWSTR:
typedef const wchar_t * LPCWSTR;
 
//LPCWSTR to QString:
QString text(QString::fromUtf16(reinterpret_cast<const unsigned short *>(tmp)));

另一种解决办法是使用QString::fromWCharArray(),但这个函数可能导致一些尚未解决的wchar_t符号问题。

最佳的编程风格: 使用L来定义wchar_t宽字符串,比如 L"text" 字义了一个UNICODE字符串"text"。

今天又看到一个文章,关于字符串之间的转换,比较全面,在此将英文翻译并整理一下。
原文地址:http://hi.baidu.com/koko200147/blog/item/7e3cad828c9b9bb66d8119cb.html

QString与其他字符类型之间的转换,QString在Qt4中是UNICODE编码的,使用utf16规范。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
QString::fromAscii ( const char * str, int size = -1 );
QString::fromLatin1 ( const char * str, int size = -1 );
QString::fromLocal8Bit ( const char * str, int size = -1 );
QString::fromRawData ( const QChar * unicode, int size );
QString::fromStdString ( const std::string & str );
QString::fromStdWString ( const std::wstring & str );
QString::fromUcs4 ( const uint * unicode, int size = -1 );
QString::fromUtf8 ( const char * str, int size = -1 );
QString::fromUtf16 ( const ushort * unicode, int size = -1 );
QString::fromWCharArray ( const wchar_t * string, int size = -1 );
 
//qstring ->std::string
QString::toStdString () ;
QString::toStdWString ();
 
//BSTR<->QString,不太了解BSTR是什么,还没用到过,所以不知道对不对
BSTR bstr_str;
QString q_str((QChar*)bstr_str, wcslen(bstr_str));
bstr_str = SysAllocString(q_str.utf16());//remember use SysFreeString on BSTR
 
//QString<->LPCSTR
QString::toLocal8Bit().constData();
QString::fromLocal8Bit ( const char * str, int size = -1 );
 
//QString<->LPCWSTR
QString::utf16();
QString::fromUtf16 ( const ushort * unicode, int size = -1 );
 
//QString<->CString
CString c_str(qstring::utf16());
QString fromUtf16 (LPCTSTR(c_str) );

CString转换为char*

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
//1.传给未分配内存的const char* (LPCTSTR)指针.
CString cstr(asdd);
const char* ch = (LPCTSTR)cstr;//ch指向的地址和cstr相同。但由于使用const保证ch不会修改,所以安全.
 
//2.传给未分配内存的指针.
CString cstr = "ASDDSD";
char *ch = cstr.GetBuffer(cstr1.GetLength() + 1);
cstr.ReleaseBuffer();
//修改ch指向的值等于修改cstr里面的值.
//PS:用完ch后,不用delete ch,因为这样会破坏cstr内部空间,容易造成程序崩溃.
 
//3.第二种用法。把CString 值赋给已分配内存的char *。
CString cstr1 = "ASDDSD";
int strLength = cstr1.GetLength() + 1;
char *pValue = new char[strLength];
strncpy(pValue, cstr1, strLength);
 
//4.第三种用法.把CString 值赋给已分配内存char[]数组.
CString cstr2 = "ASDDSD";
int strLength1 = cstr1.GetLength() + 1;
char chArray[100];
memset(chArray,0, sizeof(bool) * 100); //将数组的垃圾内容清空.
strncpy(chArray, cstr1, strLength1);
 
//5.如果上述都不行,使用以下方法
CString origCString("Hello, World!");
wchar_t* wCharString = origCString.GetBuffer(origCString.GetLength()+1);
size_t origsize = wcslen(wCharString) + 1;
size_t convertedChars = 0;
char *CharString;
CharString=new char(origsize);
wcstombs_s(&convertedChars, CharString, origsize, wCharString , _TRUNCATE);
cout << CharString << endl; //成功输出字符串"Hello,World"

从UTF8编码到GB编码的字符串转换方法:

1
2
3
4
QString Utf8_To_GB(QString strText)
{
return QString::fromUtf8(strText.toLocal8Bit().data());
}

从GB编码到UTF8编码的字符串转换方法:

1
2
3
4
QString GB_To_Utf8(char *strText)
{
return QString::fromLocal8Bit(strText);
}
标签:       订阅此文  

本文地址:http://klniu.com/post/qstring-wchar_t-tchar-and-other-types-of-conversion-characters-or-strings/

关键词(Tag): qstring

<zt>QT4学习笔记_QtScript模块

yanboo 发表于 2010-11-25 16:05:11

转自丸子·酱Qt4学习笔记(7)

 本篇说一下Qt 对于脚本的支持, 即QtScript 模块. 

    Qt 支持的脚本基于ECMAScript 脚本语言, 这个东西又是javascript, jscript 的基础. 所以, 一般只要学过javascript 就基本会写Qt 脚本了. 自此开始, Qt 脚本现在就叫javascript. 
    不过作为土人, javascript 中有一个prototype的概念, 现在才知道. javascript 本没有类的概念, 跟不用说是继承之类的了. 但是凭借prototype的特性, 我们可以实现类似C++中类, 以及类继承等一些特性. 
    prototype是个什么概念? 因为这个单词实在表意不清, 导致我花了很多时间来理解这个. 每个javascript对象都有一个指向另一个对象的引用, 这就是它的prototype. 一个对象的prototype定义了这个对象可以进行的操作集. 用C++来类比的话, 这些操作集是一定是成员函数. 看下面的javascript代码: 
function Shape(x, y) {
    this.x = x;
    this.y = y;
}
Shape.prototype.area = function() { return 0; }

function Circle(x, y, radius) {
    Shape.call(this, x, y);
    this.radius = radius;
}
Circle.prototype = new Shape;
Circle.prototype.area = function() {
    return Math.PI * this.radius * this.radius;
}
     我们把Circle对象的prototype设置成Shape对象, 实际上就是把Shape对象的prototype赋给了Circle对象, 让Circle对象的初始操作集跟Circle对象是一样的. 之后我们又重载了area()函数, 当然我们还可以加入新的函数. 它对应的C++代码如下: 
class Shape
{
public:
    Shape(double x, double y) {
        this->x = x;
        this->y = y;
    }
    virtual double area() const { return 0; }
    double x;
    double y;
};

class Circle : public Shape
{
public:
    Circle(double x, double y, double radius) : Shape(x, y)
    {
        this->radius = radius;
    }
    double area() const { return M_PI * radius * radius; }
    double radius;
};
     所以, 我们看到了, 对于一个javascript对象来说, 它还包括了一个内部的prototype对象. 对于Qt要用C++来实现类似prototype的功能的话, 除了要写一个javascript中的对应类, 还要写这个类对应的prototype类. 这个东西很高级, 也很麻烦, 所以建议看官方文档: http://doc.trolltech.com/4.3/qtscript.html#making-use-of-prototype-based-inheritance
     下面我们来说一下一般怎样从Qt的C++代码中调用Qt的script代码. 假设我们要写一个dialog, 上面有一个QPushButton, 一个QLineEdit. 点击QPushButton的时候, 会弹出一个QMessageBox来显示消息. 
    a) 直接写Qt 的C++代码的话, 只要用signal/slot 就行了:
void HelloDialog::helloClicked()
{
    QString text = textEdit->text();
    text = "Hello " + text;
    QMessageBox::information(this, "info", text); 
}
     b) 现在我们要加入javascript 的支持. 要解决的大概有这么一些问题: javascript 中怎么拿到QLineEdit 里的字符串? javascript 中怎么调用QMessage 这个Qt 的类? 我们还是先来看代码: 
QScriptValue constructQMessageBox(QScriptContext *, QScriptEngine *engine) {
    return engine->newQObject(new QMessageBox());
}

void HelloDialog::helloClicked()
{
    QString helloScript = scriptsDir.filePath("xxx.js");
    QFile file(helloScript);
    if (!file.open(QIODevice::ReadOnly)) {
        return;
    }
    QTextStream in(&file);
    in.setCodec("UTF-8");
    QString script = in.readAll();
    file.close();
    // section 1
    QScriptEngine engine;
    QScriptValue helloDialog = engine.newQObject(this);
    engine.globalObject().setProperty("helloDialog", helloDialog);
    // section 2
    QScriptValue constructor = engine.newFunction(constructQMessageBox);
    QScriptValue qsMetaObject = engine.newQMetaObject(&(QMessageBox::staticMetaObject), constructor);
    engine.globalObject().setProperty("QMessageBox", qsMetaObject);

    QScriptValue result = engine.evaluate(script);
}
     我们先把整个javascript 文件读进来, 加入一堆设置, 最后调用QScriptEngine::evaluate()函数来执行这段javascript. QScriptEngine这个类就相当于javascript 的解释器. 
    javascript 里没有类这个概念, 所有的变量都是var 类型. 如果要让Qt 的C++类在javascript 里运行, 那么先要将它包装(wrap)成一个javascript 的类型. 代码的section 1部分把this(即当前的dialog)先做了包装, 然后把包装后的对象加入到javascript 的运行环境的全局变量中. 
    接着来解决QMessageBox的问题. 由于javascript 中没有类, 继而也就是没构造函数这个概念, 但是当我们在javascript 中new 一个Qt C++对象的时候, 还是需要调用它的构造函数. 代码的section 2部分先把一个C++回调函数(只所以成为回调函数, 是因为要作为QScriptEngine::newFunction的参数, signature是固定的)包装成一个QScriptValue, 然后把它和QMessageBox 的meta-object 信息一起包装成一个QScriptValue, 最后依样画葫芦地加入到javascript 的运行环境的全局变量中. 这样我们就能在javascript 中new 出一个QMessageBox 了. 
   有一个很重要问题. 就是Qt 的meta-object 系统和javascript 的调用系统是有对应关系的. 在javascript 中, 一个var 如果是QObject 包装而来, 那么这个QObject 的所有property(Q_PROPERTY声明), signal/slot 都是可以在javascript 中调用的. 还有就是这个QObject 的所有child (指的是包含而不是继承关系), 也是可以直接访问的. 
    看一下javascript 代码. 其中greeting 和 text 都是属性:
function showMessage(parent, title, text)
{
    var messageBox = new QMessageBox;
    messageBox.windowTitle = title;
    messageBox.text = text;
    messageBox.icon = QMessageBox.Information;
    return messageBox.exec();
}

return showMessage(helloDialog, "info", helloDialog.greeting + " " + helloDialog.text);
     c) 我们实现了用javascript 来控制逻辑. GUI的话, Qt 也提供了一种可以直接读取.ui 的方法: QUiLoader::load()函数. 于是我们连GUI 也可以不用直接编译到binary 里去了. 我们要做的就是用Qt 的C++代码搭一个大概的框架, 加载需要的*.ui, *.js文件, 在适当的时候调用适当的javascript 函数就行了. 而且.ui 文件对于每个控件都会有一个objectName的属性, 用uic生成代码的话, 这个值就是变量名, 如果用QUiLoader::load()的话, 这个就被赋给了QObject 的objectName这个property. 当我们要在一个QWidget 的javascript 对象里引用它的子控件的时候, 便能直接用这个objectName 来引用. 于是*.ui 和*.js 文件可以说简直配合的天衣无缝那. 
    还是来看代码, Qt 的C++代码没什么好说的, 就看javascript 代码: 
function showMessage(parent, title, text)
{
    var messageBox = new QMessageBox;
    messageBox.windowTitle = title;
    messageBox.text = text;
    messageBox.icon = QMessageBox.Information;
    return messageBox.exec();
}

function doClick()
{
    var text = dialog.textEdit.text;
    showMessage(dialog, "info", "Hello " + text);
}

dialog.show();
dialog.helloButton.clicked.connect(doClick);
return 0;
     直接访问子控件是不是清爽多了? 呵呵. 代码见这里. 其它请参考官方文档:
        *) 
ECMAScript Reference
        *) QtScript Module


 

关键词(Tag): qt

内外网共享HpP1606DN打印机

yanboo 发表于 2010-11-24 09:35:54

  办公室新添了一台Hp P1606DN打印机,自动双面,带网络模块,用起来很不错。但这台机子有个问题,win7系统的网络用户添加它时只能使用从打印机下载的安装包。若通过IP地址直接添加,会重复打印任务直到没纸。几台win7的都是这样,xp没试,Max OS X用户却可以通过IP地址正常使用它。

  只在局域网中这没什么,用安装包就好。但我想将它映射到公网,让它在公网和内网都能用,就比较郁闷了,公网通过映射地址能连接到打印机,但一个测试页它也会永远重复打印下去。

  于是,先给打印机配公网地址,连到公网后从打印机下载该地址对应的驱动安装包。再将打印机配内网地址,连入内网后从打印机下载内网地址对应的驱动安装包。然后做地址映射,让内外网都可以访问到该打印机的IP。 使用时,先在本机上运行前面获得的驱动安装包,内网用户使用内网驱动安装包,外网用户使用外网的,然后?打啊,放心打吧 ... 不会再重复了。

转一个很棒的音标教程

yanboo 发表于 2010-11-04 11:30:35

发现一个非常棒的发音口形动画教程,分享一下。

图片
关键词(Tag): 音标

<zt>Q_DECLARE_METATYPE与qRegisterMetaType

yanboo 发表于 2010-11-01 10:29:07

原帖

基本理解

  • 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;
 }
}

    关键词(Tag): qt