MessageDialog - 从 C++ 更改文本但屏幕上没有更新
MessageDialog - text change from c++ but no update on screen
我已经设法动态更改包含 MessageDialog
的 QML Item
中的几个属性。我可以读取新设置的属性,但它们不会在屏幕上更新 - 它仍然是可见的 QML 设置的文本。我什至手动发送了 textChanged()
信号(见下文)无济于事。
知道我错过了什么吗?这是我的做法:
"ErrorDialog.qml":
Item{
id: baseItem
property string text: "myText"
property string title: "myTitle"
signal acceptedSignal()
onTextChanged: {
errorDialogItem.text=baseItem.text
}
MessageDialog {
id: errorDialogItem
objectName: "errorDialogItem"
text: baseItem.text
title: baseItem.title
onAccepted: {
acceptedSignal()
}
Component.onCompleted: visible=true
}
现在 c++:
this->component = QSharedPointer<QQmlComponent>(new QQmlComponent(&this->engine));
QObject::connect(&engine, SIGNAL(quit()), QCoreApplication::instance(), SLOT(quit()));
component->loadUrl(QUrl(QStringLiteral("qrc:///main.qml")));
topLevel = QSharedPointer<QObject>(component->create());
window = qobject_cast<QQuickWindow *>(topLevel.data());
surfaceFormat = window->requestedFormat();
window->setFormat(surfaceFormat);
window->show();
QQmlComponent dialogComponent(&engine, QUrl(QStringLiteral("qrc:///ErrorDialog.qml")));
QObject *myObject = dialogComponent.create();
QQuickItem *item = qobject_cast<QQuickItem*>(myObject);
QQmlEngine::setObjectOwnership(item, QQmlEngine::CppOwnership);
qDebug()<<"title"<<item->property("title");
qDebug()<<"text"<<item->property("text");
QString newText="TEXT SET FROM C++";
qDebug()<<"setTextProp: "<<item->setProperty("text",newText);
//-> true
qDebug()<<"new text"<<item->property("text");
//-> correctly set!
属性 已设置,但视觉上未更改。
所以我获取了嵌入式 MessageDialog 本身:
QObject* dialogObject=item->findChild<QObject*>("errorDialogItem");
QQuickItem* dialogItem=reinterpret_cast<QQuickItem*>(dialogObject);
item->setFlag(QQuickItem::ItemHasContents,true);
dialogItem->setFlag(QQuickItem::ItemHasContents,true);
我正在尽我所能,更新屏幕上的文本:
dialogItem->polish();
item->polish();
int methodIndex=item->metaObject()->indexOfMethod("textChanged()");
QMetaMethod method = item->metaObject()->method(methodIndex);
qDebug()<<"invoke: "<<method.invoke(item,Qt::DirectConnection);
//-->true
methodIndex=item->metaObject()->indexOfMethod("update()");
method = item->metaObject()->method(methodIndex);
qDebug()<<"invoke: "<<method.invoke(item,Qt::DirectConnection);
//-->true
methodIndex=dialogItem->metaObject()->indexOfMethod("textChanged()");
method = dialogItem->metaObject()->method(methodIndex);
qDebug()<<"invoke: "<<method.invoke(dialogItem,Qt::DirectConnection);
//-->true
methodIndex=dialogItem->metaObject()->indexOfMethod("windowGeometryChanged()");
method = dialogItem->metaObject()->method(methodIndex);
qDebug()<<"invoke: "<<method.invoke(dialogItem,Qt::DirectConnection);
//-->true
methodIndex=dialogItem->metaObject()->indexOfMethod("geometryChanged()");
method = dialogItem->metaObject()->method(methodIndex);
qDebug()<<"invoke: "<<method.invoke(dialogItem,Qt::DirectConnection);
//-->true
methodIndex=dialogItem->metaObject()->indexOfMethod("reset()");
method = dialogItem->metaObject()->method(methodIndex);
qDebug()<<"invoke: "<<method.invoke(dialogItem,Qt::DirectConnection);
//-->true
methodIndex=dialogItem->metaObject()->indexOfMethod("setVisible()");
method = dialogItem->metaObject()->method(methodIndex);
qDebug()<<"invoke: "<<method.invoke(dialogItem,Qt::DirectConnection,Q_ARG(bool,falseVar));
//-->false
methodIndex=dialogItem->metaObject()->indexOfMethod("setVisible()");
method = dialogItem->metaObject()->method(methodIndex);
qDebug()<<"invoke: "<<method.invoke(dialogItem,Qt::DirectConnection, Q_ARG(bool,trueVar));
//-->false
methodIndex=dialogItem->metaObject()->indexOfMethod("setText()");
method = dialogItem->metaObject()->method(methodIndex);
QString textStr = "a different text";
qDebug()<<"invoke: "<<method.invoke(dialogItem,Qt::DirectConnection, Q_ARG(QString,textStr));
//-->false
methodIndex=dialogItem->metaObject()->indexOfMethod("polish()");
method = dialogItem->metaObject()->method(methodIndex);
qDebug()<<"invoke: "<<method.invoke(dialogItem,Qt::DirectConnection);
//-->false
感谢@BaCaRoZzo,在创建最小示例时我发现了问题所在。在打开 Dialog
之前 属性 更改 绝对是强制性的,即处于 关闭 状态。如果我想更改已打开的 MessageDialog
中的内容,我必须关闭它,更改属性,然后再次打开它。更改属性然后关闭并重新打开(如 "redraw")是不够的。参见
bool setItemProperty(QString role, T value)
在下面的 .h
文件中。
这是我的工作代码,非常感谢任何进一步的建议。注意:"Controller" class 只是一些 class 提供了 GUI 的 QQmlApplicationEngine
。
C++-Class header: MessageDialog.h
#ifndef MESSAGEDIALOG_H
#define MESSAGEDIALOG_H
#include <QObject>
#include <QQuickItem>
#include <QDialog>
#include <QQmlApplicationEngine>
#include "src/controller/controller.h"
class MessageDialog : public QObject
{
Q_OBJECT
public:
enum StandardButton {
Ok = 0x00000400, // An "OK" button with AcceptRole.
Open = 0x00002000, // An "Open" button with AcceptRole.
Save = 0x00000800, // A "Save" button with AcceptRole.
Cancel = 0x00400000, // A "Cancel" button with RejectRole.
Close = 0x00200000, // A "Close" button with RejectRole.
Discard = 0x00800000, // A "Discard" button, DestructiveRole.
Apply = 0x02000000, // An "Apply" button with ApplyRole.
Reset = 0x04000000, // A "Reset" button with ResetRole.
RestoreDefaults = 0x08000000,//"Restore Defaults", ResetRole.
Help = 0x01000000, // A "Help" button with HelpRole.
SaveAll = 0x00001000, // A "Save All" button with AcceptRole.
Yes = 0x00004000, // A "Yes" button with YesRole.
YesToAll = 0x00008000, // A "Yes to All" button with YesRole.
No = 0x00010000, // A "No" button with NoRole.
NoToAll = 0x00020000, // A "No to All" button with NoRole.
Abort = 0x00040000, // An "Abort" button with RejectRole.
Retry = 0x00080000, // A "Retry" button with AcceptRole.
Ignore = 0x00100000, // An "Ignore" button with AcceptRole.
NoButton = 0x00000000 // An invalid button.
};
typedef QFlags<StandardButton> StandardButtons;
enum ButtonRole {
InvalidRole = -1, //button is invalid.
AcceptRole = 0, //accepted (e.g. OK).
RejectRole = 1, //rejected (e.g. Cancel).
DestructiveRole = 2,//destructive change
ActionRole = 3, //changes dialog.
HelpRole = 4, //request help.
YesRole = 5, //Yes"-like button.
NoRole = 6, //"No"-like button.
ApplyRole = 8, //applies current changes.
ResetRole = 7 //resets the dialog to default values.
};
enum Icon {
NoIcon = 0, // the message box does not have any icon.
Question = 4, // message is asking a question.
Information = 1, // message is nothing out of the ordinary.
Warning = 2, // message is a warning, but can be dealt with.
Critical = 3 // message represents a critical problem.
};
MessageDialog(Controller* controller,
QString title=QString(),
QString text=QString(),
QString informativeText=QString(),
QString detailedText=QString(),
StandardButtons buttons=QFlags<StandardButton>());
~MessageDialog();
void setText (const QString &text);
void setInformativeText (const QString &text);
void setDetailedText (const QString &text);
void setTitle(const QString &title);
bool open();
bool close();
void setStandardButtons(StandardButtons buttons);
void addButton(StandardButton button);
void setIcon(Icon icon);
StandardButton clickedButton();
void setModality(Qt::WindowModality modality);
int result();
StandardButton exec();
static void about(Controller* controller,
const QString &title,
const QString &text,
const QString &informativeText="",
const QString &detailedText="");
static StandardButton warning(
Controller* controller,
const QString &title,
const QString &text,
const QString &informativeText,
const QString &detailedText,
StandardButton button0 = NoButton,
StandardButton button1 = NoButton,
StandardButton button2 = NoButton,
StandardButton button3 = NoButton);
static MessageDialog::StandardButton information(
Controller* controller,
const QString &title,
const QString &text,
const QString &informativeText,
const QString &detailedText,
StandardButton button0 = NoButton,
StandardButton button1 = NoButton,
StandardButton button2 = NoButton,
StandardButton button3 = NoButton);
signals:
void buttonClicked(StandardButton standardButton);
void accepted();
void apply();
void discard();
void help();
void no();
void rejected();
void reset();
void yes();
public slots:
protected:
void initItem(Controller* controller);
void connectQMLSignals();
bool invokeMethod(QString methodSignature);
bool setStrings(
const QString &title,
const QString &text,
const QString informativeText,
const QString detailedText);
template <typename T>
bool setItemProperty(QString role, T value) {
Q_ASSERT(m_item);
bool wasOpen=m_isOpen;
close();
bool success;
success=m_item->setProperty(role.toLocal8Bit(),QVariant(value));
if(!success)
qDebug()<<"setProperty("<<role<<","<<value<<") failed.";
if (wasOpen) open();
return success;
}
QQmlApplicationEngine* m_engine;
QQuickItem* m_item;
bool m_isOpen;
StandardButtons m_standardButtons;
StandardButton m_result;
};
#endif // MESSAGEDIALOG_H
C++-Class 实现:MessageDialog.cpp
#include "messagedialog.h"
#include <QQuickItem>
#include <QQmlApplicationEngine>
MessageDialog::MessageDialog(
Controller *controller,
QString title,
QString text,
QString informativeText,
QString detailedText,
StandardButtons buttons)
{
Q_ASSERT(controller);
this->initItem(controller);
m_isOpen=false;
m_result=MessageDialog::NoButton;
this->setTitle(title);
this->setText(text);
this->setInformativeText(informativeText);
this->setDetailedText(detailedText);
this->setStandardButtons(buttons);
this->connectQMLSignals();
}
MessageDialog::~MessageDialog()
{
delete m_item;
}
void MessageDialog::setText(const QString &text)
{
setItemProperty("text",text);
}
void MessageDialog::setInformativeText(const QString &text)
{
setItemProperty("informativeText",text);
}
void MessageDialog::setDetailedText(const QString &text)
{
setItemProperty("detailedText",text);
}
void MessageDialog::setTitle(const QString &title)
{
setItemProperty("title",title);
}
void MessageDialog::setStandardButtons(StandardButtons buttons)
{
setItemProperty("standardButtons",buttons);
m_standardButtons=buttons;
}
void MessageDialog::addButton(MessageDialog::StandardButton button)
{
m_standardButtons|=button;
setItemProperty("standardButtons",m_standardButtons);
}
void MessageDialog::setIcon(MessageDialog::Icon icon)
{
setItemProperty("icon",icon);
}
MessageDialog::StandardButton MessageDialog::clickedButton()
{
int i=m_item->property("clickedButton").toInt();
return static_cast<MessageDialog::StandardButton>(i);
}
void MessageDialog::setModality(Qt::WindowModality modality)
{
setItemProperty("modality",modality);
}
int MessageDialog::result()
{
return this->clickedButton();
}
MessageDialog::StandardButton MessageDialog::exec()
{
QEventLoop loop;
connect(m_item, SIGNAL(accepted()),& loop,
SLOT(quit()),Qt::UniqueConnection);
connect(m_item, SIGNAL(apply()),& loop,
SLOT(quit()),Qt::UniqueConnection);
connect(m_item, SIGNAL(discard()),& loop,
SLOT(quit()),Qt::UniqueConnection);
connect(m_item, SIGNAL(help()),& loop,
SLOT(quit()),Qt::UniqueConnection);
connect(m_item, SIGNAL(no()),& loop,
SLOT(quit()),Qt::UniqueConnection);
connect(m_item, SIGNAL(rejected()),& loop,
SLOT(quit()),Qt::UniqueConnection);
connect(m_item, SIGNAL(reset()),& loop,
SLOT(quit()),Qt::UniqueConnection);
connect(m_item, SIGNAL(yes()),& loop,
SLOT(quit()),Qt::UniqueConnection);
invokeMethod("open()");
setModality(Qt::ApplicationModal);
loop.exec();
return this->clickedButton();
}
void MessageDialog::about(
Controller *controller,
const QString &title,
const QString &text,
const QString &informativeText,
const QString &detailedText)
{
MessageDialog dialog(controller);
dialog.setStrings(title,text,informativeText,detailedText);
dialog.setIcon(MessageDialog::Information);
dialog.setStandardButtons(Ok);
dialog.exec();
}
MessageDialog::StandardButton MessageDialog::warning(
Controller *controller,
const QString &title,
const QString &text,
const QString &informativeText,
const QString &detailedText,
MessageDialog::StandardButton button0,
MessageDialog::StandardButton button1,
MessageDialog::StandardButton button2,
MessageDialog::StandardButton button3)
{
MessageDialog dialog(controller);
dialog.setStrings(title,text,informativeText,detailedText);
dialog.setIcon(MessageDialog::Warning);
dialog.setStandardButtons(
StandardButtons(button0|button1|button2|button3));
dialog.exec();
return dialog.clickedButton();
}
MessageDialog::StandardButton MessageDialog::information(
Controller *controller,
const QString &title,
const QString &text,
const QString &informativeText,
const QString &detailedText,
MessageDialog::StandardButton button0,
MessageDialog::StandardButton button1,
MessageDialog::StandardButton button2,
MessageDialog::StandardButton button3)
{
MessageDialog dialog(controller);
dialog.setStrings(title,text,informativeText,detailedText);
dialog.setIcon(MessageDialog::Information);
dialog.setStandardButtons(
StandardButtons(button0|button1|button2|button3));
dialog.exec();
return dialog.clickedButton();
}
bool MessageDialog::open()
{
Q_ASSERT(m_item);
if (m_isOpen) return false;
m_isOpen=invokeMethod("open()");
return m_isOpen;
}
bool MessageDialog::close()
{
Q_ASSERT(m_item);
if (!m_isOpen) return false;
m_isOpen=!invokeMethod("close()");
return !m_isOpen;
}
bool MessageDialog::invokeMethod(QString methodSignature)
{
Q_ASSERT(m_item);
int methodIndex;
methodIndex=m_item->metaObject()->indexOfMethod(
methodSignature.toLocal8Bit());
QMetaMethod method = m_item->metaObject()->method(methodIndex);
return method.invoke(m_item,Qt::DirectConnection);
}
bool MessageDialog::setStrings(
const QString &title,
const QString &text,
const QString informativeText,
const QString detailedText)
{
bool success=true;
success &= this->setItemProperty("title",title);
success &= this->setItemProperty("text",text);
success &= this->setItemProperty("informativeText",informativeText);
success &= this->setItemProperty("detailedText",detailedText);
return success;
}
void MessageDialog::initItem(Controller *controller)
{
m_engine=controller->engine();
Q_ASSERT(m_engine);
QQmlComponent* myComponent=new QQmlComponent(
m_engine, QUrl(QStringLiteral("qrc:/MessageDialog.qml")));
Q_ASSERT(myComponent);
if (!myComponent->isReady()) {
qWarning("%s", qPrintable(myComponent->errorString()));
}
QObject *myObject = myComponent->create();
Q_ASSERT(myObject);
m_item = qobject_cast<QQuickItem*>(myObject);
Q_ASSERT(m_item);
QQmlApplicationEngine::setObjectOwnership(
m_item,QQmlApplicationEngine::CppOwnership);
}
void MessageDialog::connectQMLSignals()
{
connect(m_item, SIGNAL(accepted()),this, SIGNAL(accepted()));
connect(m_item, SIGNAL(apply()),this, SIGNAL(apply()));
connect(m_item, SIGNAL(discard()),this, SIGNAL(discard()));
connect(m_item, SIGNAL(help()),this, SIGNAL(help()));
connect(m_item, SIGNAL(no()),this, SIGNAL(no()));
connect(m_item, SIGNAL(rejected()),this, SIGNAL(rejected()));
connect(m_item, SIGNAL(reset()),this, SIGNAL(reset()));
connect(m_item, SIGNAL(yes()),this, SIGNAL(yes()));
}
这是通讯员MessageDialog.qml
import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Dialogs 1.2
Item{
id: baseItem
property alias text: errorDialogItem.text
property alias detailedText: errorDialogItem.detailedText
property alias informativeText: errorDialogItem.informativeText
property alias title: errorDialogItem.title
property alias modality: errorDialogItem.modality
property alias standardButtons: errorDialogItem.standardButtons
property alias icon: errorDialogItem.icon
property alias clickedButton: errorDialogItem.clickedButton
property alias standardIconSource:
errorDialogItem.standardIconSource
signal accepted()
signal apply()
signal discard()
signal help()
signal no()
signal rejected()
signal reset()
signal yes()
function open() {
return errorDialogItem.open()
}
function close() {
return errorDialogItem.close()
}
MessageDialog {
id: errorDialogItem
objectName: "errorDialogItem"
onAccepted: baseItem.accepted()
onApply: baseItem.apply()
onDiscard: baseItem.discard()
onHelp: baseItem.help()
onNo: baseItem.no()
onRejected: baseItem.rejected()
onReset: baseItem.reset()
onYes: baseItem.yes()
}
}
我希望这可以帮助将来有人节省时间。
这是 SeDi 答案的替代方法。它没有完全开发,但可以根据您自己的需要简单轻松地进行修改。
示例实现
MessageDialog::showCritcalError( myQmlEngine, "The sky is falling!" );
MessageDialog.h
#ifndef MESSAGEDIALOG_H
#define MESSAGEDIALOG_H
#include <QQmlEngine>
struct MessageDialog
{
static void showCritcalError( QQmlEngine *engine, const QString &message );
};
#endif // MESSAGEDIALOG_H
MessageDialog.cpp
#include "MessageDialog.h"
#include <QQmlComponent>
#include <QQuickItem>
// ---------------------------------
static const QString QML_RESOURCE_PREFIX( "qrc:/" );
static const QString DIALOG_QML( "MessgeDialog.qml" );
static const char *TITLE_PROP = "dialogTitle";
static const char *ICON_PROP = "dialogIcon";
static const char *TEXT_PROP = "dialogText";
static const char *VISIBLE_PROP = "dialogVisible";
static const QString INFO_DEFAULT_TITLE( "Information" );
static const QString WARNING_DEFAULT_TITLE( "Warning" );
static const QString CRITICAL_DEFAULT_TITLE( "Error" );
static const QString QUESTION_DEFAULT_TITLE( "Question" );
static const int NO_ICON = 0,
INFO_ICON = 1,
WARNING = 2,
CRITICAL_ICON = 3,
QUESTION_ICON = 4;
void showMessageDialog( QQmlEngine *engine,
const QString &title, const int icon, const QString &text )
{
QQmlComponent component( engine, QUrl( QML_RESOURCE_PREFIX + DIALOG_QML ) );
QQuickItem *item = qobject_cast<QQuickItem*>( component.create() );
item->setProperty( TITLE_PROP, title );
item->setProperty( ICON_PROP, icon );
item->setProperty( TEXT_PROP, text );
item->setProperty( VISIBLE_PROP, true ); // must do last after setting other properties
}
// ---------------------------------
void MessageDialog::showCritcalError( QQmlEngine *engine, const QString &message )
{ showMessageDialog( engine, CRITICAL_DEFAULT_TITLE, CRITICAL_ICON, message ); }
MessageDialog.qml(在我的用例中列在 .qrc 中)
import QtQuick 2.2
import QtQuick.Dialogs 1.1
Item {
property string dialogTitle: ""
property int dialogIcon: 0
property string dialogText: ""
property bool dialogVisible: false
MessageDialog {
id: messageDialog
title : dialogTitle
icon : dialogIcon
text : dialogText
visible : dialogVisible
modality: Qt.ApplicationModal
}
}
我已经设法动态更改包含 MessageDialog
的 QML Item
中的几个属性。我可以读取新设置的属性,但它们不会在屏幕上更新 - 它仍然是可见的 QML 设置的文本。我什至手动发送了 textChanged()
信号(见下文)无济于事。
知道我错过了什么吗?这是我的做法:
"ErrorDialog.qml":
Item{
id: baseItem
property string text: "myText"
property string title: "myTitle"
signal acceptedSignal()
onTextChanged: {
errorDialogItem.text=baseItem.text
}
MessageDialog {
id: errorDialogItem
objectName: "errorDialogItem"
text: baseItem.text
title: baseItem.title
onAccepted: {
acceptedSignal()
}
Component.onCompleted: visible=true
}
现在 c++:
this->component = QSharedPointer<QQmlComponent>(new QQmlComponent(&this->engine));
QObject::connect(&engine, SIGNAL(quit()), QCoreApplication::instance(), SLOT(quit()));
component->loadUrl(QUrl(QStringLiteral("qrc:///main.qml")));
topLevel = QSharedPointer<QObject>(component->create());
window = qobject_cast<QQuickWindow *>(topLevel.data());
surfaceFormat = window->requestedFormat();
window->setFormat(surfaceFormat);
window->show();
QQmlComponent dialogComponent(&engine, QUrl(QStringLiteral("qrc:///ErrorDialog.qml")));
QObject *myObject = dialogComponent.create();
QQuickItem *item = qobject_cast<QQuickItem*>(myObject);
QQmlEngine::setObjectOwnership(item, QQmlEngine::CppOwnership);
qDebug()<<"title"<<item->property("title");
qDebug()<<"text"<<item->property("text");
QString newText="TEXT SET FROM C++";
qDebug()<<"setTextProp: "<<item->setProperty("text",newText);
//-> true
qDebug()<<"new text"<<item->property("text");
//-> correctly set!
属性 已设置,但视觉上未更改。 所以我获取了嵌入式 MessageDialog 本身:
QObject* dialogObject=item->findChild<QObject*>("errorDialogItem");
QQuickItem* dialogItem=reinterpret_cast<QQuickItem*>(dialogObject);
item->setFlag(QQuickItem::ItemHasContents,true);
dialogItem->setFlag(QQuickItem::ItemHasContents,true);
我正在尽我所能,更新屏幕上的文本:
dialogItem->polish();
item->polish();
int methodIndex=item->metaObject()->indexOfMethod("textChanged()");
QMetaMethod method = item->metaObject()->method(methodIndex);
qDebug()<<"invoke: "<<method.invoke(item,Qt::DirectConnection);
//-->true
methodIndex=item->metaObject()->indexOfMethod("update()");
method = item->metaObject()->method(methodIndex);
qDebug()<<"invoke: "<<method.invoke(item,Qt::DirectConnection);
//-->true
methodIndex=dialogItem->metaObject()->indexOfMethod("textChanged()");
method = dialogItem->metaObject()->method(methodIndex);
qDebug()<<"invoke: "<<method.invoke(dialogItem,Qt::DirectConnection);
//-->true
methodIndex=dialogItem->metaObject()->indexOfMethod("windowGeometryChanged()");
method = dialogItem->metaObject()->method(methodIndex);
qDebug()<<"invoke: "<<method.invoke(dialogItem,Qt::DirectConnection);
//-->true
methodIndex=dialogItem->metaObject()->indexOfMethod("geometryChanged()");
method = dialogItem->metaObject()->method(methodIndex);
qDebug()<<"invoke: "<<method.invoke(dialogItem,Qt::DirectConnection);
//-->true
methodIndex=dialogItem->metaObject()->indexOfMethod("reset()");
method = dialogItem->metaObject()->method(methodIndex);
qDebug()<<"invoke: "<<method.invoke(dialogItem,Qt::DirectConnection);
//-->true
methodIndex=dialogItem->metaObject()->indexOfMethod("setVisible()");
method = dialogItem->metaObject()->method(methodIndex);
qDebug()<<"invoke: "<<method.invoke(dialogItem,Qt::DirectConnection,Q_ARG(bool,falseVar));
//-->false
methodIndex=dialogItem->metaObject()->indexOfMethod("setVisible()");
method = dialogItem->metaObject()->method(methodIndex);
qDebug()<<"invoke: "<<method.invoke(dialogItem,Qt::DirectConnection, Q_ARG(bool,trueVar));
//-->false
methodIndex=dialogItem->metaObject()->indexOfMethod("setText()");
method = dialogItem->metaObject()->method(methodIndex);
QString textStr = "a different text";
qDebug()<<"invoke: "<<method.invoke(dialogItem,Qt::DirectConnection, Q_ARG(QString,textStr));
//-->false
methodIndex=dialogItem->metaObject()->indexOfMethod("polish()");
method = dialogItem->metaObject()->method(methodIndex);
qDebug()<<"invoke: "<<method.invoke(dialogItem,Qt::DirectConnection);
//-->false
感谢@BaCaRoZzo,在创建最小示例时我发现了问题所在。在打开 Dialog
之前 属性 更改 绝对是强制性的,即处于 关闭 状态。如果我想更改已打开的 MessageDialog
中的内容,我必须关闭它,更改属性,然后再次打开它。更改属性然后关闭并重新打开(如 "redraw")是不够的。参见
bool setItemProperty(QString role, T value)
在下面的 .h
文件中。
这是我的工作代码,非常感谢任何进一步的建议。注意:"Controller" class 只是一些 class 提供了 GUI 的 QQmlApplicationEngine
。
C++-Class header: MessageDialog.h
#ifndef MESSAGEDIALOG_H
#define MESSAGEDIALOG_H
#include <QObject>
#include <QQuickItem>
#include <QDialog>
#include <QQmlApplicationEngine>
#include "src/controller/controller.h"
class MessageDialog : public QObject
{
Q_OBJECT
public:
enum StandardButton {
Ok = 0x00000400, // An "OK" button with AcceptRole.
Open = 0x00002000, // An "Open" button with AcceptRole.
Save = 0x00000800, // A "Save" button with AcceptRole.
Cancel = 0x00400000, // A "Cancel" button with RejectRole.
Close = 0x00200000, // A "Close" button with RejectRole.
Discard = 0x00800000, // A "Discard" button, DestructiveRole.
Apply = 0x02000000, // An "Apply" button with ApplyRole.
Reset = 0x04000000, // A "Reset" button with ResetRole.
RestoreDefaults = 0x08000000,//"Restore Defaults", ResetRole.
Help = 0x01000000, // A "Help" button with HelpRole.
SaveAll = 0x00001000, // A "Save All" button with AcceptRole.
Yes = 0x00004000, // A "Yes" button with YesRole.
YesToAll = 0x00008000, // A "Yes to All" button with YesRole.
No = 0x00010000, // A "No" button with NoRole.
NoToAll = 0x00020000, // A "No to All" button with NoRole.
Abort = 0x00040000, // An "Abort" button with RejectRole.
Retry = 0x00080000, // A "Retry" button with AcceptRole.
Ignore = 0x00100000, // An "Ignore" button with AcceptRole.
NoButton = 0x00000000 // An invalid button.
};
typedef QFlags<StandardButton> StandardButtons;
enum ButtonRole {
InvalidRole = -1, //button is invalid.
AcceptRole = 0, //accepted (e.g. OK).
RejectRole = 1, //rejected (e.g. Cancel).
DestructiveRole = 2,//destructive change
ActionRole = 3, //changes dialog.
HelpRole = 4, //request help.
YesRole = 5, //Yes"-like button.
NoRole = 6, //"No"-like button.
ApplyRole = 8, //applies current changes.
ResetRole = 7 //resets the dialog to default values.
};
enum Icon {
NoIcon = 0, // the message box does not have any icon.
Question = 4, // message is asking a question.
Information = 1, // message is nothing out of the ordinary.
Warning = 2, // message is a warning, but can be dealt with.
Critical = 3 // message represents a critical problem.
};
MessageDialog(Controller* controller,
QString title=QString(),
QString text=QString(),
QString informativeText=QString(),
QString detailedText=QString(),
StandardButtons buttons=QFlags<StandardButton>());
~MessageDialog();
void setText (const QString &text);
void setInformativeText (const QString &text);
void setDetailedText (const QString &text);
void setTitle(const QString &title);
bool open();
bool close();
void setStandardButtons(StandardButtons buttons);
void addButton(StandardButton button);
void setIcon(Icon icon);
StandardButton clickedButton();
void setModality(Qt::WindowModality modality);
int result();
StandardButton exec();
static void about(Controller* controller,
const QString &title,
const QString &text,
const QString &informativeText="",
const QString &detailedText="");
static StandardButton warning(
Controller* controller,
const QString &title,
const QString &text,
const QString &informativeText,
const QString &detailedText,
StandardButton button0 = NoButton,
StandardButton button1 = NoButton,
StandardButton button2 = NoButton,
StandardButton button3 = NoButton);
static MessageDialog::StandardButton information(
Controller* controller,
const QString &title,
const QString &text,
const QString &informativeText,
const QString &detailedText,
StandardButton button0 = NoButton,
StandardButton button1 = NoButton,
StandardButton button2 = NoButton,
StandardButton button3 = NoButton);
signals:
void buttonClicked(StandardButton standardButton);
void accepted();
void apply();
void discard();
void help();
void no();
void rejected();
void reset();
void yes();
public slots:
protected:
void initItem(Controller* controller);
void connectQMLSignals();
bool invokeMethod(QString methodSignature);
bool setStrings(
const QString &title,
const QString &text,
const QString informativeText,
const QString detailedText);
template <typename T>
bool setItemProperty(QString role, T value) {
Q_ASSERT(m_item);
bool wasOpen=m_isOpen;
close();
bool success;
success=m_item->setProperty(role.toLocal8Bit(),QVariant(value));
if(!success)
qDebug()<<"setProperty("<<role<<","<<value<<") failed.";
if (wasOpen) open();
return success;
}
QQmlApplicationEngine* m_engine;
QQuickItem* m_item;
bool m_isOpen;
StandardButtons m_standardButtons;
StandardButton m_result;
};
#endif // MESSAGEDIALOG_H
C++-Class 实现:MessageDialog.cpp
#include "messagedialog.h"
#include <QQuickItem>
#include <QQmlApplicationEngine>
MessageDialog::MessageDialog(
Controller *controller,
QString title,
QString text,
QString informativeText,
QString detailedText,
StandardButtons buttons)
{
Q_ASSERT(controller);
this->initItem(controller);
m_isOpen=false;
m_result=MessageDialog::NoButton;
this->setTitle(title);
this->setText(text);
this->setInformativeText(informativeText);
this->setDetailedText(detailedText);
this->setStandardButtons(buttons);
this->connectQMLSignals();
}
MessageDialog::~MessageDialog()
{
delete m_item;
}
void MessageDialog::setText(const QString &text)
{
setItemProperty("text",text);
}
void MessageDialog::setInformativeText(const QString &text)
{
setItemProperty("informativeText",text);
}
void MessageDialog::setDetailedText(const QString &text)
{
setItemProperty("detailedText",text);
}
void MessageDialog::setTitle(const QString &title)
{
setItemProperty("title",title);
}
void MessageDialog::setStandardButtons(StandardButtons buttons)
{
setItemProperty("standardButtons",buttons);
m_standardButtons=buttons;
}
void MessageDialog::addButton(MessageDialog::StandardButton button)
{
m_standardButtons|=button;
setItemProperty("standardButtons",m_standardButtons);
}
void MessageDialog::setIcon(MessageDialog::Icon icon)
{
setItemProperty("icon",icon);
}
MessageDialog::StandardButton MessageDialog::clickedButton()
{
int i=m_item->property("clickedButton").toInt();
return static_cast<MessageDialog::StandardButton>(i);
}
void MessageDialog::setModality(Qt::WindowModality modality)
{
setItemProperty("modality",modality);
}
int MessageDialog::result()
{
return this->clickedButton();
}
MessageDialog::StandardButton MessageDialog::exec()
{
QEventLoop loop;
connect(m_item, SIGNAL(accepted()),& loop,
SLOT(quit()),Qt::UniqueConnection);
connect(m_item, SIGNAL(apply()),& loop,
SLOT(quit()),Qt::UniqueConnection);
connect(m_item, SIGNAL(discard()),& loop,
SLOT(quit()),Qt::UniqueConnection);
connect(m_item, SIGNAL(help()),& loop,
SLOT(quit()),Qt::UniqueConnection);
connect(m_item, SIGNAL(no()),& loop,
SLOT(quit()),Qt::UniqueConnection);
connect(m_item, SIGNAL(rejected()),& loop,
SLOT(quit()),Qt::UniqueConnection);
connect(m_item, SIGNAL(reset()),& loop,
SLOT(quit()),Qt::UniqueConnection);
connect(m_item, SIGNAL(yes()),& loop,
SLOT(quit()),Qt::UniqueConnection);
invokeMethod("open()");
setModality(Qt::ApplicationModal);
loop.exec();
return this->clickedButton();
}
void MessageDialog::about(
Controller *controller,
const QString &title,
const QString &text,
const QString &informativeText,
const QString &detailedText)
{
MessageDialog dialog(controller);
dialog.setStrings(title,text,informativeText,detailedText);
dialog.setIcon(MessageDialog::Information);
dialog.setStandardButtons(Ok);
dialog.exec();
}
MessageDialog::StandardButton MessageDialog::warning(
Controller *controller,
const QString &title,
const QString &text,
const QString &informativeText,
const QString &detailedText,
MessageDialog::StandardButton button0,
MessageDialog::StandardButton button1,
MessageDialog::StandardButton button2,
MessageDialog::StandardButton button3)
{
MessageDialog dialog(controller);
dialog.setStrings(title,text,informativeText,detailedText);
dialog.setIcon(MessageDialog::Warning);
dialog.setStandardButtons(
StandardButtons(button0|button1|button2|button3));
dialog.exec();
return dialog.clickedButton();
}
MessageDialog::StandardButton MessageDialog::information(
Controller *controller,
const QString &title,
const QString &text,
const QString &informativeText,
const QString &detailedText,
MessageDialog::StandardButton button0,
MessageDialog::StandardButton button1,
MessageDialog::StandardButton button2,
MessageDialog::StandardButton button3)
{
MessageDialog dialog(controller);
dialog.setStrings(title,text,informativeText,detailedText);
dialog.setIcon(MessageDialog::Information);
dialog.setStandardButtons(
StandardButtons(button0|button1|button2|button3));
dialog.exec();
return dialog.clickedButton();
}
bool MessageDialog::open()
{
Q_ASSERT(m_item);
if (m_isOpen) return false;
m_isOpen=invokeMethod("open()");
return m_isOpen;
}
bool MessageDialog::close()
{
Q_ASSERT(m_item);
if (!m_isOpen) return false;
m_isOpen=!invokeMethod("close()");
return !m_isOpen;
}
bool MessageDialog::invokeMethod(QString methodSignature)
{
Q_ASSERT(m_item);
int methodIndex;
methodIndex=m_item->metaObject()->indexOfMethod(
methodSignature.toLocal8Bit());
QMetaMethod method = m_item->metaObject()->method(methodIndex);
return method.invoke(m_item,Qt::DirectConnection);
}
bool MessageDialog::setStrings(
const QString &title,
const QString &text,
const QString informativeText,
const QString detailedText)
{
bool success=true;
success &= this->setItemProperty("title",title);
success &= this->setItemProperty("text",text);
success &= this->setItemProperty("informativeText",informativeText);
success &= this->setItemProperty("detailedText",detailedText);
return success;
}
void MessageDialog::initItem(Controller *controller)
{
m_engine=controller->engine();
Q_ASSERT(m_engine);
QQmlComponent* myComponent=new QQmlComponent(
m_engine, QUrl(QStringLiteral("qrc:/MessageDialog.qml")));
Q_ASSERT(myComponent);
if (!myComponent->isReady()) {
qWarning("%s", qPrintable(myComponent->errorString()));
}
QObject *myObject = myComponent->create();
Q_ASSERT(myObject);
m_item = qobject_cast<QQuickItem*>(myObject);
Q_ASSERT(m_item);
QQmlApplicationEngine::setObjectOwnership(
m_item,QQmlApplicationEngine::CppOwnership);
}
void MessageDialog::connectQMLSignals()
{
connect(m_item, SIGNAL(accepted()),this, SIGNAL(accepted()));
connect(m_item, SIGNAL(apply()),this, SIGNAL(apply()));
connect(m_item, SIGNAL(discard()),this, SIGNAL(discard()));
connect(m_item, SIGNAL(help()),this, SIGNAL(help()));
connect(m_item, SIGNAL(no()),this, SIGNAL(no()));
connect(m_item, SIGNAL(rejected()),this, SIGNAL(rejected()));
connect(m_item, SIGNAL(reset()),this, SIGNAL(reset()));
connect(m_item, SIGNAL(yes()),this, SIGNAL(yes()));
}
这是通讯员MessageDialog.qml
import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Dialogs 1.2
Item{
id: baseItem
property alias text: errorDialogItem.text
property alias detailedText: errorDialogItem.detailedText
property alias informativeText: errorDialogItem.informativeText
property alias title: errorDialogItem.title
property alias modality: errorDialogItem.modality
property alias standardButtons: errorDialogItem.standardButtons
property alias icon: errorDialogItem.icon
property alias clickedButton: errorDialogItem.clickedButton
property alias standardIconSource:
errorDialogItem.standardIconSource
signal accepted()
signal apply()
signal discard()
signal help()
signal no()
signal rejected()
signal reset()
signal yes()
function open() {
return errorDialogItem.open()
}
function close() {
return errorDialogItem.close()
}
MessageDialog {
id: errorDialogItem
objectName: "errorDialogItem"
onAccepted: baseItem.accepted()
onApply: baseItem.apply()
onDiscard: baseItem.discard()
onHelp: baseItem.help()
onNo: baseItem.no()
onRejected: baseItem.rejected()
onReset: baseItem.reset()
onYes: baseItem.yes()
}
}
我希望这可以帮助将来有人节省时间。
这是 SeDi 答案的替代方法。它没有完全开发,但可以根据您自己的需要简单轻松地进行修改。
示例实现
MessageDialog::showCritcalError( myQmlEngine, "The sky is falling!" );
MessageDialog.h
#ifndef MESSAGEDIALOG_H
#define MESSAGEDIALOG_H
#include <QQmlEngine>
struct MessageDialog
{
static void showCritcalError( QQmlEngine *engine, const QString &message );
};
#endif // MESSAGEDIALOG_H
MessageDialog.cpp
#include "MessageDialog.h"
#include <QQmlComponent>
#include <QQuickItem>
// ---------------------------------
static const QString QML_RESOURCE_PREFIX( "qrc:/" );
static const QString DIALOG_QML( "MessgeDialog.qml" );
static const char *TITLE_PROP = "dialogTitle";
static const char *ICON_PROP = "dialogIcon";
static const char *TEXT_PROP = "dialogText";
static const char *VISIBLE_PROP = "dialogVisible";
static const QString INFO_DEFAULT_TITLE( "Information" );
static const QString WARNING_DEFAULT_TITLE( "Warning" );
static const QString CRITICAL_DEFAULT_TITLE( "Error" );
static const QString QUESTION_DEFAULT_TITLE( "Question" );
static const int NO_ICON = 0,
INFO_ICON = 1,
WARNING = 2,
CRITICAL_ICON = 3,
QUESTION_ICON = 4;
void showMessageDialog( QQmlEngine *engine,
const QString &title, const int icon, const QString &text )
{
QQmlComponent component( engine, QUrl( QML_RESOURCE_PREFIX + DIALOG_QML ) );
QQuickItem *item = qobject_cast<QQuickItem*>( component.create() );
item->setProperty( TITLE_PROP, title );
item->setProperty( ICON_PROP, icon );
item->setProperty( TEXT_PROP, text );
item->setProperty( VISIBLE_PROP, true ); // must do last after setting other properties
}
// ---------------------------------
void MessageDialog::showCritcalError( QQmlEngine *engine, const QString &message )
{ showMessageDialog( engine, CRITICAL_DEFAULT_TITLE, CRITICAL_ICON, message ); }
MessageDialog.qml(在我的用例中列在 .qrc 中)
import QtQuick 2.2
import QtQuick.Dialogs 1.1
Item {
property string dialogTitle: ""
property int dialogIcon: 0
property string dialogText: ""
property bool dialogVisible: false
MessageDialog {
id: messageDialog
title : dialogTitle
icon : dialogIcon
text : dialogText
visible : dialogVisible
modality: Qt.ApplicationModal
}
}