I have a component/delegate declared in qml and I would like to connect one o its actions to a signal in another qml or C++ class. So, the Component looks like this:
Component
{
id: mainButtonDelegate
Button {
id: buttonOperation
text: qsTr(buttonText)
buttonEnabled: false
onIsEnableChanged:
{
buttonEnabled = cppRegisteredClass.isButtonEnabled(text)
}
}
}
Can I create connection for the component (so for every button), like the following expressed in Qt?
connect(loginForm, SIGNAL(loginChanged()), this, SLOT(onIsEnableChanged()))
My model is a ListModel expressed in a qml file.
Edit
If this is not the correct approach could somebody suggest me another way to do sth like this?
You can use the Connections-object.
You expression would be translated to:
Connections {
target: loginForm
onLoginChanged: whatIsThis.onIsEnabledChanged()
}
Alternatively you can use the JS connect syntax:
http://doc.qt.io/qt-5/qtqml-syntax-signals.html#connecting-signals-to-methods-and-signals
You expression would translate to:
loginForm.loginChanged.connect(this.onIsEnabledChanged)
I am posting how I have done what I wanted, just if anyone else need this.
I have added a function in the model and used set property.
function action()
{
for(var i= 0; i<count; ++i)
{
if(backend.disable())
{
setProperty(i, "enable", false)
setProperty(i, "opac", 0.3)
}
else
{
setProperty(i, "enable", true)
setProperty(i, "opac", 1)
}
}
}
In the component (inside an Item parent), I have added:
LoginForm{
id: loginForm
onLoginIdentityChanged: {
mymodel.action()
}
Related
Suppose I have a custom CheckBox:
//MyCheckBox.qml
CheckBox {
required property QtObject proxy
checked: proxy.value
Binding {
target: proxy
property: "value"
value: checked
}
}
So the checked status of the MyCheckBox bound to the value property of my object (proxy) and vise-versa, i.e. I have a two-way binding.
I am using my custom checkbox as follows:
//My window
Item {
...
MyCheckBox {
id: ordinaryCheck
proxy: ...
}
...
}
Everything works as expected. But what if I need to invert the logic for some instance of MyCheckBox: when proxy.value is true the checkbox is unchecked, and when proxy.value is false the checkbox is checked ? But this, ofc, doesn't work as I have a binding loop here if I try to do this:
Item {
...
MyCheckBox {
id: invertedCheck
proxy: ...
checked: !proxy.value
Binding {
target: proxy.value
property: "value"
value: !checked
}
}
The Qt bindings are also not an option:
//MyCheckBox.qml
CheckBox {
required property QtObject proxy
checked: proxy.value
Component.onCompleted {
property.value = Qt.binding(function() { return checked });
}
}
I have the same binding loop error in this case.
So what is my option to reach the goal, how to alternate the binding at the moment of instantiation ?
Update 1
Here is my PropertyProxy::setValue member function:
void setValue( const QVariant& v )
{
if( v != value() )
{
//do some stuff
emit valueChanged();
}
}
If you're concerned about a potential binding loop, it is a potential candidate to rewrite it as an imperative implementation, e.g.
CheckBox {
required property QtObject proxy
onCheckedChanged: {
if (proxy && proxy.value !== checked) {
proxy.value = checked;
}
}
property bool proxyValue: proxy && proxy.value ? true : false
onProxyValueChanged: {
if (checked !== proxyValue) {
checked = proxyValue;
}
}
}
Your first version might also technically be a binding loop but is not detected as such.
You want to bind your checkbox value to your proxy value, and when the user toggles the checkbox you want to modify the proxy value.
To avoid binding loops, use specific interaction signals for each component, not generic onChanged signal. The former will fire only when the user interact with the UI, the latter will fire every time, even when the changes come from a backend change, leading to a potential binding loop.
In your case you want the toggled signal:
//MyCheckBox.qml
CheckBox {
required property QtObject proxy
checked: proxy.value
onToggled: proxy.value = checked
}
Note that this only works with QQC2 since they are not breaking the checked: proxy.value binding when the user toggles the checkbox, but still change the checked property value, hoping for an eventual resolution.
I have a Window containing what I called a Page - a Rectangle the size of the main window:
LoginWindow {
id: loginWindow
}
SelectionWindow {
id: selectionWindow
}
ServiceWindow {
id: serviceWindow
}
ConfirmWindow {
id: confirmWindow
}
IssueWindow {
id: issueWindow
}
Each *Window here is an element inheriting from Page.
Now I can jump between different Page elements setting their visibility. Only one Page can be visible at a time. The last Page is IssueWindow and from there I want to switch back to LoginWindow and logout the user.
From C++ I emit a signal issueFinished and in MainWindow I have this code:
onIssueFinished: {
// This line won't hide the Page
issueWindow.visible = false;
loginHandle.logout();
}
As noted in the comment, the Page element just won't hide, while other elements will change their visibility. I am using GammaRay to see the changes and everything works, just hiding the issueWindow doesn't. Also when printing the issueWindow.visible to console, it's false.
Use opacity instead of visibility, and bind one method on opacity change which handle the enabled and disabled state like.
onIssueFinished: {
// This line won't hide the Page
issueWindow.opacity = 0.0;
loginHandle.logout();
}
IssueWindow {
id: issueWindow
onOpacityChanged: {
enabled = ( opacity === 1.0)
}
}
You need to implement opacity change in all the windows.
And set the opacity for all other windows.
Or you can use stack view or swipe view.
Found out the issue was actually incorrect order of switching visibility and firing signals and responding to them.
To make sure only one Page is visible, you might use an index.
You set the visibility to:
visible: (selected == thisPageIdentifier)
With this you make sure, only the page with the corresponding pageIdentifyer is visible, and you don't have to throw around multiple signals to show and hide.
When a new page shall become visible, just set the selected property to the corresponding identifier (int or string or what ever) and the other pages turn invisible.
This should increase scalability as you do not have new signals to handle in all the other pages, if you decide to add a new page once. You only need to make sure, the identifier is unique.
Your example code adjusted to this:
Item {
property int selection: 0
LoginWindow {
id: loginWindow
visible: (selection === 0)
}
SelectionWindow {
id: selectionWindow
visible: (selection === 1)
}
ServiceWindow {
id: serviceWindow
visible: (selection === 2)
}
ConfirmWindow {
id: confirmWindow
visible: (selection === 3)
}
IssueWindow {
id: issueWindow
visible: (selection === 4)
}
}
I'm a newbie to Blackberry 10 development and the whole qt signal-slot mechanism.
I am trying to register a signal and slot for when a user clicks on a different tab in my Blackberry 10 native application. I have the following code for my UI:
TabbedPane {
id: mainTabbedPane
showTabsOnActionBar: true
peekEnabled: true
sidebarState: SidebarState.VisibleFull
Tab {
...
} //End of first tab
Tab {
...
} //End of second tab
...
applicationui.cpp
AbstractPane *appPane = qmlDocument->createRootObject<AbstractPane>();
if (appPane) {
// Set the main application scene to NavigationPane.
Application::instance()->setScene(appPane);
}
TabbedPane* tabbedPane = appPane->findChild<TabbedPane*>("mainTabbedPane");
qDebug("Pane: %p", tabbedPane);
QObject::connect(tabbedPane, SIGNAL(activeTabChanged(bb::cascades::Tab*)), SLOT(sectionTriggered(bb::cascades::Tab*)));
My issue is that it seems the TabbedPane is not being found despite being in the UI. What I'm I doing wrong? Also, I'm I implementing the signal-slot correctly?
Thank you in advance.
You could also use onTriggered in QML, so you can get that this way. Depends on what you want
Tab {
title: "Tab name"
onTriggered: {
}
},
BUT to fix your problem directly, you're missing objectName
TabbedPane {
id: mainTabbedPane
objectName: "mainTabbedPane"
showTabsOnActionBar: true
peekEnabled: true
sidebarState: SidebarState.VisibleFull
Tab {
...
} //End of first tab
Tab {
...
} //End of second tab
I'm new to Qt, and from what I've read on qt-project.org and other places; QtQuick seems like an attractive option because of its ability to work on both pointer and touch based devices. My problem is getting it to work well with c++.
I decided to write a variant of Conway's Game of Life as a next step after "Hello World". I am thoroughly mystified as to how to get the "board" -- a [height][width][bytes-per-pixel] array of char -- integrated into the scene graph.
Basically, the process is that the "LifeBoard" iterates through its rules and updates the char*/image. I've got this simple QML:
:::QML
ApplicationWindow {
id: life_app_window
visible: true
title: qsTr("Life")
menuBar: MenuBar {
Menu {
title: qsTr("File")
MenuItem {
text: qsTr("Quit")
onTriggered: Qt.quit();
}
}
}
toolBar: ToolBar {
id: lifeToolBar;
ToolButton {
id: toolButtonQuit
text: qsTr("Quit")
onClicked: Qt.quit()
}
ToolButton {
id: toolButtonStop
text: qsTr("Stop")
enabled: false
//onClicked:
}
ToolButton {
id: toolButtonStart
text: qsTr("Start")
enabled: true
//onClicked: //Start life.
}
ToolButton {
id: toolButtonReset
text: qsTr("Stop")
// onClicked: //Reset life.
}
}
Flow {
id: flow1
anchors.fill: parent
//*****
// WHAT GOES HERE
//*****
}
statusBar: StatusBar {
enabled: false
Text {
// Get me from number of iterations
text: qsTr("Iterations.")
}
}
}
I want to image to come from a class with a api kinda like this:
class Life {
public:
QImage getImage() {}
// Or
char* getPixels(int h, int w, QImage::Format_ARGB8888) {}
}
I have no clue, and hours wading through tutorials did not help. How does one link a char* image in c++ to a ??? in QML so that the QML can start/stop the "Life" loop and so that the "Life" loop and update the char array and notify QML to redraw it?
Note: I've looked at subclassing QQuickImageProvider based on the info here. The problem with this approach is that I cannot see how to let c++ "drive" the on screen image. I wish to pass control from QML to c++ and let c++ tell QML when to update the display with the changed image. Is there a solution with this approach? Or another approach entirely.
First way to do that would be creating a Rectangle for each game pixel in QML, which might be fancy for a 8x8 board, but not for a 100x100 board, since you need to write the QML code manually for each pixel.
Thus I'd go for images created in C++ and exposed to QML. You call them via an image provider to allow asynchronous loading. Let Life do the logic only.
The image is called from QML like this:
Image {
id: board
source: "image://gameoflife/board"
height: 400
width: 400
}
Now gameoflife is the name of the image provider and board the so-called id you can use later.
Register gameoflife in you main.cpp
LifeImageProvider *lifeIP = new LifeImageProvider(life);
engine.addImageProvider("gameoflife", lifeIP);
where engine is your main QQmlApplicationEngine and life an instance of your Life game engine.
LifeImageProvider is your class to create pixeldata. Starts somehow like
class LifeImageProvider : public QQuickImageProvider
{
public:
LifeImageProvider(Life *myLifeEngine);
QPixmap requestPixmap(const QString &id, QSize *size, const QSize &requestedSize);
private:
Life *myLifeEngine_;
};
The important method is requestPixmap, which is called from QML. You need to implement it.
To refresh the game board when Life sends a stateChanged() signal, expose life as a global object to QML:
context->setContextProperty("life", &life);
You can bind the signal to QML
Image {
id: board
source: "image://gameoflife/board"
height: 400
width: 400
}
Connections {
target: life
onStateChanged: {
board.source = "image://gameoflife/board?" + Math.random()
// change URL to refresh image. Add random URL part to avoid caching
}
}
Just for fun, and at the risk of downvotes for a completely tangential answer, here's a GameOfLife implemented entirely in QML, just put it in a .qml file and run it with qmlscene. Works on Qt 5.3.0, and runs surprisingly (to me) fast on an old Core 2 Duo lappy. I'm sure it'll never be as fast/efficient as a C++ QQuickImageProvider based solution though, but it does make the point it's possible to do quite a lot in QML without resorting to C++.
import QtQuick 2.2
Rectangle {
id: main
width: 640
height: 640
color: '#000088'
Timer {
interval: 1000/60
running: true
repeat: true
onTriggered: {advance();display();}
}
Component {
id: cellComponent
Rectangle {
objectName: 'cell'
property int row: 0
property int col: 0
x: main.width/2+width*col
y: main.height/2+height*row
width: 5
height: 5
radius: 2
smooth: true
color: '#ffcc00'
}
}
property var cells: null
Component.onCompleted: {
cells=[[-1, 0],[-1, 1],[ 0,-1],[ 0, 0],[ 1, 0]];
display();
}
function display() {
// Just completely regenerate display field each frame
// TODO: might be nicer to do differential updates, would allow birth/death animations
// Nuke all previously displayed cells
for (var i=0;i<children.length;i++) {
if (children[i].objectName=='cell') {
children[i].destroy();
}
}
// Show current set of cells
for (var i=0;i<cells.length;i++) {
var c=cellComponent.createObject(
main,
{'row':cells[i][0],'col':cells[i][1]}
);
}
}
function advance() {
// Build a hash of the currently alive cells and a neighbour count (includes self)
var a=new Object;
var n=new Object;
for (var i=0;i<cells.length;i++) {
var p=cells[i]
var r=p[0];
var c=p[1];
if (!(r in a)) a[r]=new Object;
a[r][c]=1;
for (var dr=r-1;dr<=r+1;dr++) {
for (var dc=c-1;dc<=c+1;dc++) {
if (!(dr in n)) n[dr]=new Object;
if (!(dc in n[dr])) n[dr][dc]=0;
n[dr][dc]+=1;
}
}
}
// For all live cells, assess viability
var kill=[];
var stay=[];
for (var r in a) {
for (var c in a[r]) {
if (n[r][c]-1<2 || n[r][c]-1>3)
kill.push([Number(r),Number(c)]);
else
stay.push([Number(r),Number(c)]);
}
}
// For neighbours of live cells, assess potential for births
var born=[];
for (var r in n) {
for (var c in n[r]) {
if (!((r in a) && (c in a[r]))) {
if (n[r][c]==3)
born.push([Number(r),Number(c)]);
}
}
}
cells=stay.concat(born)
}
}
And for a pure QML version using GLSL (via a recursive QML ShaderEffect) to compute the Game of Life rules on GPU see here.
I am currently trying to extend our application with different style.
For each style I have a separate qml file with e.g. color definitions.
StyleA.qml:
import QtQuick 2.0
QtObject {
property color textColorStandard: 'black'
...
}
In my main.qml I would like to load the right qml file, based on a software property:
import QtQuick 2.0
Item {
id: mainPanel
....
Loader {
id: myDynamicStyle
source: Property.UseThemeA? "StyleA.qml" : "StyleB.qml"
}
...
Item {
id: BackGround
color: myDynamicStyle.textColorStandard
}
}
unfortunately this approach does not work. Is there any other/better way to accomplish styling?
thanks, michael
Using things loaded in Loader is badly typed, I would rather :
First, create a common ancestor Component for all my styles, e.g :
// AbstractStyle.qml
import QtQuick 2.0;
QtObject {
property color textColorStandard;
}
Next, derivate it to create custom styles, e.g :
// StyleA.qml
import QtQuick 2.0;
AbstractStyle {
textColorStandard: "blue";
}
// StyleB.qml
import QtQuick 2.0;
AbstractStyle {
textColorStandard: "green";
}
Then use a strongly typed property in my object that must use a style, e.g:
// main.qml
import QtQuick 2.0
Item {
id: base;
Component { id: compoStyleA; StyleA { } }
Component { id: compoStyleB; StyleB { } }
property AbstractStyle currentStyle : {
var tmp = (Property.UseThemeA ? compoStyleA : compoStyleB); // choose component
return tmp.createObject (base); // instanciate it and return it
}
Rectangle {
color: currentStyle.textColorStandard;
}
}
That way, there are multiple advantages :
your code doesn't use Strings to identify components, so errors are easier to find and to avoid ;
you can't affect an item that doesn't inherit your style base class, so you won't encounter "undefined property" errors and won't need ducktyping to figure out which information you have in your style object ;
you don't have Loader so you won't have to suffer the nasty "context isolation" between inside and outside the Loader ;
all components will be preloaded at runtime, gaining speed at instanciation, and allowing you to see from the start if there are syntax errors in the Styles, instead of seeing it only when changing current style ;
last but not least, property auto-completion will work in QtCreator as the actual type will be known by the IDE !
Did you try using this instead? The loaded object is store into the item property of the loader and no in the loader directly.
Item {
id: BackGround
color: myDynamicStyle.item.textColorStandard
}