在我的应用程序中,我有一个实例QTimer,其timeout()信号连接到主窗口对象中的一个插槽,导致它定期被调用.插槽用相机拍照并将其保存到磁盘.
我想知道QTimer当接收器(主线程上的窗口对象)当前正忙时(如同拍摄并保存前一张图片),如果发出信号(来自执行的单独线程,我推测)会发生什么.在前一个呼叫终止后,呼叫是否排队并执行?整个想法是让它定期运行,但这些调用可以排队,然后当控制返回到事件循环时随机调用,导致混乱吗?我怎么能避免呢?从理论上讲,插槽应该快速执行,但是假设硬件有一些问题并且存在停顿.
我希望在这种情况下调用被丢弃而不是排队,更有用的是能够在发生时作出反应(警告用户,终止执行).
我有一个class(MyClass)从Qt内置对象(QGraphicsTextItem)继承其大部分功能.QGraphicsTextItem从中间接继承QObject.MyClass还实现了一个接口MyInterface.
class MyClass : public QGraphicsTextItem, public MyInterface
Run Code Online (Sandbox Code Playgroud)
我需要能够使用connect和disconnect开启MyInterface*.但现在看来,connect并disconnect只在工作QObject*实例.由于Qt不支持从QObject的派生类多继承,我不能得到MyInterface从QObject.(无论如何,这对于界面也没有多大意义.)
有一个问题的讨论在网上,但IMO所提出的解决方案是在通常情况下(访问通过其接口的对象)相当无用的,因为你无法连接的信号和槽MyInterface*,但必须将它转换为派生类型.由于MyClass是许多MyInterface衍生类中的一个,这将需要"代码 - 臭"如果 - 这个 - 演绎 - 否则 - 如果 - 那个 - 演绎到那个语句并且破坏了接口的目的.
这个限制有一个很好的解决方案吗?
更新:我注意到,如果我dynamic_cast一MyInterface*到QObject*(因为我知道所有MyInterface的派生类也最终从继承QObject,它似乎工作即:
MyInterface *my_interface_instance = GetInstance();
connect(dynamic_cast<QObject*>(my_interface_instance), …Run Code Online (Sandbox Code Playgroud) 我的Qt程序很难将按钮信号连接到我的插槽.我的代码是:
Main.cpp的
#include <QtGui/QApplication>
#include "MainWidget.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainWidget mainWidget;
mainWidget.show();
return app.exec();
}
Run Code Online (Sandbox Code Playgroud)
MainWidget.h
#ifndef MAINWIDGET_H
#define MAINWIDGET_H
#include <QWidget>
class MainWidget : public QWidget
{
public:
MainWidget();
public slots:
void bAdvice_clicked();
void bWeather_clicked();
void bNextMeeting_clicked();
void bQuit_clicked();
};
#endif // MAINWIDGET_H
Run Code Online (Sandbox Code Playgroud)
MainWidget.cpp
#include "MainWidget.h"
#include <QMessageBox>
#include <QPushButton>
#include <QTextEdit>
#include <QVBoxLayout>
MainWidget::MainWidget()
{
QLayout *layout = new QVBoxLayout();
this->setLayout(layout);
QTextEdit *message = new QTextEdit();
layout->addWidget(message);
QPushButton *bAdvice = new QPushButton("Advice"); …Run Code Online (Sandbox Code Playgroud) 我想我在这里遇到了一种钻石继承问题.
Qt提供了几个旋转框,用于整数值,用于双精度以及日期/时间.它们都来自QAbstractSpinBox:
#include <QtWidgets/QSpinBox>
class QSpinBox:
public QAbstractSpinBox {
};
#include <QtWidgets/QDoubleSpinBox>
class QDoubleSpinBox:
public QAbstractSpinBox {
};
Run Code Online (Sandbox Code Playgroud)
现在我想添加一些通用于所有旋转框的功能,在这个具体的例子中,一个按钮将旋转框恢复到最小(因此是specialValueText).所以我也从中衍生出来QAbstractSpinBox并想出了这样的东西:
class AbstractRevertibleSpinBox:
public QAbstractSpinBox {
public:
RevertibleSpinBox() {
/* Use abstract base: */
QAction *revertAction = new QAction(this);
QAbstractSpinBox::lineEdit()->addAction(
revertAction, QLineEdit::TrailingAction);
/* ... */
}
public slots:
virtual void revert() = 0;
}
Run Code Online (Sandbox Code Playgroud)
这revert()包含应该实现如何恢复不同旋转框的纯净.例如,setValue(double)用于QDoubleSpinBox或setDate(QDate)用于QDateEdit.然后我以明显的方式为我需要的所有旋转框派生了相应的类,如下所示:
class RevertibleSpinBox:
public QSpinBox,
public AbstractRevertibleSpinBox {
protected:
void revert() {
/* Revert …Run Code Online (Sandbox Code Playgroud) Qt文档说,信号的返回值是不可能的:
信号由moc自动生成,不得在.cpp文件中实现.他们永远不会有返回类型(即使用void).
相关的SO问题:
但是,根据我的试验(Qt 4.8.1),我可以告诉返回值确实有效:
Qt::AutoConnectionQt::BlockingQueuedConnection所以在我的代码中我通过调用信号
QString dp = emit WscAircrafts::signalAircraftsJsonArray();
Run Code Online (Sandbox Code Playgroud)
并且信号moc返回a QString,
QString _t0;
void *_a[] = { const_cast<void*>(reinterpret_cast<const void*>(&_t0)) };
QMetaObject::activate(this, &staticMetaObject, 0, _a);
return _t0;
Run Code Online (Sandbox Code Playgroud)
这里是它传回的插槽moc QString
case 4: { QString _r = _t->slotAircraftJsonArray();
if (_a[0]) *reinterpret_cast< QString*>(_a[0]) = _r; } break;
Run Code Online (Sandbox Code Playgroud)
所有这一切似乎都很直接,为什么这与文档的矛盾呢?使用返回值的问题在哪里?如上所述,在我的代码中,这似乎有效.
Qt中的信号/槽机制是一种静态机制.这些类必须由moc编译器预处理.
现在我想在运行时动态创建信号和插槽.
我已经有了一个可行的解决方案,但我觉得我觉得它像黑客,虽然我使用的是公开的方法.
这是动态插槽的代码:
bool DynamicQObject::connectDynamicSlot(const QString &objectName, QObject *pSourceObject, QMetaMethod signalMethod)
{
QByteArray slotName = signalMethod.name().prepend("on").append("(");
QStringList parameters;
for (int i = 0, j = signalMethod.parameterCount(); i < j; ++i)
{
parameters << QMetaType::typeName(signalMethod.parameterType(i));
}
slotName.append(parameters.join(",")).append(")");
QByteArray theSignal = QMetaObject::normalizedSignature(signalMethod.methodSignature().constData());
QByteArray theSlot = QMetaObject::normalizedSignature(slotName);
if (!QMetaObject::checkConnectArgs(theSignal, theSlot))
{
return false;
}
int signalId = pSourceObject->metaObject()->indexOfSignal(theSignal);
if (signalId < 0)
{
return false;
}
int slotId = slotIndices.value(theSlot, -1);
if (slotId < 0)
{
slotId = slotList.size();
slotIndices[theSlot] = slotId; …Run Code Online (Sandbox Code Playgroud) 我最近需要向类添加一个信号,所以我将类更改为继承自QObject并将Q_OBJECT宏添加到类定义中.由于这样做,我在下面的类别行中得到"vtable for CLICommand'的信号未定义引用错误"错误:
// File clicommand.h
#include <QString>
#include <QStringList>
#include <QTcpSocket>
#include "telnetthread.h"
class CLICommand : public QObject
{
Q_OBJECT
public:
CLICommand(TelnetThread *parentTelnetThread);
signals:
void signal_shutdown_request();
private:
TelnetThread *m_parentTelnetThread;
Run Code Online (Sandbox Code Playgroud)
以及第二个错误"在'vtable for CLICommand''的信号未定义的引用错误"在下面的行上(初始化成员变量):
// File clicommand.cpp
#include <QDebug>
#include <QTcpSocket>
#include <QTextStream>
#include "version.h"
#include "clicommand.h"
#include "telnetthread.h"
#include "logger.h"
CLICommand::CLICommand(TelnetThread *parentTelnetThread)
: m_parentTelnetThread(parentTelnetThread)
{
}
Run Code Online (Sandbox Code Playgroud)
就在这里我发出信号的地方.emit行生成对`CLICommand :: signal_shutdown_request()'的错误未定义引用:
// file shutdown_clicommand.cpp
#include <QIODevice>
#include "clicommand.h"
#include "logger.h"
#include "version.h"
void CLICommand::execute_shutdown(const …Run Code Online (Sandbox Code Playgroud) 我想将Python解释器3.4嵌入到Qt 5.2.1应用程序(64位)中.但是我有构建问题,我的意思是当我在main.cpp中包含Python头时它编译得很好.
#include <python.h>
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
Run Code Online (Sandbox Code Playgroud)
但是当我把它放在其他地方时(在Qt标题之后)
//
// embedpytest.cpp
//
#include <QLibrary>
#include <python.h>
EmbedPyTest::EmbedPyTest()
{
}
Run Code Online (Sandbox Code Playgroud)
我得到编译错误:
C:\Python34\include\object.h:435: error: C2059: syntax error : ';'
C:\Python34\include\object.h:435: error: C2238: unexpected token(s) preceding ';'
Run Code Online (Sandbox Code Playgroud)

这与此问题非常相似,但解决方案无效
谁知道如何解决这个问题?或建议一些干净的解决方法,以便python.h和Qt5能够幸福地生活在一起吗?
Is it safe to emit a signal on an object from another thread (if the slot is connected as QueuedConnection)? I couldn't find a specific piece of documentation that would mention this, the most relevant quote I found is this:
QObject 是可重入的。它的大多数非 GUI 子类,例如 QTimer、QTcpSocket、QUdpSocket 和 QProcess,也是可重入的,从而可以同时从多个线程使用这些类。请注意,这些类旨在从单个线程中创建和使用;在一个线程中创建一个对象并从另一个线程调用它的函数不能保证工作。
这表明它可能不行,这也适用于信号吗?有一个QMutexLockerinside QMetaObject::activate,所以在我看来它可能是线程安全的......?
#include <QCoreApplication>
#include <QTimer>
#include <thread>
#include <iostream>
struct Foo : public QObject
{
Q_OBJECT
public:
Foo(QObject* parent) : QObject(parent) {}
public slots:
void run() …Run Code Online (Sandbox Code Playgroud) qt ×10
qt-signals ×10
c++ ×9
qtcore ×3
moc ×2
inheritance ×1
python ×1
qmake ×1
qmetaobject ×1
qt4 ×1
qwidget ×1