如何从 C++ 访问特定 QML 控件的事件
Posted
技术标签:
【中文标题】如何从 C++ 访问特定 QML 控件的事件【英文标题】:how to access events of a specific QML control from c++ 【发布时间】:2013-11-13 15:48:10 【问题描述】:有没有办法从 c++ 访问 QML 控件(例如按钮)的信号(例如 clicked()
)。假设我有那个特定控件的内存地址。我只是想从 C++ 代码中模拟一个点击事件。
【问题讨论】:
【参考方案1】:简单。您只需在具有 QObject 基础的 C++ 对象中创建一个插槽,确保其注册为 QML 类型,然后在 QML 文档中“实例化”它,并使用 connect 通过 QML 将所需信号连接到 C++ 对象() 并从 C++ 端处理逻辑。
例子:
我有一个 Rectangle,我想从中获取 onWidthChanged 信号并在我的类 ShapeTracker 中使用它,该类跟踪形状何时发生变化或其他情况
在 main.cpp 中:
#include "shapetracker.h"
int main(int argc, char *argv[])
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
/* this is where you register ShapeTracker as a QML type that can be
accessed through the QML engine even though its a C++ QObject */
qmlRegisterType<ShapeTracker>("my_cpp_classes", 1, 0, "ShapeTracker");
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
然后在
main.qml
import QtQuick 2.6
/* import the C++ class you registered into this QML document */
import my_cpp_classes 1.0
Window
visible: true
Item
/* set up a parent item that has a signal which is exposed to
the ShapeTracker object and the Rectangle you want to track */
id: myRootItem
signal rectangleChanged(var newWidth)
/* Heres our special Rectangle from QML that will send a signal when
its width changes */
Rectangle
id: specialRectangle
width: 250
/* send the signal rectangleChanged(width) from our parent item
root item whenever width changes
*/
onWidthChanged: function() rectangleChanged(width);
/* Special Button that when clicked enlarges the Rectangle but
10px */
Button
id: mySpecialButton
onClicked: click_handler(mouse);
function click_handler(mouse):
if (specialRectangle.width < 500)
specialRectangle.width += 10;
/* Heres the actual ShapeTracker instance, which exists
as a QObject inside of the QML context, but has its methods
which are declared in C++, and exposed to the QML engine */
ShapeTracker
id: myShapeTracker
/* similar to a constructor, but more like a callback */
Component.onCompleted:
/* connect our signal from the parent root Item called
"rectangleChanged" to the ShapeTracker's Slot called
"myRectangleChangeHandler" */
myRootItem.rectangleChanged.connect(myShapeTracker.myRectangleChangeHandler);
/* connect send_mouse_click to the click_handler of
the button */
myShapeTracker.send_mouse_click.connect(mySpecialButton.click_handler)
在 shapetracker.h 中,您只需添加一个名为 myRectangleChangeHandler 的新插槽,它就会在通过 QML 发送并通过 C++ 处理时接收该信号
class ShapeTracker : public QObject
Q_OBJECT
public:
ShapeTracker(QObject *parent = 0 );
signal:
void send_mouse_click(QMouseEvent *event);
public slots:
void myRectangleChangeHandler(QVariant newWidth)
/* Perform a mouse click on our QML Object mySpecialButton
using QQuickItem::mousePressEvent and sending it via
signal back to QML */
QMouseEvent myEvent(QEvent::MouseButtonPress, QPointF(1,1), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
QMouseEvent* pressEvent = QQuickItem::mousePressEvent(&myEvent);
emit send_mouse_click(pressEvent);
;
总之,
您将 C++ QObject 公开给 QML,然后您使用 object.signal.connect(cppObject.desired_slot)
为了连接它们——所有额外的东西都是为了一个功能示例,以防以后有人需要它
实际上,您甚至不需要此功能,因为 onClick 事件中发生的任何事情都可以很容易地放入任何其他属性中,例如 on
Rectangle
id: rect
signal customClick(var var1)
onCustomClick : console.log(var1);
Item
rect.customClick(1);
【讨论】:
【参考方案2】:简单的方法是手动调用所有接收 SLOTS。但这会很乏味且容易出错。
您可以尝试实现一个 QObject 的子类,它有一个插槽onClicked()
,它发出信号clicked()
,并将其用作按钮和按钮控制的元素之间的垫片。将按钮clicked()
连接到新对象onClicked()
,然后将新对象连接到原始接收器。然后调用onClicked()
将触发该行为。
这是一个很简单的例子,我没有通过编译器运行过。
ButtonShim.hpp
#include <QObject>
class ButtonShim : public QObject
Q_OBJECT
public:
ButtonShim(QObject *parent = 0);
virtual ~ButtonShim();
public slots:
void onClicked();
signals:
void clicked();
;
ButtonShim.cpp
#include "ButtonShim.hpp"
ButtonShim::ButtonShim(QObject *parent) : QObject(parent)
ButtonShim::~ButtonShim()
void ButtonShim::onClicked()
// All we do here is emit the clicked signal.
emit clicked();
SomeFile.cpp
#include <bb/cascades/Button>
#include "ButtonShim.hpp"
...
ButtonShim * pButtonShim = new ButtonShim(pButton); // pButtonShim will live as long as pButton
bool c = connect(pButton, SIGNAL(clicked()), pButtonShim, SLOT(onClicked()));
c = connect(pButtonShim, SIGNAL(clicked()), pSomeObject, SLOT(onButtonClicked()));
...
// to simulate a click of pButton
pButtonShim->onClicked();
SomeFile.qml
// assuming ButtonShim has been exposed to QML from your application
...
attachedObjects: [
ButtonShim
id: buttonShim
onClicked:
clickedLabel.text = "I've been clicked";
]
...
Label
id: clickedLabel
text: "I haven't been clicked"
Button
text: "Click Me"
onClicked:
buttonShim.onClicked();
【讨论】:
感谢您的回复。我正在努力。但是如何从 C++ 代码中发出“clicked()”信号? 我添加了一些粗略的示例代码,省略了错误检查。可能存在一些语法错误。【参考方案3】:我认为您可以查看tests 的代码。他们在那里从加载到引擎中的 QML 文件中获取对象。
如果你有一个 QObject,你可以调用 signal,因为,AFAIR
public signals:
void clicked();
被moc扩展成
public:
void clicked();
【讨论】:
以上是关于如何从 C++ 访问特定 QML 控件的事件的主要内容,如果未能解决你的问题,请参考以下文章
如何从 C++ 端连接到 QML 项目的 onClick 事件
如何从 C++ 代码将 QML 对象转换为 QQuickWindow?