Jak drukować do konsoli podczas korzystania z Qt

159

Używam Qt4 i C ++ do tworzenia programów w grafice komputerowej. Muszę mieć możliwość drukowania niektórych zmiennych w konsoli w czasie wykonywania, a nie debugowania, ale coutwydaje się , że nie działają, nawet jeśli dodam biblioteki. Czy jest na to sposób?

lesolorzanov
źródło
3
Czy możesz rozwinąć temat, że cout nie działa, ponieważ to z pewnością powinno działać. Czy pojawia się błąd kompilacji. Czy możesz pokazać przykład kodu Cout, który nie działa dla Ciebie? Wyjaśnij również, w jaki sposób uruchamiasz aplikację. Czy uruchamiasz go z konsoli lub w środowisku IDE i nie widzisz danych wyjściowych w oknie wyjściowym?
Arnold Spence
Dla kompletności: @ArnoldSpence - bez bibliotek, otrzymuję error: ‘cout’ was not declared in this scope; z iostream, otrzymuję error: no match for ‘operator<<’ in ‘std::operator<< [with _Traits = std::char_traits<char>](((std::basic_ostream<char>&)(& std::cout)), ...; używanie poleceń w odpowiedzi działa dobrze.
sdaau
Trudno jest zaoferować rozwiązania, gdy stwierdzenie problemu brzmi po prostu „to nie działa”. Proszę edytować swoje pytanie dać pełniejszy opis tego, co miało się stać i jak to różni się od faktycznych rezultatów. Zobacz Jak prosić o wskazówki, co stanowi dobre wyjaśnienie.
Toby Speight
W takim przypadku powinieneś wyraźnie określić, że te "zmienne" są obiektami specyficznymi dla Qt (takimi jak QString).
user202729

Odpowiedzi:

203

Jeśli jest wystarczająco dobry do drukowania stderr, możesz użyć następujących strumieni pierwotnie przeznaczonych do debugowania:

#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" );

Chociaż, jak wskazano w komentarzach, pamiętaj, że komunikaty qDebug są usuwane, jeśli QT_NO_DEBUG_OUTPUTsą zdefiniowane

Jeśli potrzebujesz stdout, możesz spróbować czegoś takiego (jak wskazał Kyle Strand):

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

Możesz wtedy zadzwonić w następujący sposób:

qStdOut() << "std out!";
Goz
źródło
1
Zapytałem, chociaż nie debuguję, musi istnieć funkcja, która pozwoli mi pisać komunikaty w konsoli podczas działania, a nie podczas debugowania.
lesolorzanov
11
Pomimo swojej nazwy funkcja ta nie jest związana z debugowaniem za pomocą debuggera. Jest to wygodna funkcja zapewniana przez Qt do wysyłania danych wyjściowych do stderr, które można usunąć z kompilacji za pomocą funkcji define. Jest to więc alternatywa dla uzyskania danych wyjściowych na konsoli w czasie wykonywania.
Arnold Spence
Dziękuję wszystkim, używam tego :). Wydaje mi się, że nie ma wtedy potrzeby, abym pisał kod, którego użyłem. Dzięki! To było bardzo przydatne.
lesolorzanov
51
#include <QDebug>
ducky
62
Nie używaj qDebug dla wszystkich danych wyjściowych konsoli. Używaj go tylko do prawdziwych wydruków debugowania, używaj qWarning, qCritical i qFatal dla błędów i ostrzeżeń. Ponieważ instrukcje qDebug można usunąć podczas kompilacji z QT_NO_DEBUG_OUTPUT, aby zaoszczędzić wydajność i zapobiec zaśmiecaniu danych wyjściowych przez aplikację.
JustMaximumPower
150

Uważam, że to najbardziej przydatne:

#include <QTextStream>

QTextStream out(stdout);
foreach(QString x, strings)
    out << x << endl;
CapelliC
źródło
14
Nie wiem, dlaczego odpowiedź nie jest akceptowana, ale na pewno jest najbardziej przydatna.
Semyon Danilov
4
Zgoda. stderr służy do, no, błędów (i debugowania). Powinna to być akceptowana odpowiedź, ponieważ jest jedyną, która używa stdout AND qt.
Marshall Eubanks
1
Ten zadziałał dla mnie - i wydawało się, że jest to właściwy sposób na wyświetlanie informacji przez cout
Michael Vincent
2
Jeśli włączysz informacje z odpowiedzi Goza o tym, jak drukować błędy / ostrzeżenia, wraz z odrobiną informacji (niestety brakujących w odpowiedzi Goza, ale obecnych w komentarzach poniżej) o tym, co qDebug()faktycznie robią itp., Będzie to zdecydowanie lepsza odpowiedź (IMO jest już lepszy, ponieważ OP prosi o coś do zastąpienia std::cout, ale 40-letni wyborcy nie zgadzają się).
Kyle Strand
QTextStream qStdout() { return {stdout}; }może być przydatnym sposobem na zawinięcie tego, spójny z qWarning()itp. A może jakiś staticstan, aby uniknąć tymczasowego streamingu?
Yakk - Adam Nevraumont
36

Piszę do stdout

Jeśli potrzebujesz czegoś, co std::coutzapisuje na standardowe wyjście aplikacji, możesz po prostu wykonać następujące czynności ( uznanie dla CapelliC ):

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

Jeśli chcesz uniknąć tworzenia tymczasowego QTextStreamobiektu, postępuj zgodnie z sugestią Yakka w komentarzach poniżej, aby utworzyć funkcję zwracającą staticuchwyt dla stdout:

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

...

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

Pamiętaj o flushokresowym sprawdzaniu strumienia, aby upewnić się, że dane wyjściowe są faktycznie drukowane.

Piszę do stderr

Zauważ, że powyższa technika może być również używana do innych wyników. Istnieją jednak bardziej czytelne sposoby pisania stderr( uznanie dla Goza i komentarze pod jego odpowiedzią):

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()jest zamknięty, jeśli QT_NO_DEBUG_OUTPUTjest włączony w czasie kompilacji.

(Goz zauważa w komentarzu, że w przypadku aplikacji innych niż konsole mogą one drukować w innym strumieniu niż stderr).


UWAGA: Wszystkie metody drukowania Qt zakładają, że const char*argumenty są łańcuchami zakodowanymi w standardzie ISO-8859-1 ze \0znakami końcowymi .

Kyle Strand
źródło
1
QTextStream qStdout() { static QTextStream r{stdout}; return r; }?
Yakk - Adam Nevraumont
1
@Yakk Dobra sugestia! Włączę do mojej odpowiedzi.
Kyle Strand
qFatal () otrzymuje błąd podczas kompilacji z QT5. przeczytałem post, który i tak nie był przeznaczony (być tam / pracować) ... nie używaj go! :)
relascope
1
@KyleStrand Nie możesz użyć do tego funkcji? 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); } Zastosowanie: no_const(this).method() . Mógłbyś wstrzyknąć tę funkcję jako metodę do klasy, a wtedy nawet nie musiałbyś zdawać this: Foo& no_const() const { return ::no_const(this); } żadnych literówek, obiecuję.
Przywróć Monikę
1
@Mitch Hm, przeglądając te linki i dokumentację Qt, masz rację; Nie widzę nic, co mogłoby wskazywać, że istnieje jakiś znany problem spowodowany przez QTextStreamobiekty tymczasowe . Edytowano.
Kyle Strand
32

Dodaj to do pliku projektu:

CONFIG += console
Kyle Lutz
źródło
5
W pytaniu nie podano informacji o używanym systemie kompilacji. Ma to znaczenie tylko podczas używania qmake.
Kyle Strand
19

Jakie zmienne chcesz wydrukować? Jeśli masz na myśli QStrings, należy je przekonwertować na c-Strings. Próbować:

std::cout << myString.toAscii().data();
Sebastian Negraszus
źródło
8
@CoderaPurpa Musisz dodać#include <iostream>
Sebastian Negraszus
myString.toUtf8().data()jest lepsze, ponieważ drukuje znaki poza zakresem ascii. Na przykład chińskie znaki
peterchaula
8

Ma również składnię podobną do prinft, np .:

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

Bardzo poręczny

ulitosCoder
źródło
8

Przejdź do projektu Properties -> Linker-> System -> SubSystem, a następnie ustaw go na Console(/S).

Son Vu
źródło
1
To (podobnie jak odpowiedź Kyle'a Lutza) jest specyficzne dla systemu kompilacji.
Kyle Strand
3

A co z włączeniem biblioteki iostream i sprecyzowaniem, że cout jest obiektem standardowym :

#include <iostream>

std::cout << "Hello" << std::endl;
Emerald Cottet
źródło
1

Jeśli drukujesz na stderr przy użyciu biblioteki stdio, wywołanie fflush(stderr)powinno opróżnić bufor i zapewnić rejestrowanie w czasie rzeczywistym.

Andrew Prock
źródło
1
#include <QTextStream>
...
qDebug()<<"Bla bla bla";
Amir Touitou
źródło
0

Cóż, po przestudiowaniu kilku przykładów w Internecie opisujących, jak wyprowadzać komunikaty z GUI w Qt na stdout, udoskonaliłem działający samodzielny przykład przekierowywania wiadomości do konsoli za pomocą qDebug () i instalowania qInstallMessageHandler (). Konsola zostanie wyświetlona w tym samym czasie co GUI i można ją ukryć, jeśli uzna to za konieczne. Kod można łatwo zintegrować z istniejącym kodem w projekcie. Oto pełna próbka i możesz z niej korzystać w dowolny sposób, pod warunkiem przestrzegania Licencji GNU GPL v2. Musisz użyć jakiejś formy i myślę, że MainWindow - w przeciwnym razie próbka będzie działać, ale prawdopodobnie ulegnie awarii, gdy zostanie zmuszony do zakończenia. Uwaga: nie ma sposobu, aby wyjść za pomocą przycisku zamykania lub zamykania menu, ponieważ przetestowałem te alternatywy i aplikacja w końcu ulegnie awarii od czasu do czasu. Bez przycisku zamykania aplikacja będzie stabilna i można ją zamknąć z poziomu głównego okna. Cieszyć się!

#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();
}
user2178077
źródło
0

„build & run”> Domyślnie dla „Run in terminal” -> Enable

aby opróżnić bufor użyj tego polecenia -> fflush (stdout); możesz także użyć "\ n" w printflub cout.

r.shams
źródło