2013-03-05 2 views
0

Я нахожусь на этой неделе с проблемой, вызванной обновлением QPlainTextEdit. Я пытаюсь создать отдельно от окна QMainWindow Dialog с QPlainTextEdit внутри. Проблема начинается, когда я пытаюсь использовать сигнал appendHtml (также пытался с appendText), текст, который помещен, не отображается, если не отмечен мышью. Перекрашивание или обновление причины сбоя программы или отсутствие видимого действия.Как заставить Qt обновлять GUI из не основной темы

Упрощенный код QDialog с заголовком QPlainTextEdit:

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; 
} 

У меня есть два отдельных файлов UI (первый для главного окна, второй для окна журнала). Я должен использовать окно журнала по всей моей программе (около 10 потоков), и я решил эту проблему. Мой вопрос: возможно ли принудительное обновление GUI без использования основного потока, а если нет - какие еще возможности у меня есть. Если возможно, я предпочел бы не восстанавливать весь мой код - мне понадобилось бы некоторое время, чтобы это сделать. Сейчас вход супер просто - я оны нужно:

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 любое взаимодействие с GUI должно происходить в потоке Main/foreground, иначе плохие вещи происходят, как вы обнаружили. Вы можете, конечно, отправить сигнал из фонового потока, чтобы вызвать обновление GUI - я делаю это все время - но вам нужно убедиться, что вы используете для этого правильное соединение. Прямое соединение приводит к вызову прямой функции и не будет работать для вас в этом случае.

В вашем коде проблема заключается в вызове connect() - вы явно указываете режим соединения для соединения с сигналом на слот, когда вам нужно просто использовать настройку по умолчанию. Если вы установите явно на Qt::DirectConnection, базовый код выполнит прямой вызов указанного слота, а это значит, что вы в конечном итоге вызываете слот в контексте потока сигнала. Вы не хотите этого, потому что сигнал запускается в фоновом потоке.

+0

Да, я пытаюсь войти в фоновый поток (даже много потоков - с помощью оператора <<), но я не использую прямой вызов (или, может быть, я ошибаюсь), я использую сигнал для этого - так же, как в коде я прилагается. «Отправить сигнал через соединение по умолчанию» - что это значит? Кроме того, остальная часть этого предложения довольно размыта для меня. – lagoru

+1

Что он имеет в виду в вашем соединении класса LogWritter, которое вы вызываете connect (....) с 5 аргументами. Удалите 5-й аргумент Qt: DirectConnection.Прямые соединения предназначены только для одних и тех же потоков. Либо удалите аргумент, и пусть Qt выяснит, что он должен быть Qt: QueuedConnection или просто упоминать его самостоятельно. Я считаю, что лучше быть явным в соединениях для сквозного сигнала-слота – Viv

+0

OMG, он работает .... как я мог пропустить это, четыре дня поиска, в то время как я мог просто проверить, какие границы QT :: directconnection ... Спасибо очень за помощь !!! – lagoru

0

Вы не можете передавать произвольные типы/классы в сигналы и слоты. Список ограничен, и не все классы Qt находятся в списке. Чтобы добавить типы/классы в список тех, которые могут быть переданы в сигнал/слот, вы должны вызвать qRegisterMetaType для этого класса. Я рекомендую называть его в конструктор класса, который вы пытаетесь передать в сигнал, как это:

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

Статическая ИНТ обеспечивает регистрацию только вызывается один раз и перед любой экземпляр MyClass когда-либо могут быть использованы.

Смежные вопросы