Whole project can be found here:
QML Video Test Project
I have made an example application with three buttons one image and one video player. When pressing the buttons a video is supposed to play. This is what distinguishes the buttons:
Access a video file in the same folder as the applications executable file.
Access a video file added to the Qt Resource file.
Access a video file from an external binary Qt Resource file with no compression.
Only button 1. work in my application and the reason for this post is that I have run out of idea on why button 2. and 3. can not make the video play.
The image included in the application is an image that is packed together with a video file in the external binary Qt Resource file. This image is successfully read from the external resource file. This means that access to the external resource file is not the problem.
Here is the main.qml file:
import QtQuick 2.4
import QtQuick.Window 2.2
import com.qml.externalresourcemanager 1.0
import QtMultimedia 5.4
import QtQuick.Controls 1.2
Window {
visible: true
minimumHeight: 700
minimumWidth: 400
property string imageSelected: ""
property string videoSelected: ""
ExternalResourceManager {
id: externalResourceManager
Component.onCompleted: {
console.log("External resource registered: " + registerExternalResource("file:/../../VideoTest/binaryExpansionFile.rcc"))
imageSelected = "externalImage.jpg"
}
}
Button {
id: button0
width: parent.width
height: parent.height / 7
anchors.top: parent.top
text: "Click me to play as local file"
onClicked: {
console.log(installPath + "local.mp4")
videoSelected = installPath + "local.mp4"
}
}
Button {
id: button1
width: parent.width
height: parent.height / 7
anchors.top: button0.bottom
text: "Click me to play local resource file"
onClicked: {
videoSelected = "local.mp4"
}
}
Button {
id: button2
width: parent.width
height: parent.height / 7
anchors.top: button1.bottom
text: "Click me to play external resource file"
onClicked: {
videoSelected = "external.mp4"
}
}
Image {
id: image
source: imageSelected
width: parent.width
height: parent.height * 2 / 7
anchors.top: button2.bottom
}
Video {
id: video
source: videoSelected
height: parent.height * 2 / 7
width: parent.width
anchors.top: image.bottom
fillMode: VideoOutput.PreserveAspectFit
onStatusChanged: {
var temp
switch (playbackState)
{
case MediaPlayer.NoMedia:
temp = "MediaPlayer.NoMedia"
break;
case MediaPlayer.Loading:
temp = "MediaPlayer.Loading"
break;
case MediaPlayer.Loaded:
temp = "MediaPlayer.Loaded"
break;
case MediaPlayer.Buffering:
temp = "MediaPlayer.Buffering"
break;
case MediaPlayer.Stalled:
temp = "MediaPlayer.Stalled"
break;
case MediaPlayer.Buffered:
temp = "MediaPlayer.Buffered"
break;
case MediaPlayer.EndOfMedia:
temp = "MediaPlayer.EndOfMedia"
break;
case MediaPlayer.InvalidMedia:
temp = "MediaPlayer.InvalidMedia"
break;
case MediaPlayer.UnknownStatus:
temp = "MediaPlayer.UnknownStatus"
break;
}
console.log(temp)
if (status === MediaPlayer.Loaded)
{
video.play()
}
}
onBufferProgressChanged: {
console.log("Buffering: " + bufferProgress * 100)
}
onSourceChanged: {
console.log("Source: " + source)
}
onAvailabilityChanged: {
console.log("Availability: " + availability)
}
onErrorChanged: {
console.log("Error: " + error)
}
onErrorStringChanged: {
console.log("Error String: " + errorString.toString())
}
onHasVideoChanged: {
console.log("Has video: " + hasVideo)
}
onPlaybackStateChanged: {
var temp
switch (playbackState)
{
case MediaPlayer.PlayingState:
temp = "MediaPlayer.PlayingState"
break;
case MediaPlayer.PausedState:
temp = "MediaPlayer.PausedState"
break;
case MediaPlayer.StoppedState:
temp = "MediaPlayer.StoppedState"
break;
}
console.log(temp)
}
}
}
Pressing button 1 my application outputs this:
Resource path: "file:/../../VideoTest/binaryExpansionFile.rcc"
qml: External resource registered: true
qml: file:/C:/Users/MisterX/Documents/QtProjects/build-VideoTest-Desktop_Qt_5_4_2_MinGW_32bit-Debug/debug/local.mp4
qml: Source: file:///C:/Users/MisterX/Documents/QtProjects/build-VideoTest-Desktop_Qt_5_4_2_MinGW_32bit-Debug/debug/local.mp4
qml: MediaPlayer.UnknownStatus
qml: Has video: true
qml: MediaPlayer.UnknownStatus
qml: MediaPlayer.NoMedia
qml: MediaPlayer.PlayingState
Pressing button 2 my application outputs this:
Resource path: "file:/../../VideoTest/binaryExpansionFile.rcc"
qml: External resource registered: true
qml: Source: qrc:/local.mp4
qml: MediaPlayer.UnknownStatus
qml: Has video: false
qml: MediaPlayer.UnknownStatus
qml: MediaPlayer.NoMedia
qml: MediaPlayer.PlayingState
Whole project can be found here:
QML Video Test Project
This is a bug when using the MinGW compiler that uses the DirectShow backend. See this bug report link for more information.
Related
I have a QML Item with some Text fields in it, which should have all the same font. Do achieve this i introduce a new property myFont of type font. Do initialize this property I use the Qt.font function, which creates a font object. But I have to specify at least one property (either family or pointSize).
My Question is now: How can I retrieve the default font for the myFont property?
If I create only a Text{} item, it has already a default font attached, how can I get the same font for the myFont property? (Meanwhile I use a hidden Text field and create an alias to it's font property, but I want a better solution).
Item {
property font myFont: Qt.font({pointSize: 10})
Text {
id: header
font: myFont
text: "My Header"
}
Text {
id: subject
font: myFont
text: "My Subject"
}
Text {
id: message
font: myFont
text: "Some meassage!"
}
}
I think the right way to solve this is to create your own object type with the font you need to use.
In the following example, the new object would be MyText.qml. I don't know your whole code, but I suppose you have a ListView with the delegate you posted in your question.
MyText.qml
import QtQuick 2.0
Text {
font: Qt.font({pointSize: 10})
}
main.qml
import QtQuick 2.5
import QtQuick.Window 2.2
Window {
visible: true
ListModel {
id: myModel
ListElement {
header: "header xxx"
subject: "subject xxx"
message: "message xxx"
}
ListElement {
header: "header yyy"
subject: "subject yyy"
message: "message yyy"
}
ListElement {
header: "header zzz"
subject: "subject zzz"
message: "message zzz"
}
}
ListView {
anchors.fill: parent
model: myModel
delegate: Item {
width: 300; height: 80
Column {
MyText {
id: myheader
text: header + " - family: " + font.family + " size: " + font.pointSize
}
MyText {
id: mysubject
text: subject + " - family: " + font.family + " size: " + font.pointSize
}
MyText {
id: mymessage
text: message + " - family: " + font.family + " size: " + font.pointSize
}
}
}
}
}
Now, I've digged into Qt source code.
And it turns out that Qt uses a registered private TextSingleton which is defined (Qt 5.6) as:
pragma Singleton
import QtQuick 2.2
Text {
}
The font property of various qml controls is initialized:
font: TextSingleton.font
Digging further into C++ code reveals that for the Text item, the font property is a default initialized QFont, which gives the QFont object retrieved from QGuiApplication::font().
As I mentioned here, FontMetrics is the way to go since it's configurable and without using Qt.font(). You can declare it in your parent item or in a SIngleton type and the you can bind the property to it.
Here there's an example
Item {
id: root
FontMetrics {
id: fontMetrics
font.family: "Arial"
font.pixelSize: 24
}
property alias font: fontMetrics.font
Text { font: root.font }
Text { font: root.font }
}
You can access the default font in QML with Qt.application.font.
You can get and set this font in C++ using
QFont font = QApplication::font();
font.setPointSize(12); //make various other changes or get a completely new QFont
QApplication::setFont(font);
I am developing a Qt app on Win/Android. My question is very simple.
When my app starts, first a login page welcomes you.
If you want to configure server settings, ServerInfo.qml is opened in a loader. The login page and ServerInfo are loaded in the same loader.
My problem is that when I close ServerInfo.qml, then load loginpage.qml to loader, the loader creates a new instance of loginpage.qml. I don't want the page to be created again.
Here is my Qml code :
ApplicationWindow {
id:mainwindow
visible: true
width: 600
height: 800
x: Screen.width / 2 - width / 2
y: Screen.height / 2 - height / 2
menuBar:MenuBar{
Menu {
title:"Edit"
MenuItem {
text:"Sunucu Ayarları"
onTriggered: {
loader.source="ServerConfig.qml"
loader.anchors.centerIn=main
}
}
MenuItem {
text:"Çıkış"
onTriggered: {
Qt.quit();
}
}
}
}
Connections {
ignoreUnknownSignals: true
target: process
onProcessstart: {
busyrec.visible=true;
busyloader.item.busytext=text;
busyloader.item.busyrunnig=true;
}
onProcessstop: {
busyloader.item.busytext=text;
busyloader.item.busyrunnig=false;
busyloader.item.busytextcolor="blue"
}
Component.onCompleted: {
// process.onSuccesLogin();
//TaskResultm.taskresult.Malzemeler.push
console.log(TaskResultm.taskresult.serilaze());
}
}
Column {
anchors.fill: parent
Rectangle {
id:busyrec
width: parent.width
height: (parent.height/10)
visible:true
color:"green"
Loader {
id:busyloader
source:"BusyIndicator.qml"
anchors.fill: parent
}
Connections {
ignoreUnknownSignals: true
}
}
Rectangle {
id: main
// anchors.fill: parent
width: parent.width
height: (parent.height/10)*9
Loader {
id:loader
source: "LoginPage.qml"
anchors.centerIn:parent
focus:true
property bool valid: item !== null
}
Connections {
ignoreUnknownSignals: true
target: loader.valid? loader.item : null
onDirecttomainpage:{
// process.getWorkOrderList();
busyloader.item.switenabled=true;
busyloader.item.switopacity=1;
loader.anchors.fill=main;
loader.source="TaskNavigationMainScreen.qml";
}
onServerinfopageclose: {
loader.source="LoginPage.qml";
loader.anchors.centerIn=main;
}
}
}
}
onClosing: {
if(Qt.platform.os=="android") {
if(loader.item!==null)
{
if(loader.item.objectName==="tasknavigationmain")
if(loader.item.zemin===0)
close.accepted=true;
else
close.accepted=false;
}
}
else if (Qt.platform.os=="windows")
{
Qt.quit();
//if(loader.item!==null)
// if(loader.item.objectName==="tasknavigationmain")
// console.log(loader.item.stackViewItem.depth);
}
}
}
Just use a StackView instead of a Loader, it will keep previous "forms" alive as you push new ones on top, and you can always go back and forth.
A loader will load a single element, if you load another, the old one will be destroyed, there is no way around that.
I'm looking for a simple way to make widgets for a touch-screen that will allow users to set the time and IP address on the computer running the code and provide a simple (uppercase Latin-alphabetic) name.
This question is not about how to actually set the system time or IP address; I'm just looking for information about how to make the graphical widgets themselves.
What I want is for each editable property (time, address, and name) to be divided into "scrollable" fields, where the fields for "time" are hours, minutes, possibly seconds, and AM/PM/24-hr, and the fields for address/name are the individual characters. Each field would have an arrow above and below it, and touching on an arrow would scroll through the valid values for that field.
I think this is a pretty common UX pattern, especially in meatspace (e.g. on alarm clocks), but just in case it's not clear what I'm trying to describe, here's an example with a user editing the "name" property:
^^^
BN
vvv
User presses "down" below the "N":
^^^
BO
vvv
User presses "down" below the empty space:
^^^^
BOA
vvvv
...and again on the same down-arrow:
^^^^
BOB
vvvv
I'm writing this using C++14 with Qt 5. (If worst comes to worst, I'd be open to writing a separate app using a different language and/or framework, but I'm not asking for framework suggestions here; if you have one, let me know and I'll open a corresponding question on Software Recommendations SE.)
I don't see anything in the Qt 5 widget library like this; most of the input widgets are text fields. QSpinBox looks somewhat promising, but the arrows are probably too small for my touchscreen, and using a separate spinbox for each letter would probably be confusing and ugly.
I don't really know enough about Qt or GUI-programming in general to feel confident trying to write my own widgets from scratch, but this interface looks simple enough that I would expect a couple lines of QML would get me well on my way.
ListView as well as PathView can produce the desired result with slightly different behaviors and slightly different performances. Differently from ListView, PathView is circular, i.e. elements can be iterated continuously by using just one of the selection controls. It is also easier to fully customize the behavior of the path in PathView via the PathAttribute type. Anyhow path customization seems not to be a required feature, according to the question.
If you implement the solution via a ListView you should ensure that just one element is shown and that any model is processed.
Component {
id: spinnnnnnnner
Column {
width: 100
height: 110
property alias model: list.model
property string textRole: ''
spacing: 10
Item {
width: 100
height: 25
Text { anchors.centerIn: parent; text: "-"; font.pixelSize: 25; font.bold: true }
MouseArea {anchors.fill: parent; onClicked: list.decrementCurrentIndex() }
}
ListView {
id: list
clip: true
width: 100
height: 55
enabled: false // <--- remove to activate mouse/touch grab
highlightRangeMode: ListView.StrictlyEnforceRange // <--- ensures that ListView shows current item
delegate: Text {
width: ListView.view.width
horizontalAlignment: Text.AlignHCenter
font.pixelSize: 50
font.bold: true
text: textRole === "" ? modelData :
((list.model.constructor === Array ? modelData[textRole] : model[textRole]) || "")
}
}
Item {
width: 100
height: 25
Text { anchors.centerIn: parent; text: "+"; font.pixelSize: 25; font.bold: true }
MouseArea {anchors.fill: parent; onClicked: list.incrementCurrentIndex() }
}
}
}
The checks over the model ensure that any type of model can be passed to the component. Here is an example using three very different models:
import QtQuick 2.5
import QtQuick.Window 2.2
import QtQuick.Controls 1.4
import QtQuick.Layouts 1.1
ApplicationWindow {
visible: true
width: 400
height: 300
ListModel {
id: mod
ListElement {texty: "it1"}
ListElement {texty: "it2"}
ListElement {texty: "it3"}
}
Row {
Repeater {
id: rep
model: 3
delegate: spinnnnnnnner
Component.onCompleted: {
rep.itemAt(0).model = mod // listmodel
rep.itemAt(0).textRole = "texty"
rep.itemAt(1).model = 10 // number model
//
rep.itemAt(2).model = ["foo", "bar", "baz"] // array model
}
}
}
}
PathView implementation is not so different from the ListView one. In this case it is sufficient to define a vertical path and specify that just one one element is visible at a time via pathItemCount. Finally, setting preferredHighlightBegin/preferredHighlightEnd ensures that the visible element is centered in the view. The revisited component is the following:
Component {
id: spinnnnnnnner
Column {
width: 100
height: 110
property alias model: list.model
property string textRole: ''
spacing: 10
Item {
width: 100
height: 25
Text { anchors.centerIn: parent; text: "-"; font.pixelSize: 25; font.bold: true }
MouseArea {anchors.fill: parent; onClicked: list.decrementCurrentIndex() }
}
PathView {
id: list
clip: true
width: 100
height: 55
enabled: false // <--- remove to activate mouse/touch grab
pathItemCount: 1
preferredHighlightBegin: 0.5
preferredHighlightEnd: 0.5
path: Path {
startX: list.width / 2; startY: 0
PathLine { x: list.width / 2; y: list.height }
}
delegate: Text {
width: PathView.view.width
horizontalAlignment: Text.AlignHCenter
font.pixelSize: 50
font.bold: true
text: textRole === "" ? modelData :
((list.model.constructor === Array ? modelData[textRole] : model[textRole]) || "")
}
}
Item {
width: 100
height: 25
Text { anchors.centerIn: parent; text: "+"; font.pixelSize: 25; font.bold: true }
MouseArea {anchors.fill: parent; onClicked: list.incrementCurrentIndex() }
}
}
}
EDIT: 26.08.2014 08:20 - Completely reworked question!
What I want to do is:
Fill a qml-listview with data from a cpp-listmodel (QAbstractListModel).
Open a Dialog that show's more data from the cpp-listmodel by click on a listview-item.
I have two cpp-Classes:
DataModelItem with two attributes (listData (displayed in the listview) and detailsData (displayed in the Dialog))
DataModel which inherits QAbstractListModel with an attribut QList itemList.
DataModel.cpp:
QVariant DataModel::data(const QModelIndex &index, int role) const
{
DataModelItem *item = m_itemList.at(index.row());
switch (role) {
case ListDataRole:
return QString().sprintf("%.2f", item->listData());
break;
case DetailsDataRole:
return QString().sprintf("%.4f", item->detailsData());
break;
default:
qDebug () << "role not handled";
}
return QVariant();
}
What I now wanna do is, to display the listData in the ListView. When I click on one ListItem a dialog should appear with the detailsData.
I figured out, that I can't write model.detailsData in my main application, but just detailsData works (I also tried listview.model.detailsData with no effect). Probably someone know why this does not work.
Anyway I found a solution.
Here's the working example:
main.qml
import QtQuick 1.1
Rectangle {
width: 200
height: 400
ListView {
id: listView
model: dataModel
delegate: listDelegate
}
Component {
id: listDelegate
Item {
id: delegateItem
width: listDataText.width
height: listDataText.height
Text {
id: listDataText
text: listData
}
MouseArea {
anchors.fill: parent
onClicked: {
console.log(detailsData)
itemDetails.details = model.detailsData
itemDetails.visible = true
}
}
}
}
DetailsDialog {
id: itemDetails
visible: false
anchors.centerIn: parent
}
}
DetailsDialog.qml
import QtQuick 1.1
Rectangle {
property alias details: detailsText.text
width: 100
height: 62
Text {
id: detailsText
}
}
I have a QML textInput element like this:
TextBox.qml
FocusScope {
id: focusScope
property int fontSize: focusScope.height -30
property int textBoxWidth: parent.width * 0.8
property int textBoxHeight: 45
property string placeHolder: 'Type something...'
property bool isUserInTheMiddleOfEntringText: false
width: textBoxWidth
height: textBoxHeight
Rectangle {
width: parent.width
height: parent.height
border.color:'blue'
border.width: 3
radius: 0
MouseArea {
anchors.fill: parent
onClicked: {
focusScope.focus = true
textInput.openSoftwareInputPanel()
}
}
}
Text {
id: typeSomething
anchors.fill: parent; anchors.rightMargin: 8
verticalAlignment: Text.AlignVCenter
text: placeHolder
color: 'red'
font.italic: true
font.pointSize: fontSize
MouseArea {
anchors.fill: parent
onClicked: {
focusScope.focus = true
textInput.openSoftwareInputPanel()
}
}
}
MouseArea {
anchors.fill: parent
onClicked: {
focusScope.focus = true
textInput.openSoftwareInputPanel()
}
}
TextInput {
id: textInput
anchors {
right: parent.right
rightMargin: 8
left: clear.right
leftMargin: 8
verticalCenter: parent.verticalCenter
}
focus: true
selectByMouse: true
font.pointSize: fontSize
}
Text {
id: clear
text: '\u2717'
color: 'yellow'
font.pointSize: 25
opacity: 0
visible: readOnlyTextBox ? false : true
anchors {
left: parent.left
leftMargin: 8
verticalCenter: parent.verticalCenter
}
MouseArea {
anchors.fill: parent
onClicked: {
textInput.text = ''
focusScope.focus = true;
textInput.openSoftwareInputPanel()
}
}
}
states: State {
name: 'hasText'; when: textInput.text != ''
PropertyChanges {
target: typeSomething
opacity: 0
}
PropertyChanges {
target: clear
opacity: 0.5
}
}
transitions: [
Transition {
from: ''; to: 'hasText'
NumberAnimation {
exclude: typeSomething
properties: 'opacity'
}
},
Transition {
from: 'hasText'; to: ''
NumberAnimation {
properties: 'opacity'
}
}
]
}
I want to add autocomplete and suggestions like google search to this text box. Autocomple get data from database and database return a list of dictionaries by a pyside SLOT.(or c++ slot)
How I can do this work?
Take a look at this code: https://github.com/jturcotte/liquid/blob/master/qml/content/SuggestionBox.qml
I bet it will do the job.
Edit:
Code that linked above is somewhat complicated and requires C++ backend, so I simplified it and made pure Qml example application, that you can play with, edit a little and apply to your needs. Sources can be found here. Most important things there are:
This implementation of SuggestionBox that uses some sort of model as it's source for completing/suggesting something
Its signal itemSelected(item) will be emitted every time user clicks on item
Main component of application that binds its LineEdit component to SuggestionBox
Note that code is quite rough and written for a sake of example.
I was looking for something very similar: a QML autocomplete component built around QML TextField, rather than the lower-level, more flexible but also more work intensive TextInput as in the question.
Since I could not find that, I implemented it. If anyone wants to use it: it's licensed under MIT and available as part of an application I am developing. You find the component in src/qml/AutoComplete.qml, and the application may serve as usage example. Features:
highlighting of autocompleted characters in bold, as in Google Search
Key bindings (navigating with arrow keys, Return / Enter, Esc to close completion box, Esc Esc to unfocus)
uses a simple QStringList as model for now, with the application showing how to update the model with live SQL database queries when the next key is pressed
heavily documented code, so it should be easy enough to adapt
Let me know if this is useful, I might then package it as a Qt QPM package or even try to make it mature enough to be added to the QML UI library KDE Kirigami.