When developing a QML application I think it can sometime be useful if I was able to set some setting to outline all visual elements boundaries. For instance a control in Qt Quick Controls 2.x might consist of several parts like background, contentItem, indicators etc. When tweaking on the size of these I would like to see the boundaries of each of these parts.
Is there any functionality like this in Qt/QML?
Three years later, and folks (specifically: me) are still doing web searches about this :)
Just like commenter #DuKes0mE suggested, I have "made do" by adding borders to things on-the-fly and then removing them from the final code.
Like the OP, I am now tired of doing that.
A tactic I arrived at recently is to add a DebugRectangle.qml custom element to my project:
import QtQuick 2.12
Rectangle {
property var toFill: parent // instantiation site "can" (optionally) override
property color customColor: 'yellow' // instantiation site "can" (optionally) override
property int customThickness: 1 // instantiation site "can" (optionally) override
anchors.fill: toFill
z: 200
color: 'transparent'
border.color: customColor
border.width: customThickness
}
Then I can add it to existing elements like so, to debug them:
Label {
text: 'Lorem ipsum dolor sit amet'
}
Label {
text: 'quis nostrud exercitation'
DebugRectangle {} // Adds "debug border" to this Label
}
And when I am finished, I can even leave the nested DebugRectangle in the code, but toggle its visibility like so:
Label {
text: 'quis nostrud exercitation'
DebugRectangle {
visible: false
}
}
Complete sample project shared on GitHub.
There's a tool called GammaRay which (amongst other things) allows investigating QtQuick 2 applications, see:
http://doc.qt.io/GammaRay/gammaray-qtquick2-inspector.html
Setup instructions are here:
https://github.com/KDAB/GammaRay
If you're running Linux, it is quite likely your distribution already ships a GammaRay package.
Related
I'm learning to work with QML and Qt Quick Controls 2 and try to figure out how to write "proper" applications with it (endgame is a small prototype for embedded devices).
One thing I'm missing is a simple and explicit way to build multi-page applications: there is StackView, TabView and SwipeView, but there is nothing like SimpleView, a component that I could put Page components into and then switch them via custom actions. Currently, I'm mis-using the SwipeView to achieve something similar, by setting interactive property to false, but I have to wonder whether this is a proper way.
So, which is the most generic "page container" component in Qt Quick Controls 2?
Take a look at StackLayout from Qt Quick Layouts. It's a stack of arbitrary items, where you can control the index of the currently visible item.
StackLayout {
anchors.fill: parent
currentIndex: 1
Page {
// ...
}
Page {
// ...
}
}
I'm programming a small PoC in QML. In a couple of places in my code I need to bind to/query global mouse position (say, mouse position in a scene or game window). Even in cases where mouse is outside of MouseAreas that I've defined so far.
Looking around, the only way to do it seems to be having whole screen covered with another MouseArea, most likely with hovering enabled. Then I also need to deal with semi-manually propagating (hover) events to underlying mouseAreas..
Am I missing something here? This seems like a pretty common case - is there a simpler/more elegant way to achieve it?
EDIT:
The most problematic case seems to be while dragging outside a MouseArea. Below is a minimalistic example (it's using V-Play components and a mouse event spy from derM's answer). When I click the image and drag outside the MouseArea, mouse events are not coming anymore so the position cannot be updated unless there is a DropArea below.
The MouseEventSpy is taken from here in response to one of the answers. It is only modified to include the position as parameters to the signal.
import VPlay 2.0
import QtQuick 2.0
import MouseEventSpy 1.0
GameWindow {
id: gameWindow
activeScene: scene
screenWidth: 960
screenHeight: 640
Scene {
id: scene
anchors.fill: parent
Connections {
target: MouseEventSpy
onMouseEventDetected: {
console.log(x)
console.log(y)
}
}
Image {
id: tile
x: 118
y: 190
width: 200
height: 200
source: "../assets/vplay-logo.png"
anchors.centerIn: parent
Drag.active: mausA.drag.active
Drag.dragType: Drag.Automatic
MouseArea {
id: mausA
anchors.fill: parent
drag.target: parent
}
}
}
}
You can install a eventFilter on the QGuiApplication, where all mouse events will pass through.
How to do this is described here
In the linked solution, I drop the information about the mouse position when emitting the signal. You can however easily retrieve the information by casting the QEvent that is passed to the eventFilter(...)-method into a QMouseEvent and add it as parameters to the signal.
In the linked answer I register it as singleton available in QML and C++ so you can connect to the signal where ever needed.
As it is provided in the linked answer, the MouseEventSpy will only handle QMouseEvents of various types. Once you start dragging something, there won't be QMouseEvents but QDragMoveEvents e.t.c. Therefore you need to extend the filter method, to also handle those.
bool MouseEventSpy::eventFilter(QObject* watched, QEvent* event)
{
QEvent::Type t = event->type();
if (t == QEvent::MouseButtonDblClick
|| t == QEvent::MouseButtonPress
|| t == QEvent::MouseButtonRelease
|| t == QEvent::MouseMove) {
QMouseEvent* e = static_cast<QMouseEvent*>(event);
emit mouseEventDetected(e->x(), e->y());
}
if (t == QEvent::DragMove) {
QDragMoveEvent* e = static_cast<QDragMoveEvent*>(event);
emit mouseEventDetected(e->pos().x(), e->pos().y());
}
return QObject::eventFilter(watched, event);
}
You can then translate the coordinates to what ever you need to (Screen, Window, ...)
As you have only a couple of places where you need to query global mouse position, I would suggest you to use mapToGlobal or mapToItem methods.
I believe you can get cursor's coordinates from C++ side. Take a look on answer on this question. The question doesn't related to your problem but the solution works as well.
On my side I managed to get global coordinates by directly calling mousePosProvider.cursorPos() without any MouseArea.
I'm trying to dynamically change some field color when it has changed due to some processing.
CUBA documentation explains how to do it statically through web theme extension (https://doc.cuba-platform.com/manual-6.2/web_theme_extension.html), but not dynamically. Although it is possible in Vaadin (https://vaadin.com/wiki/-/wiki/Main/Dynamically%20injecting%20CSS) on which platform web gui is built upon.
I suppose that if I use the Vaadin way of injecting CSS it will work (which I will try) but I will then have Vaadin specific code, which I'm trying to avoid.
Is there a CUBA way of doing so I'm missing ?
Edit:
I'm trying to have any field of a form to change background color when it has changed from its initial value. As per CUBA documentation (https://doc.cuba-platform.com/manual-6.2/web_theme_extension.html) I need to :
- create a SCSS mixin with background color
- inject the field in the editor class in order to have access to it
- react to a field change event and then define the style name of the field
I did create the SCSS mixin, but two issues I have :
1) I would like to retrieve the field instance dynamically instead of injecting it (keep code clean and light)
2) I would like to avoid defining the background color statically so that the color could be parameterized at runtime
For 1) I tried to injected the fieldGroup and used getFieldComponent(), then applied the style with setStyleName on it when it is changed. It worked but I would prefer to define this behavior for every field that is an input field.
For 2) apart from using Vaadin specific feature of injecting CSS (and tighing my code to Vaadin (and so leading me away of generic interface) I do not see how to do
Hope it's more clear
You cannot set truly dynamic color (any RGBA) from code to field but you can create many predefined colors for your field:
#import "../halo/halo";
#mixin halo-ext {
#include halo;
.v-textfield.color-red {
background: red;
}
.v-textfield.color-blue {
background: blue;
}
.v-textfield.color-green {
background: green;
}
}
I do not recommend using styles injected from code (as Vaadin Page does) since it is a mixing of logic and presentation. Instead you can create all predefined styles (30-50 styles should be enough) and assign it depending on some conditions using setStyleName method:
public class ExtAppMainWindow extends AppMainWindow {
#Inject
private TextField textField;
private int steps = 0;
public void changeColor() {
if (steps % 2 == 0) {
textField.setStyleName("color-red");
} else {
textField.setStyleName("color-blue");
}
steps++;
}
}
If you want to apply the logic of color change for all TextFields inside of FieldGroup you can iterate FieldGroup fields in the following way:
for (FieldGroup.FieldConfig fc : fieldGroup.getFields()) {
Component fieldComponent = fieldGroup.getFieldComponent(fc);
if (fieldComponent instanceof TextField) {
TextField textField = (TextField) fieldComponent;
textField.addValueChangeListener(e ->
textField.setStyleName("color-red")
);
}
}
Created a graph using cytoscape.js. Need to add image as a label on edge.
After examination of
CanvasRenderer.drawElements in https://github.com/cytoscape/cytoscape.js/blob/v2.3.8/src/extensions/renderer.canvas.drawing-redraw.js#L406-L412
CanvasRenderer.drawEdgeText in https://github.com/cytoscape/cytoscape.js/blob/v2.3.8/src/extensions/renderer.canvas.drawing-label-text.js#L6-L31
CanvasRenderer.drawEdge in https://github.com/cytoscape/cytoscape.js/blob/v2.3.8/src/extensions/renderer.canvas.drawing-edges.js
it seems that image label on edge is not supported right now.
One candidate where this feature might be added seems to be the CanvasRenderer.drawEdgeText function. The implementation might examine the text contained in the edge's content and if it looks like reference to an image (e.g. url) then draw it as image...
https://github.com/cytoscape/cytoscape.js/blob/v2.3.8/README.md
Contributing to Cytoscape.js
Cytoscape.js is an open source project, and anyone interested is encouraged to contribute to Cytoscape.js. We gladly accept pull requests. If you are interested in regular contributions to Cytoscape.js, then we can arrange granting you permission to the repository by contacting us.
If your pull request is a bugfix, please make changes to the master branch. Otherwise, please make changes to the next version's branch (i.e. unstable).
I know this is a late answer. but this will help somebody who looks for an answer as like me.
We can use icon fonts or fontawesome for this.
set the edges data as
edges = {
data:
id: "3f5cb5c4-43aa-4f4d-b816-fb4f279585c7"
label: "1 A \uf023 \uf022" //this is the fontawesome unicode chars for lock and notes icons
source: "1"
sourceName: "shipping"
target: "4"
targetName: "twilio.com"
value: 2
}
next in your cytoscape style, mention the font as fontawesome
{
selector: '.autorotate',
style: {
'edge-text-rotation': 'autorotate',
'font-size': '8px',
// 'color': '#000000',
'color': '#333333',
'font-family': 'FontAwesome, helvetica neue Cantarell',
'text-margin-x':'5px',
'text-margin-y':'5px',
// 'source-text-margin-x':'5px',
// 'source-text-margin-y':'5px'
}
}
Now your cytoscape graph will show edges with images as like this
How to change plain line to arrow line in infovis?
Currently there are some lines between blocks, I found some css files, but I cannot find which content describing the line behaviour such that I can change the plain line to arrow line.
Thanks.
Generally spoken: You can't (and shouldn't) change it via CSS. Define such properties during the setup.
Here's a brief explanation:
The Code that generates and Edge (which is a line in network visualizations) is generated by the Edge method/function which sits inside Options.Edge.js.
The function Edge is a property/module of the $jit object and works like this:
var viz = new $jit.Viz({
Edge: {
overridable: true,
type: 'line',
color: '#fff',
CanvasStyles: {
: '#ccc',
shadowBlur: 10
}
}
} );
It's important that you define overridable as true as you else can't override anything. The parameter that you're searching for is type. The allowed values are line, hyperline, arrow and I'm pretty sure that bezier will work as well - not sure if this is true for every type of graph. You can as well define custom graph Edge types - an example is missing in the documentation.
To change the Line/Edge style, there's another function that triggers before rendering. You just have to define it during the graph registration $jit.Viz( { /* add here */ } ); - code from the example/Spacetree here:
// This method is called right before plotting
// an edge. It's useful for changing an individual edge
// style properties before plotting it.
// Edge data proprties prefixed with a dollar sign will
// override the Edge global style properties.
onBeforePlotLine: function(adj){
if (adj.nodeFrom.selected && adj.nodeTo.selected) {
adj.data.$color = "#eed";
adj.data.$lineWidth = 3;
}
else {
delete adj.data.$color;
delete adj.data.$lineWidth;
}
}
The final step would now be to inspect what add.data can deliver and then either add the style you want or define a new one using a closure.
There might be another way to go on this: Example for a ForceDirected graph. Take a look at the documentation here.
$jit.ForceDirected.Plot.plotLine( adj, canvas, animating );
Maybe you could even use something like this:
var edge = viz.getEdge('Edge_ID');
edge.setData( property, value, type );
Disclaimer: I got no working copy of theJit/InfoViz library around, so I can't help more than that unless you add a JSFiddle example with your code.
Edit
As I just read that you only want to change to the default arrow type, just enter this type during the configuration of the graph.