I'm rendering a custom OpenGL Item, and on top of that I would like to add some widgets.
So far, it's working fine. This is what it looks like.
However, now I am trying to add a Text item to the OpenGL via:
Rectangle{
id: logoTextBox
x: logoButton.x + logoButton.width
y: logoButton.y
width: 200
height: logoButton.height
color: "#EEEEEE"
Text{
id: logoVersionBlurb
y: 10
x: 10
font.pointSize: 8
text: "Ver 1.0"
color: "black"
}
Text{
id: logoNameBlurb
y: 20
x: 10
font.pointSize: 14
font.bold: true
text: "Please work"
}
}
and It looks like this:
I still want the OpenGL to render, but I want the Text to appear overlayed above it. Any ideas?
I'm creating my GLContext like this in QML:
MyGLWidget{
id: glWidget
}
And here is the relevant method from the C++ file
void MyGLWidget::sync()
{
if (!m_renderer) {
m_renderer = new MyGLRenderer();
connect(window(), SIGNAL(beforeRendering()), m_renderer, SLOT(paint()), Qt::DirectConnection);
}
m_renderer->setViewportSize(window()->size() * window()->devicePixelRatio());
}
Okay, I've found a solution. I set the text's renderType to NativeRendering, and that caused the Triangle to render correctly.
Text{
id:sizeDialogXText
color: "white"
y: sizeDialogTitleText.y + 20
x: sizeDialogTitleText.x
text: "X"
font.pointSize: 12
renderType: Text.NativeRendering //This is the important line
}
Related
Okay, I give up. How do I draw backing rectangle around Label?
Here's what I do
import QtQuick 2.0
import QtQuick.Controls 2.15
Label {
id: label
text: root.text
font {
pointSize: 24
bold: true
}
wrapMode: Text.WordWrap
background: Rectangle{
radius: 20
color: "lightgreen"
anchors.centerIn: parent
width: parent.width + 30
height: parent.height + 30
}
}
And that sure draws rounded rect around Label, but the size of the label stays the same, so layout can't position it right. How the heck do I make it work?
I think what you're looking for is padding. Don't add anything to the height/width of the background. Just add padding.
Label {
id: label
text: root.text
font {
pointSize: 24
bold: true
}
wrapMode: Text.WordWrap
padding: 15
background: Rectangle{
radius: 20
color: "lightgreen"
width: parent.width
height: parent.height
}
}
I want to create a chart like this in qt. I already searched and can not find a way to do it.
I also can not find a way to customize Barchart and look like this in Widget Based Applications
Easy in QML!
import QtQuick 2.0
import QtQuick.Layouts 1.1
Rectangle
{
width: 600
height: 300
ListModel
{
id: dataModel
ListElement { label: "C.A"; value: 37 }
ListElement { label: "C.B"; value: 58 }
ListElement { label: "C.C"; value: 16 }
ListElement { label: "C.D"; value: 5 }
ListElement { label: "C.E"; value: 95 }
ListElement { label: "C.F"; value: 10 }
ListElement { label: "C.G"; value: 27 }
ListElement { label: "C.H"; value: 2 }
}
Rectangle
{
height: 4
width: layout.width
anchors.top: layout.bottom
anchors.horizontalCenter: layout.horizontalCenter
color: "#bbbdbe"
}
RowLayout
{
id: layout
width: 400
height: 200
spacing: 0
anchors.centerIn: parent
Repeater
{
id: rpt
property int barWidth: layout.width / count
model: dataModel
delegate:
Rectangle
{
width: rpt.barWidth
height: layout.height
color: "transparent"
Rectangle
{
anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
width: 3
height: (parent.height * value) / 100
color: "#448bbe"
Rectangle
{
color: "#448bbe"
radius: width / 2
width: 8
height: 8
anchors.top: parent.top
anchors.horizontalCenter: parent.horizontalCenter
}
}
Text
{
y: parent.height + 3
anchors.horizontalCenter: parent.horizontalCenter
text: label
}
}
}
}
}
Screenshot
Since the OP didn't specify he wants a solution for a Qt widgets based application [he did after editing the question], the answer is:
Create your own QWidget class. Override the paintEvent and paint in it with a QPainter. I think there's plenty of examples if you google it.
Like this: http://doc.qt.io/qt-5/qtwidgets-painting-basicdrawing-example.html
Or this: http://programmingexamples.wikidot.com/qt-qpainter-example
Or this: Draw on QWidget
You can go for Custom QQuickPaintedItem here you can find an Example.
I have an application which use C++ and QML.
In my C++ : I read the value and i send it to QML in order to show it in a slider.
My value change when i press in my hardware.
My problem is in the QML part:
In QML :
I need to trigger an animation for few seconds when this value change. I only need to show this animation when the value from c++ part Change.
if someone could help ?
I already tried the QML timer but not showing animation when value changed ?
Some code in QML part for the animation :
VolumeRemote.QML
Rectangle {
id: item1
width: 550
height: 110
color: "#0a0a07"
border.color: "#ffffff"
opacity: 1
SliderComponent{
id:slider
x: 34
y: 79
width: 466
height: 5
minimumValue: 0
//here i give the value from C++ to my slider
//Controller is a global Qobject where i define some stuff
value: Controller.volume_radio
onValueChanged: {
animation.running=true;
}
PropertyAnimation {
id:myanimation
running: true
target:item1
property: 'visible'
to: false
duration: 10000
}
}
Text {
id: text1
x: 93
y: 16
width: 170
height: 41
color: "#ffffff"
text: qsTr("Radio Volume :")
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
font.pixelSize: 24
font.family: regular.name
}
Text {
id: valeurslider
x: 277
y: 16
// x: 618
//y: 45
width: 24
height: 41
color: "#ffffff"
text: slider.value
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
opacity: 0.45
font.pixelSize: 30
font.family: regular.name
}
Image {
id: image1
x: 34
y: 16
width: 44
height: 41
source: "assets/ic_sound_popup_on.png"
}
}
You have two options
A local property and its change signal
readonly property qreal valueFromCpp: Controller.volume_radio
onValueFromCppChanged: // trigger animation
A Connections element
Connections {
target: Controller
onNameOfThePropertyNotifySignal: // trigger animation
}
if you use this in the C++ part: Q_PROPERTY(int RadioVolume READ getval NOTIFY val_signal ), you have to add a write function to change RadioVolume. Tha is to say:
Q_PROPERTY(int RadioVolume READ getval WRITE setVal NOTIFY val_signal ) and in the function setVal(), you have to change the RadioValume variable value and you have to emit the val_signal everytime the value changes. Instead of setting the value directly, call the setVal() function everywehre you set RadioVolume value and then in the QML part you have to put this: onVal_Signal: put the animation here
If you have any question regarding my answer do not hesitate to ask. If you have the code, i will be glad to help you change it
I use #Beloqui and #KevinKrammar second answer :
1 - Declare simple animation with property visible
2 - SliderCompenent and give the value : Controller.volume_radio
3 - use of connections in order to get the signal notified from C++ : OnVolumesignal
Then i can trigger the animation when signal is emitted from c++ part
Here a small piece of code :
import QtQuick 2.0
import QtQuick 2.0
import Controllers 1.0
import "Logic.js" as Controller_Js
Rectangle {
id: item1
width: 550
height: 110
color: "#0a0a07"
border.color: "#ffffff"
opacity: 1
visible: Controller.stateVol
SliderComponent{
id:slider
x: 34
y: 79
width: 466
height: 5
minimumValue: 0
maximumValue: 100
value: Controller.volume_radio
NumberAnimation {
id: animation
target: item1
property: "visible"
duration: 1000
easing.type: Easing.InOutQuad
}
//gestion du signal
Connections{
target:commodo
onVolumesignal:{
if (commodo.RadioVolume !==100){
Controller.stateVol=true
animation.start();
console.log("state of controller :", Controller.stateVol)
} else if (commodo.RadioVolume>100){
animation.stop();
Controller.stateVol=false
console.log("state", Controller.stateVol)
}
}
}
Cobntroller.stateVol is defined to false in my controller.qml
Thanks guys, it really helped me.
Here is my QML file that is a simple Rectangle where I want to display double values excerpted from my cpp code (yaw, roll and pitch).
tilt.qml :
import QtQuick 2.5
Rectangle {
id: myTilt
width: 100
height: 80
color: "grey"
border.color: "black"
anchors.margins: 15
property double yaw: 1.0 ;
property double roll: 0 ;
property double pitch: 0;
MouseArea {
anchors.fill: parent
onClicked: {
parent.color = Qt.rgba(Math.random(),Math.random(),Math.random(),1);
}
}
Text {
id: tilt
text: qsTr("Tilt :")
anchors.margins: 3
anchors.top: page.top
anchors.left: page.left
}
Text {
id: yaw
text: qsTr("Yaw : ") + Math.abs(yaw)
anchors.margins: 5
anchors.top: tilt.bottom
anchors.left: tilt.left
}
Text {
id: roll
text: qsTr("Roll : ") + roll
anchors.margins: 0
anchors.top: yaw.bottom
anchors.left: yaw.left
}
Text {
id: pitch
text: qsTr("Pitch : ") + pitch
anchors.margins: 0
anchors.top: roll.bottom
anchors.left: roll.left
}
}
Here is what I tryied in order to link my cpp values to the qml code.
myTilt is a QQuickItem.
void OpenGLManager::build_qml(QQuickWidget *tilt_qml) {
myTilt = tilt_qml->rootObject();
myTilt->setProperty("yaw", tilt[0]);
myTilt->setProperty("pitch", tilt[1]);
myTilt->setProperty("roll", tilt[2]);
}
void OpenGLManager::setDroneTilt(QList<double> yaw, QList<double> pitch, QList<double> roll)
{
tilt = QVector3D(10, 20, 30) ;
myTilt->setProperty("yaw", tilt[0]);
myTilt->setProperty("pitch", tilt[1]);
myTilt->setProperty("roll", tilt[2]);
}
I'm loading this qml file as source for a QQuickWidget designed in QtDesigner.
The rectangle displays fine but instead of the values I want, I get NaN for Math.abs(yaw) and QQuickText(0x2a29100) for roll and pitch.
I'm using Qt5.6
Text {
id: yaw
text: qsTr("Yaw : ") + Math.abs(yaw)
anchors.margins: 5
anchors.top: tilt.bottom
anchors.left: tilt.left
}
I wonder what can go wrong...
It's an ID of the text element.
Also, there is a general practice: never use QML objects from C++ code. So, don't do things like myTilt = tilt_qml->rootObject(); and myTilt->setProperty(...);. Create a C++ class instead and make it usable from QML.
In OpenGL terms, what I want to do is modify the projection matrix of a Qt GUI.
Pretend the window is 480x640. It is displayed as normal, and rendered to a texture.
I then take that texture, and stretch it across the entire screen.
Does Qt have something like that? I don't want the GUI looking fine and having appropriately-sized text on a 480x640 tablet, but then it gets loaded up on a 1536x2048 tablet and you need a magnifying glass for the text.
I've written my own GUI in OpenGL before, calculating a vid.width/BASEWIDTH, vid.height/BASEHEIGHT ratio and multiplying the modelview matrix of elements to ensure that a GUI always fills a screen and stays the same size -- obviously this only works perfectly providing the aspect ratio is the same, but I digress.
I messed with layouts in Qt Quick for awhile, and it offers some nice anchoring options, but nothing for stuff like scaling up the text if the parent window is larger. Or am I missing something here?
An OpenGL GUI I wrote had a few options for control position coordinates:
Origin for transforms (Top, Center, Bottom, Left, Center, Right)
PosIsPercentage (specified whether the position coordinates were to be interpreted as a percentage of screen width/height)
This allowed you to set the position as a distance from any edge of the screen, or you could set PosIsPercentage = true and set the X value to 75 to have the coordinate always be at 3/4ths of whatever the screen size was.
There was also a SizeIsPercentage value, so you could set a button to be 10% of the screen width.
I see some of these options in the Qt Quick designer, but they aren't behaving as I expect.
I know this is hard to explain, so here is an image to demonstrate:
http://www.spaddlewit.com/QtLayoutProblem.png
(not what I'm using Qt for, but a good example of the problem I'm having)
Scaling items based on the width and height of the screen works well enough, except when you move to a high DPI device. A better method is to scale items based on the height of the default font. The default font size of a Text item, for example, will always be legible on platforms supported by Qt, no matter the DPI. You can use the same principle to scale font sizes; multiply the default font size by some amount.
Below I've done a quick mock up of the screenshot you linked to:
import QtQuick 2.3
import QtQuick.Controls 1.2
ApplicationWindow {
id: window
contentItem.implicitWidth: 640
contentItem.implicitHeight: 480
contentItem.minimumWidth: 640
contentItem.minimumHeight: 480
contentItem.maximumWidth: 1024
contentItem.maximumHeight: 768
/*
With Qt 5.4, you can also use the new FontMetrics item,
which saves you the overhead of creating a Text item:
For example:
FontMetrics {
id: fontMetrics
}
Then:
font.pixelSize: fontMetrics.font.pixelSize * 4
anchors.margins: fontMetrics.implicitHeight * 2
*/
Text {
id: defaultText
}
Image {
source: "http://cdn2.landscapehdwalls.com/wallpapers/1/perfect-green-hills-1197-1280x800.jpg"
}
Item {
id: container
anchors.fill: parent
anchors.margins: defaultText.implicitHeight * 2
Column {
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
spacing: container.anchors.margins
Text {
id: yourGameText
text: "Your Game!"
font.pixelSize: defaultText.font.pixelSize * 4
wrapMode: Text.Wrap
}
ListView {
interactive: false
anchors.right: parent.right
width: yourGameText.width
height: container.height * 0.3
model: ["Play Game!", "Options", "Exit"]
delegate: Button {
text: modelData
width: ListView.view.width
}
}
}
Row {
anchors.left: parent.left
anchors.bottom: parent.bottom
spacing: container.anchors.margins
Image {
source: "http://www.facebookbrand.com/img/assets/asset.f.logo.lg.png"
width: defaultText.implicitHeight * 3
height: width
}
Image {
source: "http://g.twimg.com/Twitter_logo_white.png"
width: defaultText.implicitHeight * 3
height: width
}
Image {
source: "http://www.youtube.com/yt/brand/media/image/YouTube-logo-full_color.png"
width: defaultText.implicitHeight * 3
height: width
}
}
}
}
Window Size
The first thing I did was set the default, minimum and maximum size of the window.
Scaling
Next, I created an empty Text item which items and text sizes will be based off. It might seem hackish, and it is a bit, but it also works really well. As mentioned in the comment, in Qt 5.4 there will be a FontMetrics type which you can use instead of creating a Text item that will never actually be shown.
Another alternative is to use Screen's pixelDensity property.
Margins
You said you wanted to:
set the position as a distance from any edge of the screen
I did that by creating an Item that fills the window, and then setting the margins from the edges of the window as some factor of the default font's implicit height. This ensures that the content within the item will be the same physical distance (e.g., in millimetres) from the edge of the window regardless of the DPI of the device you're viewing it on. If you'd rather the distance be larger if the window is larger, you can do this instead:
anchors.margins: window.width * 0.1
Font Sizes
Take a look at the Text item within the Column. If you want to ensure the text is also the same physical size on the screen, you can set font.pixelSize to be the default font's size multiplied by some amount. Again, if you'd rather base it off the size of the screen rather than the DPI, you can do this instead:
font.pixelSize: window.height * 0.05
More Information
The Scalability documentation also gives a nice overview on this topic.
Below is a screenshot of the application running:
The following works, but it's annoying -- you have to create a scaleWidth and scaleHeight function and wrap any constant coordinates in them.
Font sizes scale along the shortest edge of the screen -- this application is a Portrait-only orientation, so it uses scaleWidth(pointSize) for font sizes.
Would be nice to find a solution that's compatible with the QML designer.. is there any way to automatically insert this calculation, maybe afterwards in C++ code at runtime?
import QtQuick 2.2
import QtQuick.Window 2.1
import QtQuick.Controls 1.2
ApplicationWindow {
id:window
visible: true
width: 480
height: 640
function scaleWidth(w)
{
return w * (width / 480.0)
}
function scaleHeight(h)
{
return h * (height / 640.0)
}
Text {
id: defaultText
}
Image {
id: image1
x: 0
y: 0
width: window.width
height: window.height
fillMode: Image.Stretch
source: "http://cdn2.landscapehdwalls.com/wallpapers/1/perfect-green-hills-1197-1280x800.jpg"
Label {
id: lblTitle
x: 0
y: scaleHeight(8)
text: qsTr("Welcome to the App")
anchors.horizontalCenter: parent.horizontalCenter
font.pointSize: scaleWidth(36)
horizontalAlignment: Text.AlignHCenter
}
Label {
id: lblSubtitle
x: 0
text: qsTr("Login to Continue")
font.pointSize: scaleWidth(24)
anchors.top: lblTitle.bottom
anchors.topMargin: scaleHeight(8)
anchors.horizontalCenter: lblTitle.horizontalCenter
}
Item {
id: itemCenterAlign
x: 0
y: 0
width: 0
height: 200
anchors.horizontalCenter: parent.horizontalCenter
}
Label {
id: lblUsername
x: 0
text: qsTr("Username:")
anchors.top: lblSubtitle.bottom
anchors.topMargin: scaleHeight(64)
font.bold: true
font.pointSize: scaleWidth(24)
anchors.right: itemCenterAlign.left
anchors.rightMargin: scaleWidth(8)
}
TextField {
id: txtUsername
width: scaleWidth(224)
height: scaleHeight(43)
anchors.left: itemCenterAlign.right
anchors.leftMargin: scaleWidth(8)
anchors.top: lblSubtitle.bottom
anchors.topMargin: scaleHeight(64)
font.pointSize: scaleWidth(24)
placeholderText: qsTr("Username")
}
Label {
id: lblPIN
x: 0
y: scaleWidth(-8)
text: qsTr("PIN:")
font.bold: true
font.pointSize: scaleWidth(24)
anchors.topMargin: scaleHeight(12)
anchors.right: itemCenterAlign.left
anchors.rightMargin: scaleWidth(8)
anchors.top: lblUsername.bottom
}
TextField {
id: txtPIN
x: 0
y: 0
width: scaleWidth(224)
height: scaleHeight(43)
placeholderText: qsTr("PIN")
font.pointSize: scaleWidth(24)
anchors.topMargin: scaleHeight(8)
anchors.leftMargin: scaleWidth(8)
anchors.left: itemCenterAlign.right
anchors.top: txtUsername.bottom
}
Row {
id: row1
x: 0
y: scaleHeight(277)
width: scaleWidth(464)
height: scaleHeight(115)
spacing: scaleWidth(8)
anchors.horizontalCenter: parent.horizontalCenter
Button {
id: cmdQuit
text: qsTr("Quit")
width: row1.width / 3 - row1.spacing / 2
height: row1.height
}
Button {
id: cmdGPSOnly
text: qsTr("GPS Only")
width: row1.width / 3 - row1.spacing / 2
height: row1.height
}
Button {
id: cmdLogin
text: qsTr("Login")
width: row1.width / 3 - row1.spacing / 2
height: row1.height
}
}
Button {
id: cmdAbout
width: cmdQuit.width
height: scaleHeight(44)
text: qsTr("About")
anchors.top: row1.bottom
anchors.topMargin: scaleHeight(8)
anchors.left: row1.left
anchors.leftMargin: 0
}
Label {
id: lblVersion
y: 619
text: qsTr("v3.0.0.0")
font.pointSize: scaleWidth(16)
anchors.bottom: parent.bottom
anchors.bottomMargin: scaleHeight(8)
anchors.left: parent.left
anchors.leftMargin: scaleWidth(8)
}
Label {
id: lblBooks
x: 0
y: lvBooks.y
text: qsTr("Books Loaded:")
horizontalAlignment: Text.AlignRight
font.pointSize: scaleWidth(24)
anchors.right: lvBooks.left
anchors.rightMargin: scaleWidth(8)
}
Rectangle
{
x: lvBooks.x
y: lvBooks.y
width: lvBooks.width
height: lvBooks.height
color: "white"
border.color: "black"
}
ListView {
id: lvBooks
x: 0
y: 0
width: scaleWidth(224)
height: scaleHeight(160)
anchors.bottom: parent.bottom
anchors.bottomMargin: scaleHeight(8)
anchors.right: parent.right
anchors.rightMargin: scaleWidth(8)
model: ListModel {
ListElement {
name: "Book1"
}
ListElement {
name: "Book2"
}
}
delegate: Item {
x: 5
width: scaleWidth(80)
height: scaleHeight(40)
Row {
Text {
text: name
font.bold: true
font.pointSize: scaleWidth(24)
anchors.verticalCenter: parent.verticalCenter
}
spacing: 0
}
}
}
}
}