@GrecKo said in QML-Dialog with flexible method calls possible?:
First I'd like to state that what you are doing is bad practice
Thanks for that valuable assessment! Following this, I have re-thought my approach. I've got it working now by opening a QML file from C++ and feeding it with initial properties. I hope this is better.
For anyone interested, here's how I do it. I have the possibility to use StandardButtons or user defined ones (initialized with a QStringList).
userinteractionbox.qml
import QtQuick 2.0
import QtQuick.Controls 2.15
Dialog {
id: userInteractionBox
property string text: ""
property var userButtons: []
property int initStandardButtons: Dialog.NoButton
contentItem: ScrollView {
contentWidth: availableWidth
contentHeight: 1000
height: availableHeight
width: availableWidth
TextArea {
id: textArea
text: userInteractionBox.text
wrapMode: "WordWrap"
}
}
signal standardButtonClicked(int nr)
signal userButtonClicked(int nr)
footer: DialogButtonBox {
id: dbbx
// STANDARD BUTTONS
standardButtons: userInteractionBox.initStandardButtons
function processButton(button) {
switch (button) {
case standardButton(Dialog.Ok): userInteractionBox.standardButtonClicked(Dialog.Ok); break;
case standardButton(Dialog.Open): userInteractionBox.standardButtonClicked(Dialog.Open); break;
case standardButton(Dialog.Save): userInteractionBox.standardButtonClicked(Dialog.Save); break;
case standardButton(Dialog.Cancel): userInteractionBox.standardButtonClicked(Dialog.Cancel); break;
case standardButton(Dialog.Close): userInteractionBox.standardButtonClicked(Dialog.Close); break;
case standardButton(Dialog.Discard): userInteractionBox.standardButtonClicked(Dialog.Discard); break;
case standardButton(Dialog.Apply): userInteractionBox.standardButtonClicked(Dialog.Apply); break;
case standardButton(Dialog.Reset): userInteractionBox.standardButtonClicked(Dialog.Reset); break;
case standardButton(Dialog.RestoreDefaults): userInteractionBox.standardButtonClicked(Dialog.RestoreDefaults); break;
case standardButton(Dialog.Help): userInteractionBox.standardButtonClicked(Dialog.Help); break;
case standardButton(Dialog.SaveAll): userInteractionBox.standardButtonClicked(Dialog.SaveAll); break;
case standardButton(Dialog.Yes): userInteractionBox.standardButtonClicked(Dialog.Yes); break;
case standardButton(Dialog.YesToAll): userInteractionBox.standardButtonClicked(Dialog.YesToAll); break;
case standardButton(Dialog.No): userInteractionBox.standardButtonClicked(Dialog.No); break;
case standardButton(Dialog.NoToAll): userInteractionBox.standardButtonClicked(Dialog.NoToAll); break;
case standardButton(Dialog.Abort): userInteractionBox.standardButtonClicked(Dialog.Abort); break;
case standardButton(Dialog.Retry): userInteractionBox.standardButtonClicked(Dialog.Retry); break;
case standardButton(Dialog.Ignore): userInteractionBox.standardButtonClicked(Dialog.Ignore); break;
}
}
// USER BUTTONS
Repeater {
model: userButtons.length
Button {
visible: text !== ""
onClicked: userInteractionBox.userButtonClicked(index+1);
text: userButtons[index]
}
}
onClicked: {
processButton(button)
}
}
}
For interaction I have a userinteractionbox.h
#ifndef USERINTERACTIONBOX_H
#define USERINTERACTIONBOX_H
#include <QObject>
#include <QQuickItem>
#include <QQmlApplicationEngine>
#include <QGuiApplication>
#include <QQmlContext>
#include <QQuickWindow>
#include <QQuickView>
#include <QtQuick/qquickitem.h>
#include <QDebug>
class UserInteractionBox : public QObject
{
Q_OBJECT
public slots:
void buttonClickedSlot(int buttonNr);
public:
UserInteractionBox(QQuickView* view, QString title, QString text);
~UserInteractionBox() override {}
enum StandardButton {
NoButton = 0x00000000,
Ok = 0x00000400,
Save = 0x00000800,
SaveAll = 0x00001000,
Open = 0x00002000,
Yes = 0x00004000,
YesToAll = 0x00008000,
No = 0x00010000,
NoToAll = 0x00020000,
Abort = 0x00040000,
Retry = 0x00080000,
Ignore = 0x00100000,
Close = 0x00200000,
Cancel = 0x00400000,
Discard = 0x00800000,
Help = 0x01000000,
Apply = 0x02000000,
Reset = 0x04000000,
RestoreDefaults = 0x08000000
};
Q_DECLARE_FLAGS(StandardButtons, StandardButton)
Q_FLAG(StandardButton)
enum ClosePolicyFlag {
NoAutoClose = 0x00,
CloseOnPressOutside = 0x01,
CloseOnPressOutsideParent = 0x02,
CloseOnReleaseOutside = 0x04,
CloseOnReleaseOutsideParent = 0x08,
CloseOnEscape = 0x10
};
Q_DECLARE_FLAGS(ClosePolicyFlags, ClosePolicyFlag)
Q_FLAG(ClosePolicyFlag)
void open();
void close();
QFlags<StandardButton> standardButtons() ;
void setStandardButtons(QFlags<StandardButton> flags);
int clickedButton() const;
bool modal() const;
void setModal(bool newModal);
int width() const;
void setWidth(int newWidth);
int height() const;
void setHeight(int newHeight);
const ClosePolicyFlags &closePolicy() const;
void setClosePolicy(const ClosePolicyFlags &newClosePolicy);
const QStringList &userButtons() const;
void setUserButtons(const QStringList &newUserButtons);
signals:
void standardButtonsChanged();
void buttonClicked(int);
void accepted();
void applied();
void discarded();
void helpRequested();
void rejected();
void reset();
private:
QQmlApplicationEngine * m_engine = nullptr;
QQuickWindow* m_mainWindow = nullptr;
QQuickItem* m_item = nullptr;
QQuickView* m_view = nullptr;
QString m_title = QString();
QString m_text = QString();
QString m_addInfo = QString();
QFlags<StandardButton> m_standardButtons = QFlags<StandardButton>(StandardButton::Ok|StandardButton::Cancel);
QStringList m_userButtons;
int m_clickedButton = StandardButton::NoButton;
QObject* m_qmlObject = nullptr;
bool m_modal = true;
int m_width;
int m_height;
ClosePolicyFlags m_closePolicy = ClosePolicyFlag::NoAutoClose;
};
Q_DECLARE_METATYPE(UserInteractionBox::StandardButton)
Q_DECLARE_METATYPE(QFlags<UserInteractionBox::StandardButton>)
Q_DECLARE_OPERATORS_FOR_FLAGS(UserInteractionBox::StandardButtons)
Q_DECLARE_METATYPE(UserInteractionBox::ClosePolicyFlag)
Q_DECLARE_METATYPE(QFlags<UserInteractionBox::ClosePolicyFlag>)
Q_DECLARE_OPERATORS_FOR_FLAGS(UserInteractionBox::ClosePolicyFlags)
#endif // USERINTERACTIONBOX_H
Implementation: userinteractionbox.cpp:
#include "userinteractionbox.h"
void UserInteractionBox::buttonClickedSlot(int buttonNr) {
m_clickedButton = buttonNr;
emit buttonClicked(buttonNr);
switch (buttonNr) {
case Ok : emit accepted(); close(); break;
case Open : emit accepted(); close(); break;
case Save : emit accepted(); close(); break;
case Cancel : emit rejected(); close(); break;
case Close : emit rejected(); close(); break;
case Discard : emit discarded(); close(); break;
case Apply : emit applied(); break;
case Reset : emit reset(); break;
case RestoreDefaults : emit reset(); break;
case Help : emit helpRequested(); break;
case SaveAll : emit accepted(); close(); break;
case Yes : emit accepted(); close(); break;
case YesToAll : emit accepted(); close(); break;
case No : emit rejected(); close(); break;
case NoToAll : emit rejected(); close(); break;
case Abort : emit rejected(); close(); break;
case Retry : emit accepted(); close(); break;
case Ignore : emit accepted(); close(); break;
case NoButton : break;
}
}
UserInteractionBox::UserInteractionBox(QQuickView *view, QString title, QString text) {
m_view = view;
Q_ASSERT(m_view);
m_engine = qobject_cast<QQmlApplicationEngine *>(m_view->engine());
Q_ASSERT(m_engine);
m_mainWindow = qobject_cast<QQuickWindow*>(m_engine->rootObjects().value(0));
Q_ASSERT(m_mainWindow);
m_height = m_mainWindow->height()*3/5;
m_width = m_mainWindow->width()*3/5;
m_title = title;
m_text = text;
}
void UserInteractionBox::open() {
close(); // just in case
QQmlComponent boxComp( m_engine, QUrl( "qrc:/UserInteractionBox.qml" ) );
if (!boxComp.errorString().isEmpty()) {
qDebug()<<boxComp.errorString();
}
Q_ASSERT(boxComp.errorString().isEmpty());
Q_ASSERT(!boxComp.isNull()); if (boxComp.isNull()) return;
QVariantMap initialProperties;
initialProperties["parent"] = QVariant::fromValue(m_mainWindow->contentItem());
initialProperties["title"] = m_title;
initialProperties["text"] = m_text;
initialProperties["modal"] = m_modal;
initialProperties["width"] = m_width;
initialProperties["height"] = m_height;
initialProperties["initStandardButtons"] = QVariant::fromValue(int(m_standardButtons));
initialProperties["userButtons"] = QVariant::fromValue(m_userButtons);
initialProperties["closePolicy"] = QVariant::fromValue(int(m_closePolicy));
QQmlContext *ctxt = m_view->rootContext();
m_qmlObject = boxComp.createWithInitialProperties(initialProperties,ctxt);
Q_ASSERT(m_qmlObject); if (!m_qmlObject) return;
bool standardConnect =
QObject::connect(m_qmlObject,SIGNAL(standardButtonClicked(int)), this, SLOT(buttonClickedSlot(int)),Qt::UniqueConnection);
Q_ASSERT(standardConnect);
bool userConnect =
QObject::connect(m_qmlObject,SIGNAL(userButtonClicked(int)), this, SLOT(buttonClickedSlot(int)),Qt::UniqueConnection);
Q_ASSERT(userConnect);
QMetaObject::invokeMethod(m_qmlObject, "open");
}
QFlags<UserInteractionBox::StandardButton> UserInteractionBox::standardButtons() {
return m_standardButtons;
}
void UserInteractionBox::setStandardButtons(QFlags<StandardButton> flags) {
m_standardButtons = flags;
}
void UserInteractionBox::close()
{
if (m_qmlObject) {
QMetaObject::invokeMethod(m_qmlObject, "close");
m_qmlObject->deleteLater();
m_qmlObject = nullptr;
}
}
int UserInteractionBox::clickedButton() const
{
return m_clickedButton;
}
bool UserInteractionBox::modal() const
{
return m_modal;
}
void UserInteractionBox::setModal(bool newModal)
{
m_modal = newModal;
}
int UserInteractionBox::width() const
{
return m_width;
}
void UserInteractionBox::setWidth(int newWidth)
{
m_width = newWidth;
}
int UserInteractionBox::height() const
{
return m_height;
}
void UserInteractionBox::setHeight(int newHeight)
{
m_height = newHeight;
}
const UserInteractionBox::ClosePolicyFlags &UserInteractionBox::closePolicy() const
{
return m_closePolicy;
}
void UserInteractionBox::setClosePolicy(const ClosePolicyFlags &newClosePolicy)
{
m_closePolicy = newClosePolicy;
}
const QStringList &UserInteractionBox::userButtons() const
{
return m_userButtons;
}
void UserInteractionBox::setUserButtons(const QStringList &newUserButtons)
{
m_userButtons = newUserButtons;
}
Now I can call it like this:
auto box = new UserInteractionBox(m_view, "Some Title", "Some information\n\nSoSome question");
box->setStandardButtons(UserInteractionBox::StandardButton::YesToAll | UserInteractionBox::StandardButton::Cancel);
bool connect = QObject::connect(box, SIGNAL(accepted()), this, SLOT(someSlot()), Qt::UniqueConnection);
Q_ASSERT(connect);
box->open();
I hope this code is not all too bad, I am only a hobby programmer. Perhaps it may be useful for people having a similar problem.