2009-09-28 4 views
10

Gần đây tôi đã di chuyển dự án Qt của mình từ Linux sang Vista và bây giờ tôi đang gỡ lỗi một cách mù quáng.Ứng dụng GUI Qt: cảnh báo nếu QObject :: connect() không thành công?

Trên Linux, nếu QObject :: connect() không thành công trong bản dựng gỡ lỗi, tôi nhận được thông báo cảnh báo trên stderr. Trên Windows, không có đầu ra console cho các ứng dụng GUI, chỉ có một cuộc gọi OutputDebugString.

Tôi đã cài đặt DebugView và thiết bị này bắt đầu độc đáo qDebug() của riêng bạn, nhưng vẫn không có cảnh báo về tín hiệu không thành công.

Một giải pháp có thể là sử dụng tính năng tự động hoàn thành của QtCreator cho các tín hiệu, nhưng tôi thích Eclipse và sử dụng cả hai là PITA. Bất kỳ ý tưởng nào về cách nhận thông tin tín hiệu/thời điểm trong thời gian chạy?

Chỉnh sửa: Tôi vừa nhận ra connect() trả về bool, giải quyết vấn đề trước mắt, xấu xí vì có thể. Tuy nhiên, điều này không giải quyết được các trường hợp mà QMetaObject::connectSlotsByName() không thành công và thao tác này sẽ tự động chạy với các tiện ích con.

Trả lời

10

Gọi hàm tĩnh QErrorMessage :: qtHandler().

Theo tài liệu, điều này 'cài đặt trình xử lý tin nhắn bằng qInstallMsgHandler() và tạo QErrorMessage hiển thị các thông báo qDebug(), qWarning() và qFatal()'.

Cách khác, cài đặt trình xử lý tin nhắn với qInstallMsgHandler().

Một thay thế (được mô tả trong một bài đăng qt-lãi) là một cái gì đó như thế này:

#ifdef _DEBUG 
#define connect(connectStmt) Q_ASSERT(connect(connectStmt)) 
#endif 

... và cho những gì nó có giá trị, sau đây là một số tín hiệu và khe cắm gỡ lỗi đề nghị tôi biên soạn: http://samdutton.wordpress.com/2008/10/03/debugging-signals-and-slots-in-qt/

+1

Điều này thực sự hữu ích! – Pepe

1

Nếu bạn sử dụng Visual Studio, bạn có thể thêm bảng điều khiển vào bất kỳ ứng dụng QT nào.
Chuyển đến thuộc tính dự án, trong Linker-> Settings thay đổi "SubSystem" để nói "Console"

Bây giờ biên dịch lại mã của bạn và bạn sẽ bàn điều khiển xuất hiện khi bạn kích hoạt ứng dụng. Nếu bạn muốn loại bỏ nó, chỉ cần thay đổi Hệ thống con một lần nữa thành "Windows"

Tôi không chắc liệu điều này có thể xảy ra với QtCreator hay không.

Một tùy chọn khác là sử dụng các cuộc gọi win32 nguyên bản như AttachConsole() để tạo bảng điều khiển theo cách thủ công và đính kèm nó vào stdout và stderr. xem here để biết thêm chi tiết về điều này.

0

bạn có thể chuyển hướng stdout/stderr khá dễ dàng: tạo một lớp bắt nguồn từ std :: basic_streambuf và overloads xsputn() và overflow(), sau đó sử dụng ví dụ std :: cerr.rdbuf (instanceOfYourRedirectClass) để chuyển hướng tất cả stderr ouptut với hàm gọi lại mà bạn cung cấp.

Đây là phiên bản đơn giản của những gì tôi sử dụng; tùy theo nhu cầu của bạn, bạn có thể phải bổ sung thêm logic để fiddle với việc xử lý cuối của các nhân vật đường truyền, vv

template< class Elem = char, class Tr = std::char_traits<Elem> > 
class Redirector : public std::basic_streambuf<Elem, Tr> 
{ 
    typedef void (*pfncb) (const Elem*, std::streamsize); 

public: 
    Redirector(std::ostream& a_Stream, pfncb a_Cb) : 
    m_Stream(a_Stream), 
    m_pCbFunc(a_Cb), 
    { 
     //redirect stream 
    m_pBuf = m_Stream.rdbuf(this); 
    }; 

    ~Redirector() 
    { 
     //restore stream 
    m_Stream.rdbuf(m_pBuf); 
    } 

    std::streamsize xsputn(const Elem* _Ptr, std::streamsize _Count) 
    { 
    m_pCbFunc(_Ptr, _Count); 
    return _Count; 
    } 

    typename Tr::int_type overflow(typename Tr::int_type v) 
    { 
    Elem ch = Tr::to_char_type(v); 
    m_pCbFunc(&ch, 1); 
    return Tr::not_eof(v); 
    } 

protected: 
    std::basic_ostream<Elem, Tr>& m_Stream; 
    std::streambuf*    m_pBuf; 
    pfncb       m_pCbFunc; 
}; 

Cách sử dụng:

void outcallback(const char *ptr, std::streamsize count) 
    { 
    if(*ptr != gc_cEOL) //ignore eof 
     OutputDebugString(ptr); 
    } 

    Redirector<> redirect(std::cout, mycallback); 
+0

Điều đó cũng chuyển hướng stdout bằng printf() hay chỉ std :: cout? Tôi muốn nghi ngờ cái sau, điều này làm cho nó ít hữu ích hơn trong trường hợp này. – Macke

2

cách tiếp cận của tôi là kết nối lại các động cơ khai thác gỗ Qt với qInstallMsgHandler và ghi nhật ký của riêng tôi cả vào tệp và bảng điều khiển.

Bằng cách này, tôi biết rằng tất cả các thông báo lỗi/cảnh báo được ghi lại và tôi có thể phân tích chúng ngay cả sau khi chương trình đã ngừng thực thi.

P.S: QtCreator chặn các thư đó và hiển thị chúng trong ngăn đầu ra của ứng dụng.

+0

Cảm ơn bạn, điều này chắc chắn sẽ giúp, mặc dù tôi bắt đầu tin rằng DLL Qt chỉ đơn giản là im lặng. Tôi đã có thể thấy qDebug() đầu ra, do đó, về mặt lý thuyết, nó cũng đã xuất hiện trong DebugView. –

1

Bạn có thể sử dụng IDE Qt chính thức: QtCreator. Nó chứa một giao diện điều khiển đầu ra, nơi bạn sẽ thấy bất kỳ vấn đề với tín hiệu. Lỗi tín hiệu là đầu ra trong gỡ lỗi và phát hành chạy.

4

Giải pháp Tôi thích cho điều này là để thiết lập

QT_FATAL_WARNINGS=1 

trong môi trường của chương trình khi bạn gỡ lỗi. Điều đó làm cho chương trình sụp đổ, tạo cho bạn một backtrace tốt đẹp, đặc biệt là nếu bạn chạy mã trong một trình gỡ lỗi. Nếu bạn không muốn sự cố, hãy xem câu trả lời ở trên.

+0

Không có backtrace, đáng buồn, với MinGW: chỉ "Một ứng dụng có ... một cách khác thường" (Có thể điều này hoạt động tốt hơn với MSVC). – mlvljr

+0

Tôi thích điều này như là giải pháp (trong VS 2012 callstack được hiển thị) như redefining CONNECT không làm việc ra, đặc biệt là không nếu vấn đề ràng buộc là trong một dll khác nhau – Samuel

0

Hầu hết thời gian tôi chỉ muốn một số sự chú ý ngay bây giờ và sau đó: Chỉ cần đặt điểm ngắt trên dòng "int dummyPutBreakpointHere = 23;"

in main.C: 

static QtMessageHandler defaultMessageHandler; 
void myRazorsharpMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg) 
{ 
    if (type > QtDebugMsg) { 
     int dummyPutBreakpointHere= 23; 
    } 
    defaultMessageHandler(type, context, msg); 
} 
... 
later in main(): defaultMessageHandler= qInstallMessageHandler(0);