วิธีการพิมพ์ไปยังคอนโซลเมื่อใช้ Qt


159

ฉันใช้ Qt4 และ C ++ เพื่อสร้างบางโปรแกรมในคอมพิวเตอร์กราฟิก ฉันต้องสามารถพิมพ์ตัวแปรบางอย่างในคอนโซลของฉันในเวลาทำงานไม่ใช่การดีบั๊ก แต่coutดูเหมือนจะไม่ทำงานแม้ว่าฉันจะเพิ่มห้องสมุด มีวิธีทำเช่นนี้หรือไม่?


3
คุณช่วยอธิบายเกี่ยวกับศาลไม่ทำงานเพราะมันควรจะทำงานอย่างแน่นอน คุณได้รับข้อผิดพลาดในการรวบรวม คุณสามารถแสดงตัวอย่างรหัสของ cout ที่ใช้ไม่ได้สำหรับคุณหรือไม่ อธิบายวิธีการใช้แอปพลิเคชันของคุณด้วย คุณกำลังเรียกใช้จากคอนโซลหรือจากภายใน IDE และไม่เห็นเอาต์พุตไปที่หน้าต่างเอาต์พุตหรือไม่?
Arnold Spence

เพื่อความสมบูรณ์: @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)
user202729

คำตอบ:


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 คุณสามารถลองสิ่งนี้ (ขณะที่ Kyle Strand ชี้ให้เห็น):

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

จากนั้นคุณสามารถโทรได้ดังนี้:

qStdOut() << "std out!";

1
ฉันถามในขณะที่ไม่ทำการดีบั๊กจะต้องมีฟังก์ชั่นที่อนุญาตให้ฉันเขียนข้อความในคอนโซลระหว่างรันไทม์ไม่ใช่ในระหว่างการดีบัก
lesolorzanov

11
แม้จะมีชื่อฟังก์ชันนั้นไม่เกี่ยวข้องกับการดีบักด้วยดีบักเกอร์ มันเป็นฟังก์ชั่นอำนวยความสะดวกที่ Qt จัดเตรียมสำหรับการส่งเอาต์พุตไปยัง stderr ที่สามารถลบออกจากการคอมไพล์ด้วยการกำหนด ดังนั้นจึงเป็นทางเลือกสำหรับการบรรลุผลลัพธ์ไปยังคอนโซลที่รันไทม์
Arnold Spence

ขอบคุณมากฉันใช้มัน :) ฉันเดาว่าไม่จำเป็นสำหรับฉันที่จะเขียนโค้ดที่ฉันใช้ ขอบคุณ! นี่เป็นประโยชน์อย่างมาก
lesolorzanov

51
#include <QDebug>
ducky

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
ฉันไม่รู้ว่าทำไมคำตอบไม่เป็นที่ยอมรับ แต่มันมีประโยชน์มากที่สุดอย่างแน่นอน
Semyon Danilov

4
ตกลง stderr ใช้สำหรับดีข้อผิดพลาด (และการดีบัก) นี่ควรเป็นคำตอบที่ยอมรับได้เพราะเป็นคำตอบเดียวที่ใช้ stdout และ qt
Marshall Eubanks

1
อันนี้ใช้งานได้สำหรับฉัน - และดูเหมือนว่าวิธีการที่ถูกต้องในการส่งออกข้อมูลผ่านศาล
Michael Vincent

2
หากคุณรวมข้อมูลจากคำตอบของ Goz เกี่ยวกับวิธีการพิมพ์ข้อผิดพลาด / คำเตือนพร้อมกับข้อมูลเล็กน้อย (ไม่มีคำตอบของ Goz ที่น่าเศร้า แต่มีอยู่ในความคิดเห็นด้านล่าง) เกี่ยวกับสิ่งที่qDebug()ทำจริงนี่จะเป็นคำตอบที่เหนือกว่า (IMO มันยอดเยี่ยมอยู่แล้วตั้งแต่ OP ขอให้บางสิ่งมาแทนที่std::coutแต่ผู้ลงคะแนนเสียง 40ish ดูเหมือนจะไม่เห็นด้วย)
Kyle Strand

QTextStream qStdout() { return {stdout}; }อาจเป็นวิธีที่มีประโยชน์ในการห่อสิ่งนี้ให้สอดคล้องกับqWarning()ฯลฯ และอาจมีบางstaticรัฐที่จะหลีกเลี่ยงการสตรีมชั่วคราว
Yakk - Adam Nevraumont

36

เขียนถึง stdout

หากคุณต้องการบางสิ่งที่std::coutเขียนลงในเอาต์พุตมาตรฐานของแอปพลิเคชันของคุณคุณสามารถทำสิ่งต่อไปนี้ ( credit to 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( ให้เครดิตกับ Gozและความคิดเห็นด้านล่างคำตอบของเขา):

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เปิดในเวลารวบรวม

(Goz ตั้งข้อสังเกตในความคิดเห็นว่าสำหรับแอพที่ไม่ใช่คอนโซลแอปเหล่านี้สามารถพิมพ์ไปยังสตรีมอื่นที่ไม่ใช่stderr)


หมายเหตุ:วิธีการพิมพ์ Qt ทั้งหมดถือว่าconst char*อาร์กิวเมนต์เป็นสตริงที่เข้ารหัสด้วย ISO-8859-1 พร้อม\0อักขระสิ้นสุด


1
QTextStream qStdout() { static QTextStream r{stdout}; return r; }?
Yakk - Adam Nevraumont

1
@Yakk คำแนะนำที่ดี! ฉันจะรวมเข้าไปในคำตอบของฉัน
Kyle Strand

qFatal () ได้รับข้อผิดพลาดเมื่อรวบรวมกับ QT5 อ่านโพสต์ว่ามันไม่สำคัญ (อยู่ที่นั่น / ทำงาน) อยู่ดี ... อย่าใช้มัน! :)
relascope

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); } ไม่มีการพิมพ์ผิดฉันสัญญา
Reinstate Monica

1
@Mitch Hm ตรวจสอบลิงก์เหล่านั้นและเอกสารประกอบ Qt คุณพูดถูก ฉันไม่เห็นสิ่งใดที่บ่งบอกว่ามีปัญหาที่ทราบจริงที่เกิดจากQTextStreamวัตถุชั่วคราว แก้ไข
Kyle Strand

32

เพิ่มลงในไฟล์โครงการของคุณ:

CONFIG += console

5
ไม่มีข้อมูลในคำถามเกี่ยวกับระบบการสร้างที่ถูกใช้งาน qmakeนี้มีความเกี่ยวข้องเฉพาะเมื่อใช้
Kyle Strand

19

คุณต้องการพิมพ์ตัวแปรอะไร ถ้าคุณหมายถึง QStrings สิ่งเหล่านั้นต้องถูกแปลงเป็น c-Strings ลอง:

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

8
@CoderaPurpa คุณต้องเพิ่ม#include <iostream>
Sebastian Negraszus

myString.toUtf8().data()ดีกว่าเพราะพิมพ์อักขระที่อยู่นอกช่วง ascii ตัวอย่างตัวอักษรจีน
peterchaula

8

นอกจากนี้ยังมีไวยากรณ์คล้ายกับ prinft เช่น:

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

มีประโยชน์มากเช่นกัน



3

สิ่งที่เกี่ยวกับการรวมไลบรารี iostreamและแม่นยำว่าcoutเป็นวัตถุของstdดังนี้:

#include <iostream>

std::cout << "Hello" << std::endl;

1

หากคุณกำลังพิมพ์ไปยัง stderr โดยใช้ไลบรารี stdio การเรียกร้องให้fflush(stderr)ควรล้างบัฟเฟอร์และทำให้คุณได้รับการบันทึกตามเวลาจริง



0

หลังจากศึกษาตัวอย่างหลายอย่างบนอินเทอร์เน็ตที่อธิบายถึงวิธีการส่งข้อความออกจาก GUI ใน Qt ไปยัง stdout ฉันได้ปรับปรุงตัวอย่างแบบสแตนด์อะโลนในการเปลี่ยนเส้นทางข้อความไปยังคอนโซลผ่าน qDebug () และติดตั้ง qInstallMessageHandler () คอนโซลจะแสดงพร้อมกันกับ GUI และสามารถซ่อนได้หากเห็นว่าจำเป็น รหัสนี้ง่ายต่อการรวมเข้ากับรหัสที่มีอยู่ในโครงการของคุณ นี่คือตัวอย่างเต็มรูปแบบและอย่าลังเลที่จะใช้มันในทุกทางเท่าที่คุณต้องการตราบใดที่คุณปฏิบัติตามไลเซนส์ GNU GPL v2 คุณต้องใช้รูปแบบของการเรียงลำดับและ MainWindow ฉันคิดว่า - มิฉะนั้นตัวอย่างจะทำงาน แต่อาจผิดพลาดเมื่อถูกบังคับให้ออก หมายเหตุ: ไม่มีทางที่จะออกจากปุ่มปิดหรือปิดเมนูได้เพราะฉันได้ทดสอบทางเลือกเหล่านั้นแล้วและแอปพลิเคชันจะหยุดทำงานในที่สุดทุก ๆ คราว หากไม่มีปุ่มปิดแอปพลิเคชั่นจะเสถียรและคุณสามารถปิดได้จากหน้าต่างหลัก สนุก!

#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" -> Enable

เพื่อล้างบัฟเฟอร์ใช้คำสั่งนี้ -> fflush (stdout); คุณยังสามารถใช้ "\ n" ในหรือprintfcout

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.