2013-03-05 9 views
0

지난 주부터 QPlainTextEdit의 업데이트로 인한 문제가 발생했습니다. 내부 QPlainTextEdit QMainWindow 대화 창에서 별도로 만들려고 해요. 문제는 appendHtml 신호 (appendText로 시도 함)를 사용하려고 할 때 시작됩니다. 배치 된 텍스트는 마우스로 표시하지 않는 한 보이지 않습니다. 프로그램이 충돌하거나 보이는 조치가 없으면 원인을 다시 채우거나 업데이트하십시오. QPlainTextEdit 헤더와 인 QDialog의Qt가 메인 스레드가 아닌 GUI를 강제 업데이트하는 방법

단순화 번호 : 메소드 정의

namespace Ui { 
class LogWindow; 
} 

class LogWriter: public QDialog 
{ 
Q_OBJECT 

QMutex print_lock; 

public: 

class Log{ 

    Q_OBJECT 

    const static int MAX_SIZE = 100; 
    bool to_terminal; 
    QString color; 
    QMutex *print_lock; 
    QPlainTextEdit *text_place; 
    QVector< QPair<QString,time_t> > history; 
    LogWriter * obj; 

    public: 
    bool print; 

    Log(bool _print,QString _color,LogWriter *obj_ = NULL) 
    {print = _print; color = _color; obj = obj_;} 
    void setLock(QMutex *print_lock_){print_lock = print_lock_;} 
    void setTextField(QPlainTextEdit *_text) {text_place = _text;} 
    Log& operator<<(QString &a); 
    Log& operator<<(const char* a); 
}; 

static LogWriter* getInstance() 
{ 
    static LogWriter instance; // Guaranteed to be destroyed. 
           // Instantiated on first use. 
    return &instance; 
} 
~LogWriter(); 

Log LOW,MEDIUM,HIGH; 
Ui::LogWindow *ui; 

signals: 
void signalLogAppend(QString); 
}; 

단순화 번호 :

LogWriter::LogWriter(QWidget * parent): QDialog(parent) { 

ui = new Ui::LogWindow; 
ui->setupUi(this); 

LOW.setLock(&print_lock); 
MEDIUM.setLock(&print_lock); 
HIGH.setLock(&print_lock); 

connect(this,SIGNAL(signalLogAppend(QString)),ui->plainTextEdit, 
SLOT(appendHtml(QString)),Qt::DirectConnection); 

} 

LogWriter::Log& LogWriter::Log::operator<< (QString &s){ 
history.push_front(qMakePair(s,time(NULL))); 
if(history.size() > MAX_SIZE) history.pop_back(); 

if(print){ 
    //print_lock->lock(); 

    QString text = "<font color=\""; 
    text += color + "\">"; 
    text += s + "</font>"; 
    //cout << text.toStdString() << endl; 
    //text_place->appendHtml(text); 
    //text_place->repaint(); 
    emit (obj)->signalLogAppend(text); 
    //print_lock->unlock(); 

} 
return *this; 
} 

I는 (제 로그 윈도우에 대한 제 1 주 윈도우의) 두 개의 분리 된 인터페이스 파일을 갖는다. 내 프로그램 전체에서 로그 창을 사용해야하는데 (약 10 개의 스레드),이 문제에 갇혔다. 내 질문은 - 가능하지 않은 경우 메인 스레드를 사용하지 않고 GUI를 강제로 업데이트 할 수 있습니까? 그 밖의 가능성은 무엇입니까? 가능하다면 모든 코드를 재구성하는 것을 피할 것입니다. 그렇게하려면 시간이 걸릴 것입니다. 현재 로그인은 매우 간단합니다 - 나는 필요 ONY :

LogWindow *log = LogWindow::getInstance(); 
log->MEDIUM << "something"; 

와 같은 추가 정보는 내가 QTCreator 경고를 추가 : 내가 제대로 코드를 이해한다면, 당신은 백그라운드 스레드에서 로그인을 시도하고

QObject::connect: Cannot queue arguments of type 'QTextBlock' 
    (Make sure 'QTextBlock' is registered using qRegisterMetaType().) 
    QObject::connect: Cannot queue arguments of type 'QTextCursor' 
    (Make sure 'QTextCursor' is registered using qRegisterMetaType().) 

답변

2

GUI 스레드로 신호를 전달하기 위해 직접 연결을 사용하고 있습니까? 작동하지 않을 것입니다. Qt는 기본 연결을 통해 신호를 보내야합니다. 그래서 Qt는 그것이 크로스 스레드 신호이고 그에 따라 스레드를 통해 전달합니다 (즉, 포 그라운드 스레드의 메시지 루프를 통해).

Qt에서, GUI 상호 작용은 주/전경 스레드에서 발생해야합니다. 그렇지 않으면 발견 한대로 나쁜 일이 발생합니다. 백그라운드 스레드의 신호를 보내어 GUI 업데이트를 트리거 할 수 있습니다. 항상이 작업을 수행하지만 올바른 연결을 사용하고 있는지 확인해야합니다. 직접 연결은 직접 함수 호출을하게되며이 경우에는 작동하지 않습니다.

코드에서 문제는 connect()로 전화하는 것입니다. 기본 설정을 사용해야하는 경우 신호 대 슬롯 연결에 대한 연결 모드를 명시 적으로 지정하십시오. 명시 적으로 연결을 Qt::DirectConnection으로 설정하면 기본 코드가 지정된 슬롯에 대한 직접 호출을 실행합니다. 즉, 신호의 스레드 컨텍스트에서 슬롯을 호출하게됩니다. 신호가 백그라운드 스레드에서 트리거되기 때문에이를 원하지 않습니다.

+0

예 - 백그라운드 스레드 (심지어 많은 스레드 - 연산자 <<)에서 로그하려고하는데 직접 호출을 사용하지 않습니다. (또는 어쩌면 저는 잘못되었습니다.) 신호를 사용합니다. 나는 코드를 붙였다. "기본 연결을 통해 신호 전송"- 의미는 무엇입니까? 또한이 문장의 나머지 부분은 나에게 다소 흐릿합니다. – lagoru

+1

그가 의미하는 것은 5 개의 인수로 connect (....)를 호출하는 LogWritter 클래스 연결에있다.다섯 번째 인수 인 Qt : DirectConnection을 제거합니다. 직접 연결은 동일한 스레드 연결에만 적용됩니다. 인수를 제거하고 Qt가 QueuedConnection 일 필요가 있음을 Qt가 알게하거나 그냥 직접 언급하십시오. 내가 크로스 스레드 신호 슬롯에 대한 연결에 명시하는 것이 더 좋은 것을 발견 – Viv

+0

OMG 작동합니다 .... 내가 어떻게 QT를 확인할 수있는 동안 4 일간의 검색을 놓칠 수 : : 직접 연결 경계는 ... 감사합니다 Logged 대단히 도움을! – lagoru

0

신호 및 슬롯에 임의의 유형/클래스를 전달할 수 없습니다. 목록이 제한되어 있고 모든 Qt 클래스가 목록에있는 것은 아닙니다. 신호/슬롯에 전달할 수있는 유형/클래스 목록에 유형/클래스를 추가하려면 해당 클래스에 대해 qRegisterMetaType을 호출해야합니다. 나는이 같은 신호 전달하려는 클래스의 생성자를 호출하는 것이 좋습니다 :

MyClass::MyClass() : MyParentClass() 
{ 
    static int reg = qRegisterMetaType<MyClass>("MyClass"); 
} 

정적 INT는 등록이 한 번만 MyClass에의 인스턴스 이제까지 사용되기 전에 호출됩니다 보장합니다.

관련 문제