Windows控制台和Qt Unicode文本

问题描述:

我花了整整一天的时间试图弄清楚这一点,但没有运气。我看了世界各地,但没有运行代码的运气。Windows控制台和Qt Unicode文本

操作系统:Win XP Sp2 IDE &框架:C++,Qt Creator 2.0。

我想输出一些unicode(UTF-8)文本到Windows控制台,但我看到的是乱码而不是unicode字符。我知道赢得控制台确实支持unicode(自win 2000以来)......至少根据*和许多网络,但我不知道如何使它与Qt合作。我见过的大多数“解决方案”(没有看到很多)使用C++和WInAPI技术......这是我无法使用的,因为这不是Qt方式。我正在使用QStrings和Qt!

代码如下。我拿出了所有不同的东西,我试图保持代码简单的帖子。希望有人能够获得代码的工作。

#include <QtCore/QCoreApplication> 
#include <QString> 
#include <QTextStream>   
#include <QDate> 
#include <QFile> 
using namespace std; 

int main(int argc, char *argv[]) 
{ 
    QCoreApplication app(argc, argv); 

    QTextStream qin(stdin);   
    QTextStream qout(stdout);  

    //The last 2 chars in QString each need a double slash for an accent. 
    QString szqLine = QString::fromUtf8("abc áéüóöú őű"); 

    //I want this text console output to be in red text color. 
    qout << "Bellow are some unicode characters: " << endl; 

    //The Win XP console does not display the unicode chars correctly!! 
    //The cosole does not display unicode chars even though it is capable 
    //according to wikipedia. I just don't know how with Qt. 
    //I want this text output in white(or default font color, not red.) 
    qout << szqLine << endl; 

    //Would be nice to get some unicode input from console too. 
    qout << "Write some unicode chars like above: " << endl; 
    QString szqInput; 
    szqInput = QString::fromUtf8(qin.readLine()); 
    qout << "You wrote: " << endl; 
    qout << szqInput << endl; 



    return app.exec(); 
} 
+2

Unicode只在设置合适的字体时才起作用,通常它不起作用,因为它默认为ANSI页面。看到相似的尝试相关的问题:http://*.com/questions/2849010/output-unicode-to-console-using-c – 2011-01-22 05:20:24

+0

...显然,你可以设置的东西,如在QT的控制台编码...尝试在这方面我能做什么,但所有的尝试都失败了。希望有人知道如何使用QT/unicode/console。 – user440297 2011-01-22 05:33:51

+2

我认为您需要使用您找到的非Qt解决方案创建自定义QIODevice(或QTextStream)子类。 (注意它是Qt,而不是QT,它是Apple QuickTime。) – 2011-01-22 06:15:11

好的,我用这段代码做了一些测试。不需要特别的控制台设置。

#include <QTextStream> 

#ifdef Q_OS_WIN32 
#include <windows.h> 
#include <iostream> 
#else 
#include <locale.h> 
#endif 

class ConsoleTextStream: public QTextStream { 
    public: 
    ConsoleTextStream(); 
    ConsoleTextStream& operator<<(const QString &string); 
}; 

ConsoleTextStream::ConsoleTextStream(): 
    QTextStream(stdout, QIODevice::WriteOnly) 
{ 
} 

ConsoleTextStream& ConsoleTextStream::operator<<(const QString &string) 
{ 
#ifdef Q_OS_WIN32 
    WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), 
     string.utf16(), string.size(), NULL, NULL); 
#else 
    QTextStream::operator<<(string); 
#endif 
    return *this; 
} 

class ConsoleInput: public QTextStream { 
public: 
    ConsoleInput(); 
    QString readLine(); 
}; 

ConsoleInput::ConsoleInput(): 
    QTextStream(stdin, QIODevice::ReadOnly) 
{ 
} 

QString ConsoleInput::readLine() 
{ 
#ifdef Q_OS_WIN32 
    const int bufsize = 512; 
    wchar_t buf[bufsize]; 
    DWORD read; 
    QString res; 
    do { 
    ReadConsoleW(GetStdHandle(STD_INPUT_HANDLE), 
     buf, bufsize, &read, NULL); 
    res += QString::fromWCharArray(buf, read); 
    } while (read > 0 && res[res.length() - 1] != '\n'); 
    // could just do res.truncate(res.length() - 2), but better be safe 
    while (res.length() > 0 
     && (res[res.length() - 1] == '\r' || res[res.length() - 1] == '\n')) 
    res.truncate(res.length() - 1); 
    return res; 
#else 
    return QTextStream::readLine(); 
#endif 
} 

int main() 
{ 
#ifndef Q_OS_WIN32 
    setlocale(LC_ALL, ""); 
#endif 
    ConsoleTextStream qout; 
    qout << QString::fromUtf8("Текст на иврите: לחם גרוזיני מסורתי הנאפה בתנור לבנים\n"); 
    qout << QString::fromUtf8("Текст на японском: ※当サイト内コンテンツ・画像・写真データの、転載・転用・加工・無断複製は禁止いたします。\n"); 
    qout << QString::fromUtf8("Текст на европейском: áéüóöú őű\n"); 
    qout << flush; // needed on Linux 
    ConsoleInput qin; 
    QString s = qin.readLine(); 
    qout << s << endl; 
    s = qin.readLine(); // one more time, to ensure we read everything ok 
    qout << s << endl; 
    return 0; 
} 

在Windows上,它打印除俄罗斯和欧洲以外的所有文本的方框。看起来Lucida Console不支持希伯来文和日文。有趣的是,当我将文本从控制台复制到剪贴板,然后粘贴到支持Unicode的地方(例如在浏览器中)时,它确实显示正确。这证明Windows实际上输出Unicode,只是不显示它。一些控制台字体需要全面的Unicode支持。

注意,在上面的例子中我已重写只有一个operator<<(),但我需要的所有覆盖他们,如果我想使用它们,因为它们返回QTextStream&但不是虚拟的,因此,有必要使他们所有返回ConsoleTextStream&,否则类似qout << 1 << someUnicodeString的东西将无法正常工作。

我也在Linux上用UTF-8语言环境测试了这个例子,工作完美。

带有ReadConsoleW()的控制台输入工作原理是因为控制台默认配置为所谓的线路输入模式,因此它会一直等到用户点击Enter键但不会等到有足够的字符可用于填充缓冲区时,完全符合我们的要求:只要缓冲区大小足够,就可以读取一行。

我想这是因为你的代码需要使用WriteConsoleW代替WriteFile内部,并且运行时库可能无法使用该功能。如果它不使用WriteFileW,那么你不能写Unicode。

你在两个阶段都出错 - 输入和输出。

输入

你不能写
QString szqLine = QString::fromUtf8("abc áéüóöú őű");
,希望能有一个有效的Unicode字符串作为结果,因为这不是由C++标准保证的(看到这么质疑C++ source in unicode详情)。

你可以检查你没有使用代码的一个有效Unicode字符串这样

foreach(QChar ch, szqLine) { 
    qout << ch.unicode(); 
} 

如果szqLine是一个有效的Unicode字符串,你会得到的字符串中的字符的Unicode代码点的列表。如果你的字符串没有输出。

正确的方式做到这一点是这样的

QChar const chars[] = { 'a', 'b', 'c', ' ', 255, 233, 252, 243, 246, 250, ' ', 337, 369}; 
QString s(&chars[0], sizeof(chars)/sizeof(QChar)); 

QString::QString (const QChar * unicode, int size)QChar::QChar (int code) Qt的功能和Full UTF-8 Character Map您的字符的Unicode码点。

输出

Windows控制台使用输入一个特定的代码页,另一个用于输出(见Console Code Pages)当您使用标准输入/输出机制。这限制了您可以输入并在当前代码页中显示的字符集。但是,您可以使用WriteConsole Win API函数输出以UTF-16编码的任何Unicode字符串。您无法避免使用Win API函数,因为这里没有可用的Qt API。以下是显示如何在Windows控制台上显示问题中字符的完整示例。

#include <QtCore/QCoreApplication> 
#include <QString> 
#include <QTextCodec> 

#include <Windows.h> 

using namespace std; 

int main(int argc, char *argv[]) 
{ 
    QCoreApplication app(argc, argv); 

    QChar const chars[] = { 'a', 'b', 'c', ' ', 255, 233, 252, 243, 246, 250, ' ', 337, 369};     
    QString s(&chars[0], sizeof(chars)/sizeof(QChar)); 

    WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), s.utf16().constData(), s.size(), NULL, NULL); 

    return app.exec(); 
} 

今天我得到了更远一点的代码波纹管。现在,它向控制台正确显示unicode,但仍然不能正常工作,因为控制台在第一个unicode文本输出到控制台之后死机或崩溃,并且在控制台上没有任何后续显示。就好像unicode字符会导致控制台缓冲区在第一个文本输出后感到困惑。

#include <QtCore/QCoreApplication> 
#include <QString> 
#include <QTextStream> 
using namespace std; 

int main(int argc, char *argv[]) 
{ 
    QCoreApplication app(argc, argv); 

    QTextStream qin(stdin); 
    qin.setCodec("UTF-8"); 
    qin.autoDetectUnicode(); 

    QTextStream qout(stdout); 
    qout.setCodec("UTF-8"); 
    qout.autoDetectUnicode(); 

    //The last 2 chars in QString each need a double slash for an accent. 
    QString szqLine = QString::fromUtf8("abc áéüóöú őű"); 

    qout << "Bellow are some unicode characters: " << endl; 

    //Now this is displayed correctly on cosole but after displaying text 
    //it no loger is capable of displaying anything subsequently. 
    qout << szqLine << endl; 

    //Would be nice to get some unicode input from console too. 
    qout << "Write some unicode chars like above: " << endl; 
    QString szqInput; 
    szqInput = qin.readLine(); 
    qout << "You wrote: " << endl; 
    qout << szqInput << endl; 

    return app.exec(); 
}