Close Sheet with signal from C++ in Blackberry Cascades - c++

I have a UI for some decryption software that gets invoked from the mail client on an encrypted attachment.
My decryption object emits a signal on successful completion of the decryption :
emit decryptedChanged();
which I pass through my controller object (attached as _encryptedattachmentencryptedattachment to the QML UI:
connect(m_decryptor, SIGNAL(decryptedChanged()), this, SIGNAL(decryptedChanged()));
I have a Sheet which is shown on invocation on an encrypted file: when the UI is initialised:
onCreationCompleted: {
splashscreen.open();
}
(at the end of my TabbedPane, before the attachedObjects where the Sheet is.)
I am trying to get the Sheet to close based on the signal.
Sheet {
id: splashscreen
peekEnabled: false
Page {
Container {
layout: DockLayout {
}
ImageView {
horizontalAlignment: HorizontalAlignment.Fill
verticalAlignment: VerticalAlignment.Fill
imageSource: "asset:///images/background.png"
}
Label {
horizontalAlignment: HorizontalAlignment.Fill
verticalAlignment: VerticalAlignment.Center
text: "Decrypting..."
multiline: true
}
}
}
onCreationCompleted: {
_encryptedattachment.decryptedChanged.connect(splashscreen.onDecryptedChanged());
}
function onDecryptedChanged () {
splashscreen.close();
}
}
The splashscreen will not close. I know the object can be seen by the UI, as I use other properties etc. Am I missing a QPROPERTY or something?
Update:
This is my signal definition:
Q_INVOKABLE void decryptedChanged();
Update again:
I have added some console.logs to the QML:
onCreationCompleted: {
_encryptedattachment.decryptedChanged.connect( splashscreen.onDecryptedChanged() );
console.log("connected");
}
function onDecryptedChanged() {
console.log("closing");
splashscreen.close();
}
This gives me the following ouptut:
closing
connected
which is backwards, and the splashscreen does not close.

The problem is in this line:
_encryptedattachment.decryptedChanged.connect( splashscreen.onDecryptedChanged() );
the parentheses after the onDecryptedChanged mean that that function is called, not connected to.
_encryptedattachment.decryptedChanged.connect( splashscreen.onDecryptedChanged );
works fine.

Related

Return from child qml to main one

I have several QML files, main one is the one that opens the ApplicationWindow when ever I try to get back from child QML to main, new window is opened again!
how can I prevent of doing this?
I thought that enabling a flag in child QML, but there may be other ways!
I tried stackview in QML
Is there any way to prevent from opening new page when I get back to main QML?
create a loader in main window and call every page into that loader when ever you need to change page just change loader's source
Window {
Loader{
id:myLoader
anchors.fill: parent
source: "LoginPage.qml"
}
Connections{
target: myLoader.item
onBack_clicked:{
loginid = ""
myLoader.source = "LoginPage.qml"
}
onSetting_clicked:{
myLoader.source = "Setting.qml"
}
}
}
and for child qml files : (for me Setting.qml)
Item {
signal back_clicked()
Button {
id: button1
anchors.right: parent.right
anchors.rightMargin: 15
onClicked: {
back_clicked()
}
}
}
but if you want to not destroy old page use SwipeView Or StackView:
SwipeView {
id: swipeView
clip: true
currentIndex: 0
Item{
id:firstPage
clip:true
//your page
}
Item{
id:secondPage
clip:true
//your page
}
}
and to change pages just change currentIndex
swipeView.currentIndex = 1
UPDATE:
StackView {
id: stackView
initialItem: one
}
Component {
id: one
Item{//your first page }
}
Component {
id: two
Item{//your second page }
}
and to push your pages :
stackView.push({ item: two})
//or
stackView.push("MySecondView.qml")
to get back to old or main page just pop it :
stackView.pop()

QML signals connecting

I started writing application in QML (using QtQuick 1.1 with Qt 4.8.1) and I have a few questions about signals. In my project there are following files:
main.qml:
Rectangle {
signal sigExit()
width: 800
height: 600
Text {
text: qsTr("Hello World")
anchors.centerIn: parent
}
MouseArea {
anchors.fill: parent
onClicked: {
sigExit();
Qt.quit();
}
}
Button
{
x: 10
y: parent.height-height-5
text: "someText"
}
}
Button.qml:
Rectangle {
signal buttonsig()
width: 60
//(...)
MouseArea
{
anchors.fill: parent
onClicked: buttonsig();
}
}
When I want to connect signal from main.qml to C++ slot, I do:
main.cpp :
QmlApplicationViewer viewer;
viewer.setOrientation(QmlApplicationViewer::ScreenOrientationAuto);
viewer.setMainQmlFile(QLatin1String("qml/MyProject/main.qml"));
viewer.showExpanded();
MyClass* obj = new MyClass;
QObject* item = qobject_cast<QObject*>(viewer.rootObject());
QObject::connect(item, SIGNAL(sigExit()), obj, SLOT(onExitWindow()));
and it works. But what when I want to connect sigbutton() from Button.qml to C++ slot? It will be something like that?
QObject *rect = item->findChild<QObject*>("Button");
QObject::connect(rect, SIGNAL(buttonsig()), obj, SLOT(onExitWindow()));
And the second issue: how can I connect sigbutton() to main.qml (for example, I want to change position of my buttons after clicking them)?
You will also need to have the objectName property of your Button item if you want to access it :
Button {
id: myButton
objectName: "myButton"
x: 10
y: parent.height-height-5
text: "someText"
}
Now you can access it by :
QObject *rect = item->findChild<QObject*>("myButton");
Regarding the second question, you can use Connections object to connect buttonsig() to some QML signal handler in main.qml :
Rectangle {
signal sigExit()
width: 800
height: 600
Connections{
target: myButton
onButtonsig :
{
...
}
}
Text {
text: qsTr("Hello World")
anchors.centerIn: parent
}
MouseArea {
anchors.fill: parent
onClicked: {
sigExit();
Qt.quit();
}
}
Button
{
id: myButton
x: 10
y: parent.height-height-5
text: "someText"
}
}
Note that the signal handler's name should be on<Signal> (First letter of signal letter Capital). Also Button should have an id to address it in Connections.
Accessing loaded qml elements, casting them and connecting their signals to your C++ slots is perferctly possible. But this method should be avoided in your production code.
See this warning from Qt docs.
So what's the way to call a C++ slot from qml side? You can register the object whose slot needs to be called with qml engine as a context property. Once registered, these context properties can be accessed anywhere from QML side.
Slots of objects registered as context properties can be called directly in your signal handler in QML example: onClicked:{<contextPropertyName>.<slotName>()}
Or, you can connect a QML signal with context property object's slot directly using Connections type. Please see this documentation
For details about registering context properties, please see Embedding C++ objects into QML with context properties.
If you want to see some examples, see my answers to these questions.
Qt Signals and Slots - nothing happens and Setting object type property in QML from C++

BB10 - Change QML Header Title from C++

I'm pretty new to C++ and QML, so sort of trying to teach myself the way! I am trying to change the "title" property of a QML Header object. I am currently developing my app off the back off the pushCollector cascades example on GitHub.
I've read elsewhere that I can assign a property alias and do it that way;
NavigationPane {
id: navPane
property alias connectionText:connectionStatus.title
Page {
Container {
Header {
id: connectionStatus
title: "Connection Status:"
verticalAlignment: VerticalAlignment.Bottom
bottomMargin: 0.0
topMargin: 0.0
visible: true
subtitle: ""
}
My question is, how do I make a void function that can dynamically change the title whenever I call the function. I need something like;
void App:changeConnectionText(const QString new Text)
{
//change object title in QML
}
Thanks!
Add this in .cpp
#include <bb/cascades/Header>
You access like this:
void ApplicationUI::changeConnectionText(QString Text) {
Header* myheader = Application::instance()->scene()->findChild<Header*>("connectionStatus");
myheader->setTitle(Text);
}
And you call it like this (in cpp):
changeConnectionText("Yay, connected!");
And QML
Header {
id: connectionStatus
objectName: "connectionStatus" //add this!!!
title: "Connection Status:"
verticalAlignment: VerticalAlignment.Bottom
bottomMargin: 0.0
topMargin: 0.0
visible: true
subtitle: ""
}
Tested, it works

NavigationPane pop from C++ BB10

I'm right now creating my app only in C++, i creating the NavigationPane and adding the container with the Views i need. It works fine, but i want to capture a Button clicked to make the NavigationPane pop the current page and push a diferent (made in runtime) Page.
How can it be achieved, i tried working with the signals, but i think i'm not getting how it works the signals and the QT_SLOTS, in the case of the NavigationPane, it doesn't have those methods as QT_SLOT.
Any advice will be appreciated.
You first need to connect the clicked() signal of your Button to the pop() slot of your NavigationPane. It should look like this:
// Connect the button's clicked() signal to the navigation pane's
// pop() slot.
bool connectResult = QObject::connect(myButton,
SIGNAL(clicked()),
myPane,
SLOT(pop()));
// Use the Q_ASSERT() function to test the return value and
// generate a warning message if the signal slot connection
// wasn’t successful.
Q_ASSERT(connectResult);
// Indicate that the variable connectResult isn't used in the
// rest of the app to prevent a compiler warning.
Q_UNUSED(connectResult);
This page about buttons might help you understand how to handle this. To better understand how to connect objects together, you might also want to have a look at a the signals and slots documentation.
You then have to create and push your new page after the pop. To do that, you simply have to connect the popTransitionEnded (bb::cascades::Page *page) slot of your NavigationPane to your custom function that will do the job.
bool connectResult = QObject::connect(myPane,
SIGNAL(popTransitionEnded(bb::cascades::Page*)),
this,
SLOT(createNewPageAndPushIt(bb::cascades::Page*)));
Q_ASSERT(connectResult);
Q_UNUSED(connectResult);
See this page for more details about the usage of NavigationPane to stack pages.
---------------------TRY THIS-------------
Get sample app from my github samples for your query....
https://github.com/svmrajesh/BB-10-Cascades/tree/master/MY%20APPS/stackNavigation
main.qml: (first page)
import bb.cascades 1.0
NavigationPane {
id: navigationPane
backButtonsVisible: false
peekEnabled: false
Page
{
id: rootPage
Container {
background: Color.LightGray
layout: DockLayout {
}
Label {
text: "First page"
horizontalAlignment: HorizontalAlignment.Center
verticalAlignment: VerticalAlignment.Center
}
}
actions: [
ActionItem {
title: "Next page"
ActionBar.placement: ActionBarPlacement.OnBar
onTriggered: {
var page = pageDefinition.createObject();
navigationPane.push(page);
}
attachedObjects: ComponentDefinition {
id: pageDefinition
source: "PageTwo.qml"
}
}
]
}
onPopTransitionEnded: {
page.destroy();
}
}
2.second page
import bb.cascades 1.0
Page {
id: pageTwo
Container {
background: Color.Gray
layout: DockLayout {
}
Label {
text: "Second page"
horizontalAlignment: HorizontalAlignment.Center
}
Container {
layout: StackLayout {
}
horizontalAlignment: HorizontalAlignment.Center
verticalAlignment: VerticalAlignment.Center
Button {
text: qsTr("Next Page")
imageSource: "asset:///images/picture1thumb.png"
onClicked: {
// show detail page when the button is clicked
var page = getSecondPage();
console.debug("pushing detail " + page)
navigationPane.push(page);
}
property Page secondPage
function getSecondPage() {
if (! secondPage) {
secondPage = secondPageDefinition.createObject();
}
return secondPage;
}
attachedObjects: [
ComponentDefinition {
id: secondPageDefinition
source: "PageTwoOne.qml"
}
]
}
Button {
text: "Previous Page"
onClicked: {
navigationPane.pop();
}
}
}
}
/* ------------- Use this Code If back button visibility is "True"-----------------
paneProperties: NavigationPaneProperties {
backButton: ActionItem {
title: "Back"
// imageSource: "asset:///back.png"
onTriggered: {
navigationPane.pop();
}
}
} */
}
3.last page
import bb.cascades 1.0
Page {
id: pageTwoone
Container {
background: Color.DarkGray
layout: DockLayout {}
Label {
horizontalAlignment: HorizontalAlignment.Center
text: "Last Page"
}
Container {
layout: StackLayout {}
horizontalAlignment: HorizontalAlignment.Center
verticalAlignment: VerticalAlignment.Center
Button {
horizontalAlignment: HorizontalAlignment.Center
verticalAlignment: VerticalAlignment.Center
text: qsTr("Goto Home Page")
onClicked: {
// show detail page when the button is clicked
navigationPane.navigateTo(rootPage);
}
}
Button {
horizontalAlignment: HorizontalAlignment.Center
verticalAlignment: VerticalAlignment.Center
text: qsTr("Goto Back")
onClicked: {
// show detail page when the button is clicked
navigationPane.pop();
}
}
}
}
}
------------ ADD More pages to navigate using this code----------------------------
-------------copy this code and run.. get sample app from above link if needed ------
Have you checked this?
https://developer.blackberry.com/native/reference/cascades/bb__cascades__navigationpane.html
NavigationPane* navigationPane; // Global var to change current Page with push/pop
void initializeNavigationPane()
{
ActionItem* nextAction = ActionItem::create()
.title("Next page")
.onTriggered(this, SLOT(pushPage()));
navigationPane = NavigationPane::create();
QObject::connect(navigationPane, SIGNAL(popTransitionEnded(bb::cascades::Page*)),
this, SLOT(popFinished(bb::cascades::Page*)));
// Put a new page
navigationPane->push(Page::create()
.content(Label::create("First page"))
.addAction(nextAction, ActionBarPlacement::OnBar));
Application::instance()->setScene(navigationPane);
}
void popFinished(bb::cascades::Page* page){
delete page;
}
//You have to connect this method when you want a new Page pushed.
Q_SLOT void pushPage(){
ActionItem* backAction = ActionItem::create()
.title("Previous page")
.imageSource(QUrl("asset:///back.png"))
.onTriggered(navigationPane, SLOT(pop()));
navigationPane->push(Page::create()
.content(Label::create("Second page"))
.paneProperties(NavigationPaneProperties::create()
.backButton(backAction)));
}
Explication:
An instance of the object NavigationPane allows change the current page to others with the push/pop effect (see image):
developer.blackberry.com/native/files/reference/cascades/images/navigation_pane_push_pop.png
You have to inicialice with:
navigationPane = NavigationPane::create();
And tell to the Application you will use this instance to change page:
Application::instance()->setScene(navigationPane);
Now you app got a NavigationPane, but nothing is inside, if you run it, you will get a black screen, to add a page (the principal page - page0) use push:
navigationPane->push(Page::create()
.content(Label::create("First page")));
To add a new Page that It can go back to the page0 we just push use Push again, Remeber include the back button to go back:
navigationPane->push(Page::create()
.content(Label::create("Second page"))
.paneProperties(NavigationPaneProperties::create()
.backButton(ActionItem::create()
.title("Previous page")
.imageSource(QUrl("asset:///back.png")) //You should add manually this image.
.onTriggered(navigationPane, SLOT(pop()))));
Q_INVOKABLE void insert (intindex, bb::cascades::Page *page )
https://developer.blackberry.com/native/reference/cascades/bb__cascades__NavigationPane.html#function-insert-index-page
Inserts a page at a specified index in the NavigationPane.
The page that is passed must not be 0 or it will be ignored. If the
page is already present in the navigation stack, the operation will
fail. This operation will not trigger a transition effect, even if the
page is added to the top of the stack. If a transition effect is
desired, use push() instead. The topChanged() signal will be emitted
if the operation affects the top node.
Parameters
1- index
The index where the page will be placed. If the index < 0 the the page is inserted in the bottom. If the index > the number of pages in the navigation stack, it is added on top of the stack.
2- page
The page to be inserted, must not be 0.
Since: BlackBerry 10.0.0
An idea is
You could use:
navigationPane.count() To get the current pages in the nagationPane stack, and use:
navigationPane.insert(navigationPane.count()-1, myPageToBeBack); To push a page between the current page and
the previous one

Implementing the back button on bb10

I have one navigation pane and I disabled the back button in the main.qml, however I want to display the back button again to some part of the app. How do i implement this? here's my cpp
pane = qml->createRootObject<NavigationPane>();
// Set created root object as the application scene
app->setScene(pane);
qml->setContextProperty("cppObj", this);
}
void ApplicationUI::onLoginClicked() {
// create scene document from buttonclicked.qml asset
// set parent to created document to ensure it exists for the whole application lifetime
QmlDocument *qml = QmlDocument::create("asset:///projects.qml").parent(this);
qml->setContextProperty("cppObj", this);
Page* root = qml->createRootObject<Page>();
pane->push(root);
}
void ApplicationUI::onAddClicked() {
// create scene document from buttonclicked.qml asset
// set parent to created document to ensure it exists for the whole application lifetime
QmlDocument *qml = QmlDocument::create("asset:///addprojects.qml").parent(this);
Page* root = qml->createRootObject<Page>();
pane->push(root);
}
and here's my main where I disabled the back button
NavigationPane {
backButtonsVisible: false }
How do i make the back button active to some section of the app?
Let's say you have the following code:
StartPage
import bb.cascades 1.0
NavigationPane {
id: navPane
Page {
Container {
horizontalAlignment: HorizontalAlignment.Fill
verticalAlignment: VerticalAlignment.Fill
layout: DockLayout {
}
Button {
horizontalAlignment: HorizontalAlignment.Center
verticalAlignment: VerticalAlignment.Center
text: "Next Page"
onClicked: {
var nextPage = page.createObject();
navPane.push(nextPage);
}
}
}
}
attachedObjects: [
ComponentDefinition {
id: page
source: "NextPage.qml"
}
]
}
NextPage:
import bb.cascades 1.0
Page {
// disables backButton (not peeking)
paneProperties: NavigationPaneProperties {
backButton: ActionItem {
enabled: false
}
}
// [0]
Container {
horizontalAlignment: HorizontalAlignment.Fill
verticalAlignment: VerticalAlignment.Fill
layout: DockLayout {
}
Button {
horizontalAlignment: HorizontalAlignment.Center
verticalAlignment: VerticalAlignment.Center
text: "Prev page"
onClicked: {
var page = navPane.pop();
if (page)
page.destroy();
}
}
} // [0]
// hides navigation bar
onCreationCompleted: {
navPane.backButtonsVisible = false;
}
}
Then you can completely disable backButton with this code in NextPage.qml
onCreationCompleted: {
navPane.backButtonsVisible = false;
}
Alternatively, if you want to have navigation pane visible but just Back Button disabled, use following in the same NextPage.qml file:
paneProperties: NavigationPaneProperties {
backButton: ActionItem {
enabled: false
}
}
Also, don't forget about peekEnabled property. Using peek BB10 feature user can move between sibling pages using sliding finger movement not touching any buttons on the screen.
It could be done in similar way:
onCreationCompleted: {
navPane.peekEnabled = false;
}
Hope it helps.