Як надрукувати консоль при використанні Qt


159

Я використовую Qt4 і C ++ для створення деяких програм у комп'ютерній графіці. Мені потрібно мати можливість друкувати деякі змінні в моїй консолі під час виконання, не налагоджуючи, але cout, здається, не працює, навіть якщо я додаю бібліотеки. Чи є спосіб це зробити?


3
Чи можете ви детальніше сказати, що мода не працює, тому що це, безумовно, має спрацювати. Чи отримуєте ви помилку компіляції. Чи можете ви показати приклад коду cout, який не працює для вас? Також поясніть, як ви запускаєте додаток. Ви запускаєте його з консолі чи зсередини IDE і не бачите вихід у своєму вихідному вікні?
Арнольд Спенс

Просто для повноти: @ArnoldSpence - без бібліотек я отримую error: ‘cout’ was not declared in this scope; з iostream я отримую error: no match for ‘operator<<’ in ‘std::operator<< [with _Traits = std::char_traits<char>](((std::basic_ostream<char>&)(& std::cout)), ...; використання команд у відповіді замість цього працює чудово.
sdaau

Важко запропонувати рішення, коли постановка проблеми просто "не працює". Будь ласка, відредагуйте своє запитання, щоб дати більш повну характеристику того, що ви очікували, і чим це відрізняється від фактичних результатів. Див. Як запитати підказки щодо того, що дає хороше пояснення.
Toby Speight

У цьому випадку вам слід чітко вказати, що ці "змінні" є Qt-специфічними об'єктами (такими як QString).
користувач202729

Відповіді:


203

Якщо для друку досить добре stderr, ви можете використовувати такі потоки, спочатку призначені для налагодження:

#include<QDebug>

//qInfo is qt5.5+ only.
qInfo() << "C++ Style Info Message";
qInfo( "C Style Info Message" );

qDebug() << "C++ Style Debug Message";
qDebug( "C Style Debug Message" );

qWarning() << "C++ Style Warning Message";
qWarning( "C Style Warning Message" );

qCritical() << "C++ Style Critical Error Message";
qCritical( "C Style Critical Error Message" );

// qFatal does not have a C++ style method.
qFatal( "C Style Fatal Error Message" );

Хоча як зазначено в коментарях, пам’ятайте, що повідомлення qDebug видаляються, якщо QT_NO_DEBUG_OUTPUTце визначено

Якщо вам потрібен stdout, ви можете спробувати щось подібне (як зазначив Кайл Странд):

QTextStream& qStdOut()
{
    static QTextStream ts( stdout );
    return ts;
}

Потім ви можете зателефонувати наступним чином:

qStdOut() << "std out!";

1
Я запитав, не налагоджуючи, повинна бути функція, яка дозволяє мені писати повідомлення в консолі під час виконання, а не під час налагодження.
lesolorzanov

11
Незважаючи на свою назву, ця функція не пов'язана з налагодженням налагоджувачем. Це зручна функція, яку Qt забезпечує для надсилання виводу в stderr, який може бути видалений з компіляції з визначенням. Тож це альтернатива досягти виходу на консоль під час виконання.
Арнольд Спенс

Всім дякую, я цим користуюся :). Я думаю, тоді мені не потрібно писати будь-який код, який я використовував. Дякую! Це було дуже корисно.
lesolorzanov

51
#include <QDebug>
душка

62
Будь ласка, не використовуйте qDebug для всіх вихідних консолей. Використовуйте його лише для справжніх відладочних відбитків, використовуйте qWarning, qCritical і qFatal для помилок та попереджень. Оскільки оператори qDebug можуть бути видалені при компіляції з QT_NO_DEBUG_OUTPUT, щоб зберегти продуктивність і не допустити, щоб додаток захаращував вихід.
JustMaximumPower

150

Я вважаю це найкориснішим:

#include <QTextStream>

QTextStream out(stdout);
foreach(QString x, strings)
    out << x << endl;

14
Я не знаю, чому відповідь не приймається, але це найкорисніше напевно.
Семен Данилов

4
Домовились. stderr - це помилки (і налагодження). Це має бути прийнятою відповіддю, оскільки це єдиний, який використовує stdout AND qt.
Маршалл Юбанкс

1
Це працювало для мене - і здавалося, що це правильний спосіб вивести інформацію через cout
Майкл Вінсент

2
Якщо ви включите інформацію з відповіді Goz про те, як друкувати помилки / попередження, а також трохи інформації (на жаль, відсутній у відповіді Goz, але присутній у коментарях під нею) про те, що qDebug()робити насправді тощо, це буде набагато вищою відповіддю (ІМО це вже вище, оскільки ОП просить щось замінити std::cout, але 40 виборців, схоже, не згодні).
Кайл Странд

QTextStream qStdout() { return {stdout}; }може бути корисним способом вирішити це, узгоджуючись з qWarning()т. д. І, можливо, якась staticдержава уникає тимчасових потоків?
Якк - Адам Невраумон

36

Написання до stdout

Якщо ви хочете щось, що, наприклад std::cout, записується до стандартного виводу вашої програми, ви можете просто зробити наступне ( зарахуйте до CapelliC ):

QTextStream(stdout) << "string to print" << endl;

Якщо ви хочете уникнути створення тимчасового QTextStreamоб’єкта, дотримуйтесь пропозицій Yakk у коментарях нижче щодо створення функції для повернення staticручки для stdout:

inline QTextStream& qStdout()
{
    static QTextStream r{stdout};
    return r;
}

...

foreach(QString x, strings)
    qStdout() << x << endl;

Пам'ятайте , щоб flushпотік періодично , щоб забезпечити вихід на насправді друкується.

Написання до stderr

Зауважте, що вищезазначена методика може бути використана і для інших результатів. Однак є й більш читані способи написання stderr( заслуга Гоза та коментарі нижче його відповіді):

qDebug() << "Debug Message";    // CAN BE REMOVED AT COMPILE TIME!
qWarning() << "Warning Message";
qCritical() << "Critical Error Message";
qFatal("Fatal Error Message");  // WILL KILL THE PROGRAM!

qDebug()закрито, якщо QT_NO_DEBUG_OUTPUTвін увімкнено під час компіляції.

(Гоз зазначає у коментарі, що для неконсольних програм вони можуть друкувати в інший потік, ніж stderr.)


ПРИМІТКА: Усі методи друку Qt припускають, що const char*аргументи є кодованими рядками ISO-8859-1 із \0символами, що закінчуються .


1
QTextStream qStdout() { static QTextStream r{stdout}; return r; }?
Якк - Адам Невраумон

1
@Yakk Гарна пропозиція! Я включу у свою відповідь.
Кайл Странд

qFatal () отримує помилку під час компіляції з QT5. прочитайте публікацію, що це все одно не було (будьте там / працюйте) ... не використовуйте його! :)
реласкоп

1
@KyleStrand Ви не можете використовувати для цього функцію? template <typename C> constexpr typename std::remove_const<typename std::remove_reference<C>::type>::type& no_const(C* c) { return const_cast<typename std::remove_const<typename std::remove_reference<C>::type>::type&>(*c); } Використання: no_const(this).method() . Ви можете ввести цю функцію як метод у клас, і тоді вам навіть не потрібно буде передавати this: Foo& no_const() const { return ::no_const(this); } Опис, я не обіцяю.
Відновіть Моніку

1
@Mitch Hm, переглядаючи ці посилання та документацію Qt, ви праві; Я не бачу нічого, що б вказувало на те, що існує якась реальна проблема, викликана тимчасовими QTextStreamоб'єктами. Відредаговано.
Кайл Странд

32

Додайте це до файлу проекту:

CONFIG += console

5
У запитанні щодо того, яка система побудови використовується, не було відомостей. Це актуально лише під час використання qmake.
Кайл Странд

19

Які змінні ви хочете надрукувати? Якщо ви маєте на увазі QStrings, їх потрібно перетворити на c-Strings. Спробуйте:

std::cout << myString.toAscii().data();

8
@CoderaPurpa Вам потрібно додати#include <iostream>
Себастьян Неграш

myString.toUtf8().data()краще, тому що він друкує символи за межами діапазону ascii. Наприклад, китайські ієрогліфи
петершаула

8

Він також має синтаксис, схожий на prinft, наприклад:

qDebug ("message %d, says: %s",num,str); 

Дуже зручно також


8

Перейдіть до проекту Properties -> Linker-> System -> SubSystem, а потім встановіть його Console(/S).


1
Це (як відповідь Кайла Лутца) є специфічною для системи побудови.
Кайл Странд


1

Якщо ви друкуєте на stderr за допомогою бібліотеки stdio, виклик fflush(stderr)повинен промити буфер і отримати можливість реєструватися в режимі реального часу.



0

Ну, вивчивши кілька прикладів в Інтернеті, що описують, як вивести повідомлення з графічного інтерфейсу в Qt до stdout, я вдосконалив робочий окремий приклад перенаправлення повідомлень на консоль, через qDebug () та встановлення qInstallMessageHandler (). Консоль буде показана одночасно з графічним інтерфейсом і може бути прихована, якщо вважатиме за потрібне. Код легко інтегрувати з існуючим кодом у вашому проекті. Ось повний зразок і сміливо використовуйте його будь-яким способом, доки ви дотримуєтесь ліцензії GNU GPL v2. Вам потрібно використовувати якусь форму та головне вікно, я думаю - інакше зразок запуститься, але, ймовірно, вийде з ладу, коли змушений вийти. Примітка. Немає можливості вийти за допомогою кнопки закриття або закриття меню, оскільки я перевірив ці альтернативи, і програма з часом вийде з ладу. Без кнопки закриття програма буде стабільною, і ви можете закрити її з головного вікна. Насолоджуйтесь!

#include "mainwindow.h"
#include <QApplication>

//GNU GPL V2, 2015-02-07
#include <QMessageBox>
#include <windows.h>
#define CONSOLE_COLUMNS 80
#define CONSOLE_ROWS    5000
#define YOURCONSOLETITLE "Your_Console_Title"

typedef struct{

    CONSOLE_SCREEN_BUFFER_INFOEX conScreenBuffInfoEX;

    HANDLE con_screenbuf;
    HWND hwndConsole;
    HMENU consoleMenu ;
    QString consoleTitle;

    QMessageBox mBox;
    QString localMsg;
    QString errorMessage;
    WINBOOL errorCode;

} consoleT;

static consoleT *console;

BOOL WINAPI catchCTRL( DWORD ctrlMsg ){

        if( ctrlMsg == CTRL_C_EVENT ){

            HWND hwndWin = GetConsoleWindow();
               ShowWindow(hwndWin,SW_FORCEMINIMIZE);
        }

    return TRUE;
}

void removeCloseMenu(){

    int i;

    for( i = 0; i < 10; i++){

        console->hwndConsole = FindWindowW( NULL, console->consoleTitle.toStdWString().data());

        if(console->hwndConsole != NULL)
            break;
    }

    if( !(console->errorCode = 0) && (console->hwndConsole == NULL))
            console->errorMessage += QString("\nFindWindowW error: %1 \n").arg(console->errorCode);

    if( !(console->errorCode = 0) &&  !(console->consoleMenu = GetSystemMenu( console->hwndConsole, FALSE )) )
        console->errorMessage += QString("GetSystemMenu error: %1 \n").arg(console->errorCode);

    if(!(console->errorCode = DeleteMenu( console->consoleMenu, SC_CLOSE, MF_BYCOMMAND )))
           console->errorMessage += QString("DeleteMenu error: %1 \n").arg(console->errorCode);
}

void initialiseConsole(){

    console->conScreenBuffInfoEX.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX);
    console->consoleMenu = NULL;
    console->consoleTitle = YOURCONSOLETITLE;
    console->con_screenbuf = INVALID_HANDLE_VALUE;
    console->errorCode = 0;
    console->errorMessage = "";
    console->hwndConsole = NULL;
    console->localMsg = "";

    if(!(console->errorCode = FreeConsole()))
        console->errorMessage += QString("\nFreeConsole error: %1 \n").arg(console->errorCode);

    if(!(console->errorCode = AllocConsole()))
        console->errorMessage += QString("\nAllocConsole error: %1 \n").arg(console->errorCode);

    if( (console->errorCode = -1) && (INVALID_HANDLE_VALUE ==(console->con_screenbuf = CreateConsoleScreenBuffer( GENERIC_WRITE | GENERIC_READ,0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL))))
        console->errorMessage += QString("\nCreateConsoleScreenBuffer error: %1 \n").arg(console->errorCode);

    if(!(console->errorCode = SetConsoleActiveScreenBuffer(console->con_screenbuf)))
        console->errorMessage += QString("\nSetConsoleActiveScreenBuffer error: %1 \n").arg(console->errorCode);

    if(!(console->errorCode = GetConsoleScreenBufferInfoEx(console->con_screenbuf, &console->conScreenBuffInfoEX)))
        console->errorMessage += QString("\nGetConsoleScreenBufferInfoEx error: %1 \n").arg(console->errorCode);

    console->conScreenBuffInfoEX.dwSize.X = CONSOLE_COLUMNS;
    console->conScreenBuffInfoEX.dwSize.Y = CONSOLE_ROWS;

    if(!(console->errorCode = SetConsoleScreenBufferInfoEx(console->con_screenbuf, &console->conScreenBuffInfoEX)))
       console->errorMessage += QString("\nSetConsoleScreenBufferInfoEx error: %1 \n").arg(console->errorCode);

    if(!(console->errorCode = SetConsoleTitleW(console->consoleTitle.toStdWString().data())))
        console->errorMessage += QString("SetConsoleTitle error: %1 \n").arg(console->errorCode);

    SetConsoleCtrlHandler(NULL, FALSE);
    SetConsoleCtrlHandler(catchCTRL, TRUE);

    removeCloseMenu();

    if(console->errorMessage.length() > 0){
        console->mBox.setText(console->errorMessage);
        console->mBox.show();
    }

}

void messageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg){


    if((console->con_screenbuf != INVALID_HANDLE_VALUE)){

        switch (type) {

        case QtDebugMsg:
            console->localMsg = console->errorMessage + "Debug: " + msg;
            WriteConsoleW(console->con_screenbuf, console->localMsg.toStdWString().data(), console->localMsg.toStdWString().length(), NULL, NULL );
            WriteConsoleA(console->con_screenbuf, "\n--\n", 4, NULL, NULL );
            break;

        case QtWarningMsg:
            console->localMsg = console->errorMessage + "Warning: " + msg;
            WriteConsoleW(console->con_screenbuf, console->localMsg.toStdWString().data(), console->localMsg.toStdWString().length() , NULL, NULL );
            WriteConsoleA(console->con_screenbuf, "\n--\n", 4, NULL, NULL );
            break;

        case QtCriticalMsg:
            console->localMsg = console->errorMessage + "Critical: " + msg;
            WriteConsoleW(console->con_screenbuf, console->localMsg.toStdWString().data(), console->localMsg.toStdWString().length(), NULL, NULL );
            WriteConsoleA(console->con_screenbuf, "\n--\n", 4, NULL, NULL );
            break;

        case QtFatalMsg:
            console->localMsg = console->errorMessage + "Fatal: " + msg;
            WriteConsoleW(console->con_screenbuf, console->localMsg.toStdWString().data(), console->localMsg.toStdWString().length(), NULL, NULL );
            WriteConsoleA(console->con_screenbuf, "\n--\n", 4, NULL, NULL );
            abort();
        }
    }
}



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

    qInstallMessageHandler(messageHandler);

    QApplication a(argc, argv);

    console = new consoleT();
    initialiseConsole();

    qDebug() << "Hello World!";

    MainWindow w;
    w.show();

    return a.exec();
}

0

"build & run"> За замовчуванням для "Run in terminal" -> Увімкнути

для промивання буфера використовуйте цю команду -> fflush (stdout); ви також можете використовувати "\ n" в printfабо cout.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.