请让我先说我像瘟疫一样避免使用 Python。
你有没有在没有任何 Python 的情况下在 C++ 土地上工作?我问是因为:
std::string API::loadUsername() {
Future<QString> future = _core->loadUserAsync();
return future.result().toStdString();
}
不可能工作。
是的,我之前发表了评论。因为 Qt 是一个应用程序框架,所以不能“洒上一点 Qt”。它也是一个深受单线程影响的应用程序框架,因为在主事件循环之外几乎没有进行任何测试。他们还会抱怨运行多个事件循环是一种反模式。(这是应用现实,但这是一个不同的论点。)
QFuture 的全部意义在于使用线程池中的线程,并在该函数/任务成功或悲惨地结束时发出信号。
如果您的 return 语句实际上返回了您想要的值,那么您根本不需要 QFuture,因为您发生了阻塞 I/O。
顺便说一句,这个:
API::API() {
if (!QCoreApplication::instance()) {
int argc = 1;
char* argv[] = {"api"};
_qt = std::make_shared<QCoreApplication>(argc, argv);
}
}
考虑到所有当时古老的 x86 和较低处理器的知识,关于第一个参数是可执行文件的完整路径,这是令人难以置信的危险。在QCoreApplication中设置了一些东西,比如 applicationFilePath() 有点依赖它。
这是我在彩票跟踪器应用程序中使用 QFuture 的一些帖子,因为数据库 I/O 可能很长。
https://www.logikalsolutions.com/wordpress/information-technology/how-far-weve-come-pt-12/
https://www.logikalsolutions.com/wordpress/information-technology/how-far-weve- come-pt-13/
https://www.logikalsolutions.com/wordpress/information-technology/how-far-weve-come-pt-14/
https://www.logikalsolutions.com/wordpress/information-technology/how-far-weve-come-pt-16/
第 16 部分有我将在下面粘贴的代码,但您需要阅读第 12、13 和 14 部分才能理解目标。
void DataBaseIO::top12Report()
{
QFuture future = QtConcurrent::run(this, &DataBaseIO::detachedTop12);
}
void DataBaseIO::detachedTop12()
{
QString msgTxt;
QTextStream rpt(&msgTxt);
QSqlQuery q(db);
rpt << "Number hit_count" << endl
<< "--------- ---------" << endl;
rpt.setFieldWidth(9);
rpt.setFieldAlignment(QTextStream::AlignRight);
q.exec("select elm_no, count(*) as hit_count from drawings group by elm_no order by hit_count desc limit 12;");
while (q.next())
{
QSqlRecord rec = q.record();
int no = rec.field("elm_no").value().toInt();
int hits = rec.field("hit_count").value().toInt();
rpt << no << hits << endl;
}
rpt.flush();
emit displayReport( "Top 12 Report", msgTxt);
}
使用 QFuture 最简单的方法是通过 run()。不需要观察者。在你的任务结束时发出一个信号。诚然,您无法知道这是否会失败,因为您没有观察者。
顺便说一句,您的计时器来自 QFutureWatcher,因为它有一个 timerEvent()。
https://doc.qt.io/qt-5/qfuturewatcher-members.html
一旦你只在 C++ 中工作,你需要阅读 C++ 信号和 Python。
https://www.tutorialspoint.com/pyqt5/pyqt5_signals_and_slots.htm
https://www.mfitzp.com/tutorials/pyqt-signals-slots-events/
没有办法绕过应用程序必须有这样的东西。
import sys
from PyQt5.QtWidgets import QApplication
app = QApplication(sys.argv)
app.exec()
语法可能并不完美,因为我避免使用 Python。
你不能只扔一点 Qt。谁使用你正在开发的东西,谁就必须使用整个框架。
Qt 有一个有限的子集不需要主事件循环。我找不到东西的清单。该项目可能不再发布它。现实情况是,如果没有主事件循环,您将无能为力。当您发出信号时,它必须有一个事件循环,以便它可以放在事件队列中(假设它不直接连接)。在 C++ 中,emit 在很多时候实际上是一个直接的函数调用。我不知道 Python 的世界。我认为它必须是一个排队事件。
根据经验,如果您使用任何具有信号的类,则必须运行一个主事件循环。如果您允许 Python 加入,那么 Python 必须启动主事件循环。如果没有,它就无法与 Qt 通信。
这是一个关于如何从 Python 使用 C/C++ 的非常详细的教程。
https://realpython.com/python-bindings-overview/
底线是,除非你在 Qt 上全力以赴,否则你无法做你想做的事。
很可能您可以使用纯 C++ 执行您尝试执行的操作,具体取决于您将 loadUserAsync() 重写为无任何 Qt 的直接 I/O 阻塞函数的能力。