0

私は先週からQPlainTextEditの更新によって引き起こされた問題を抱えています。QPlainTextEditを内部に持つQMainWindowダイアログウィンドウとは別に作成しようとしています。この問題は、appendHtmlシグナル(appendTextでも試してみました)を使用しようとすると始まります。配置されたテキストは、マウスでマークしない限り表示されません。再ペイントまたは更新すると、プログラムがクラッシュするか、表示されるアクションが発生しません。

QPlainTextEditヘッダーを使用したQDialogの簡略化されたコード:

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

2つの別々のUIファイルがあります(最初はメインウィンドウ用、2番目はログウィンドウ用)。プログラム全体でログウィンドウを使用する必要があり(約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().)
4

2 に答える 2

2

コードを正しく理解している場合は、バックグラウンドスレッドからログを記録しようとしており、直接接続を使用してシグナルをGUIスレッドに渡していますか?これは機能しません。Qtがクロススレッドシグナルであることを認識し、それに応じてスレッド間で(つまり、フォアグラウンドスレッドのメッセージループを介して)シグナルを送信できるように、デフォルトの接続を介してシグナルを送信する必要があります。

Qtでは、GUIの相互作用はメイン/フォアグラウンドスレッドで発生する必要があります。そうしないと、発見したとおりに悪いことが発生します。確かにバックグラウンドスレッドからシグナルを送信してGUIの更新をトリガーすることはできますが(私は常にこれを行っています)、正しい接続を使用していることを確認する必要があります。直接接続は直接関数呼び出しになり、この場合は機能しません。

コードでは、問題はconnect()の呼び出しです。デフォルト設定を使用する必要がある場合は、信号からスロットへの接続の接続モードを明示的に指定します。接続を明示的にに設定するQt::DirectConnectionと、基になるコードは指定されたスロットへの直接呼び出しを実行します。つまり、シグナルのスレッドコンテキストでスロットを呼び出すことになります。シグナルはバックグラウンドスレッドでトリガーされるため、これは望ましくありません。

于 2013-03-05T19:11:39.657 に答える
0

任意のタイプ/クラスをシグナルとスロットに渡すことはできません。リストは限られており、すべてのQtクラスがリストに含まれているわけではありません。シグナル/スロットに渡すことができるタイプ/クラスのリストにタイプ/クラスを追加するには、そのクラスのqRegisterMetaTypeを呼び出す必要があります。次のようなシグナルに渡そうとしているクラスのコンストラクターで呼び出すことをお勧めします。

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

static intは、登録が1回だけ呼び出され、MyClassのインスタンスが使用される前に呼び出されることを保証します。

于 2013-03-05T19:18:00.827 に答える