报告GUI或控制台(cout)进度的方法

时间:2014-04-04 11:52:00

标签: c++ qt cout

我正在移植"移植"我的CLI应用程序使用Qt的GUI。 我基本上在GUI中设置了程序的每个选项,然后按下一个运行程序主要功能的按钮。 在CLI版本中,我有一些std::cout报告控制台的进度。 我也需要在GUI中向用户报告进度,但我不确定最好的方法是什么。

我尝试了一种简单的方法,即使用this将cout重定向到QTextEdit,但它只在最后用all输出进行更新。

我可以用QText替换每个cout,但是我也想在控制台中使用进度输出在控制台中运行应用程序..,当用参数调用程序时。

所以我的问题是,是否有一种方法,设计模式,工具,允许我调用类似reportProgress("I am here");的内容,如果从GUI调用,将在QText中显示,如果从控制台调用则在控制台中输出(或参数)? 或者,我是否必须编写报告程序进度的两个版本?

4 个答案:

答案 0 :(得分:2)

我用来报告多种类型输出的方法是使用抽象"记录器"基类。然后,从Logger继承类,一个用于GUI,用于CLI或任何您想要登录的其他类。发送到日志的每个对象都只发出一个Log(const QString&),由相关类提取。

/// An interface to be implemented by loggers.
class ILogger : public QObject
{
   Q_OBJECT
public:
   ILogger(QObject* parent = {});
   Q_SLOT virtual void Log(const QString& txt) = 0;
};

ILogger::ILogger(QObject* parent) : QObject(parent) {}
/// Logs to a QPlainTextEdit
class TextBoxGUILogger : public ILogger
{
   Q_OBJECT
public:
   TextBoxGUILogger(QObject* parent = {});
   void setWidget(QPlainTextEdit*);
   void Log(const QString& txt) override;
private:
   QPointer<QTextEdit> m_txtEditBox;
};

TextBoxGUILogger::TextBoxGUILogger(QObject* parent) : ILogger(parent) {}

void TextBoxGUILogger::setWidget(QPlainTextEdit* edit) 
{
   m_txtEditBox = edit;
}

void TextBoxGUILogger::Log(const QString& txt) 
{
   if (m_txtEditBox) m_txtEditBox->append(txt);
}
/// Logs to the standard output.
class CLILogger : public ILogger
{
   Q_OBJECT
public:
   CLILogger(QObject* parent = {});
   void Log(const QString& txt) override;
};

CLILogger::CLILogger(QObject* parent) : ILogger(parent) {}

void CLILogger::Log(const QString& txt) 
{
   printf("%s", txt.toLocal8Bit().constData());
}
/// Logs to a file.
class FileLogger : public ILogger
{
   Q_OBJECT
public:
   FileLogger(QObject* parent = {});
   /// The file can be owned by another object, or it can be made a child
   /// of the logger. In either case the behavior will be correct.
   void setFile(QFile*);
   void Log(const QString& txt) override;
private:
   QPointer<QFile> m_file;
};

FileLogger::FileLogger(QObject* parent) : ILogger(parent) {}

void FileLogger::setFile(QFile* file) 
{
   m_file = file;
}

void FileLogger::Log(const QString& txt) 
{
   if (m_file)
       m_file->write(txt.toLocal8Bit().constData());
}

因此,您现在可以创建相关的记录器......

对于标准输出(CLI): -

ILogger* pLogger = new CLILogger;

QPlainTextEdit: -

ILogger* pLogger = new TextBoxGuiLogger;

最后,到一个文件: -

ILogger* pLogger = new FileLogger;

要记录的每个类都连接到记录器: -

// Qt 5 connect syntax
connect(someClass, &SomeClass::Log, pLogger, &ILogger::Log);

这允许您同时创建一个或多个日志记录对象,并且记录的对象不关心正在进行日志记录的对象,它们只是发出信号: -

emit Log("Log this text");

答案 1 :(得分:1)

QProgressBar可以满足您的需求。这是一个GUI元素,据我所知,CLI没有任何内容。

答案 2 :(得分:0)

据我所知,Qt中没有这样的内置API,但您可以在reportProgress()函数中轻松实现它。创建QApplication时,您可以在构造函数中定义其类型,具体取决于它是控制台还是GUI应用程序:

  

QApplication :: QApplication(int&amp; argc,char ** argv,Type type)

其中Type可以QApplication::TtyQApplication::GuiClient等。

在reportProgress()函数中,您可以使用QApplication::type()函数查询应用程序的类型,例如:

void reportProgress() {
    QApplication::Type t = QApplication::type();
    if (t == QApplication::Tty) {
        // console output
    } else {
        // output to text edit, etc.
    }
    [..]
}

答案 3 :(得分:0)

在Windows中,您可以通过cat简单地管理GUI程序的输出。那么你必须首先创建或安装cat,但那是微不足道的。或者,您可以将程序构建为控制台子系统,或使用GUI子系统并让程序创建控制台。

没有真正需要做更多花哨的事情,但如果这感觉很可取,那么在Windows中解除事物的一种简单而好的方法就是通过Windows邮件地址将进度事件发布到GUI。

总结:管道输出最简单,然后创建一个控制台作为下一个最简单的(单个API调用,或构建为控制台子系统),然后最复杂的,添加一个事件驱动的进度GUI。