Problème d'affichage de la scrollbar d'une ScrollView
RésoluMourad2009B Messages postés 145 Statut Membre -
Bonjour à tous,
je suis en train de travailler sur un projet (Qt Quick, Qt, C++), comme IDE j'utilise QtCreator.
Et puis dans mon main.qml, j'ai tout essayé, mais je n'arrive pas à afficher la scrollbar du contrôle "ScrollView"
ou l'ascenseur, vertical, pour pouvoir scroller et essayer d'afficher tous mes contrôles qui sont nombreux.
Je vous mets au dessous le fichier complet, le main.qml, et est-ce que vous pouvez, s'il vous plaît, me donner votre avis, et m'aider à trouver ce qui ne va pas.
Merci d'avance
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import QtQuick.VirtualKeyboard 2.15
import "."
// Pour utiliser DatabaseManager (depuis qmlRegisterType)
import com.mkapplications.database 1.0
// Pour accéder aux éléments du module QML (déclaré dans CMake)
import com.mkapplications.GestionBudgetEmbarque 1.0
ApplicationWindow
{
id: window
//Pour les mobiles
minimumWidth: Qt.platform.os === "android" || Qt.platform.os === "ios" ? Screen.width : 800
minimumHeight: Qt.platform.os === "android" || Qt.platform.os === "ios" ? Screen.height : 400
visible: true
title: qsTr("Hello World")
//Les propriéts
property int idSousCategorie: -1 // valeur initiale par défaut
// Flag global pour éviter boucle infinie
property bool updating: false
//Le clavier virtuel
InputPanel
{
id: inputPanel
z: 99
x: 0
y: window.height
width: window.width
states: State
{
name: "visible"
when: inputPanel.active
PropertyChanges {
target: inputPanel
y: window.height - inputPanel.height
}
}
transitions: Transition
{
from: ""
to: "visible"
reversible: true
ParallelAnimation
{
NumberAnimation
{
properties: "y"
duration: 250
easing.type: Easing.InOutQuad
}
}
}
} //Fin du clavier virtuel
//---------------------------Vue principale---------------------------//
ScrollView
{
id: scrollView
anchors
{
left: parent.left
right: parent.right
top: parent.top
bottom: Qt.platform.os === "android" ?
parent.bottom :
inputPanel.top
}
clip: true
ScrollBar.vertical.policy: ScrollBar.AlwaysOn // Pour faciliter le défilement
ScrollBar.vertical.interactive: true // Important pour mobile
// La colonne qui contient tous les controles
ColumnLayout
{
id: idLayoutPricipal
width: scrollView.availableWidth // Important pour le mobile
height: scrollView.availableHeight // Important pour le mobile
// Cette ligne est CRUCIALE : elle permet au ScrollView de connaître la hauteur du contenu
implicitHeight: childrenRect.height
//width: parent.width
Layout.fillWidth: true
Layout.leftMargin: 20 // Marge à gauche
Layout.rightMargin: 20 // Marge à droite
Layout.topMargin: 20 // Marge en haut
spacing: 20
//---------------------------La colonne qui contient le rectangle et l'icone de l'application---------------------------//
RowLayout
{
id: rootLayout
width: scrollView.availableWidth // Important pour le mobile
spacing: 10
// --------------------------------- Header ---------------------------------
Rectangle
{
id: idHeaderRect
Layout.fillWidth: true
Layout.leftMargin: 20 // Marge à gauche
Layout.rightMargin: 20 // Marge à droite
Layout.topMargin: 20 // Marge en haut
height: idHeaderRow.implicitHeight + 20
// height: 60
color: "#cc65cc"
radius: 8
// Dégradé de couleur (conservé de votre version originale)
gradient: Gradient
{
GradientStop { position: 0.00; color: "#cc65cc" }
GradientStop { position: 0.01; color: "#dd1d1d" }
GradientStop { position: 1.00; color: "#ffffff" }
}
border.color: "#2129dd"
//---------------------------La ligne qui contient l'icone de l'application ainsi que le titre---------------------------//
RowLayout
{
id: idHeaderRow
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
spacing: 20
Image
{
source: "qrc:/Media/Icones/icoPrincipale64.ico"
width: 32
height: 32
}
Label
{
text: "Gestion budget"
font.pixelSize: 20
}
}
}
} //Fin de La colonne qui contient le rectangle et l'icone de l'application
//---------------------------La ligne qui contient les comboBox et leurs Labels---------------------------//
RowLayout
{
width: parent // important pour que le layout s'adapte à la ScrollView
anchors.leftMargin: 10 // Augmenté
anchors.rightMargin: 20 // Augmenté
//anchors.topMargin: 10
//anchors.bottomMargin: 10
// 1-------- Colonne pour les comboBox et leurs Labels
ColumnLayout
{
Layout.fillWidth: true
Layout.leftMargin: 10
Layout.rightMargin: 10
//Layout.topMargin: 10
//Layout.bottomMargin: 10
spacing: 10
// Controle pour le Label Session
Label
{
text: "Session:"
Layout.preferredWidth: 100
Layout.alignment: Qt.AlignVCenter
}
// Controle pour la comboBox Session
ComboBox
{
id: idSessionCombo
Layout.fillWidth: true
Layout.minimumWidth: 250
textRole: "nom_de_session"
valueRole: "id_session"
currentIndex: 0
//Slot déclenché quand l'index de la ComboBox Session change
onCurrentIndexChanged: {
.....................................
}
}
// Controle pour le Label Catégorie
Label
{
text: "Catégorie:"
Layout.preferredWidth: 100
Layout.alignment: Qt.AlignVCenter
}
// Controle pour la comboBox Catégorie
ComboBox
{
id: idCategorieCombo
Layout.fillWidth: true
Layout.minimumWidth: 250
textRole: "nom_de_categorie"
valueRole: "id_categorie"
currentIndex: -1
//Slot déclenché quand l'index de la ComboBox Catégorie change
onCurrentIndexChanged: {
............................
...............................
}
}
// Controle pour le Label Sous-Catégorie
Label
{
text: "Sous-Catégorie:"
Layout.preferredWidth: 100
Layout.alignment: Qt.AlignVCenter
}
// Controle pour la comboBox Sous-Catégorie
ComboBox
{
id: idSousCategorieCombo
Layout.fillWidth: true
Layout.minimumWidth: 250
textRole: "nom_de_sc"
valueRole: "id_sous_categorie"
currentIndex: 0
onCurrentIndexChanged: {
.............................................
}
}
// Controle pour la Label Depense
Label
{
text: "Dépense:"
Layout.preferredWidth: 100
Layout.alignment: Qt.AlignVCenter
}
// Controle pour la ComboBox Depense
ComboBox
{
id: idDepenseCombo
Layout.fillWidth: true
Layout.minimumWidth: 250
textRole: "nom_de_depense"
valueRole: "id_depense"
currentIndex: 0
editable: true
}
//Controle pour Label Prix unitaire
Label
{
text: "Prix unitaire :"
Layout.preferredWidth: 100
Layout.alignment: Qt.AlignVCenter
}
// RowLayout pour le Controle TextField Prix unitaire et le Label euro
RowLayout
{
// Controle TextField Prix unitaire
CustomTextField
{
id: idPrixUnitaireFieldText
Layout.fillWidth: true
placeholderText: "0.00"
inputMethodHints: Qt.ImhDigitsOnly
onEditingFinished: {
....................................
}
// Nettoyage texte avec filtre + restriction (optionnel)
onTextChanged: {
.......................................
}
}
//Controle Label pour symbole euro du prix unitaire
Label
{
text: " €"
Layout.preferredWidth: 20
Layout.alignment: Qt.AlignVCenter
}
}
// Controle pour Label Quantité
Label
{
text: "Quantité :"
Layout.preferredWidth: 100
Layout.alignment: Qt.AlignVCenter
}
// Controle pour TextField Quantité
CustomTextField
{
id: idQuantiteFieldText
Layout.fillWidth: true
placeholderText: "1"
inputMethodHints: Qt.ImhDigitsOnly
onTextChanged: {
..........................................
}
onEditingFinished: {
...................................
}
}
// Controle pour Label Prix total
Label
{
text: "Prix total :"
Layout.preferredWidth: 100
Layout.alignment: Qt.AlignVCenter
}
// Controle pour le TextField Prix total
RowLayout
{
// Prix total
CustomTextField
{
id: idPrixTotalFieldText
Layout.fillWidth: true
placeholderText: "0.00"
inputMethodHints: Qt.ImhDigitsOnly
onTextChanged: {
..................................
}
onEditingFinished: {
.............................
}
}
//Controle Label pour symbole euro du prix totalo
Label
{
text: " €"
Layout.preferredWidth: 20
Layout.alignment: Qt.AlignVCenter
}
}
//99999999999999999999999999999999999999999999999999999999999999999999999
Label
{
text: "Date:"
Layout.preferredWidth: 100
}
TextField
{
id: idDateField
Layout.fillWidth: true
placeholderText: "JJ/MM/AAAA"
inputMethodHints: Qt.ImhDate
MouseArea
{
anchors.fill: parent
onClicked: dateDialog.open()
}
}
Popup
{
id: dateDialog
width: 300
height: 300
modal: true
focus: true
DatePicker
{
id: calendar
anchors.fill: parent
onSelectedDateChanged:
{
idDateField.text = Qt.formatDate(selectedDate, "dd/MM/yyyy")
dateDialog.close()
}
}
}
// time 8888888888
Label
{
text: "Heure:"
Layout.preferredWidth: 100
}
TextField
{
id: idTimeField
Layout.fillWidth: true
width: parent.width - 20
placeholderText: "HH:MM"
inputMethodHints: Qt.ImhTime
MouseArea
{
anchors.fill: parent
onClicked: timeDialog.open()
}
}
Popup
{
id: timeDialog
width: 200
height: 200
modal: true
focus: true
TimePicker
{
id: clock
anchors.fill: parent
Button
{
text: "Valider"
Layout.alignment: Qt.AlignHCenter
onClicked:
{
idTimeField.text = Qt.formatTime(new Date(0, 0, 0, clock.selectedTime.hours, clock.selectedTime.minutes), "hh:mm")
timeDialog.close()
}
}
}
}
} //Fin de Colonne pour les comboBox et leurs Labels
} //La fin de La ligne qui contient les comboBox et leurs Labels-
}
// Espace flexible en bas
Item
{
Layout.fillHeight: true
}
} //Fin de ScrollView
}
Pour éviter que le fichier main.qml soit trop long, j'ai supprimé tout ce qui n'est pas en rapport de la maison page. Et j'ai remplacé par des points.
Windows / Chrome 138.0.0.0
2 réponses
Bonjour Bruno83200_6929,
Un grand merci pour ta réponse rapide et efficace ! Je débute avec QML et j’étais bloqué depuis deux jours sur cette mise en page. Grâce à toi, je vais enfin pouvoir avancer. Merci encore
Bonjour,
Le ScrollView doit connaître la taille de son contenu via contentWidth et contentHeight.
Ne pas contraindre artificiellement la taille du layout principal avec width et height.
Utiliser implicitWidth et implicitHeight pour que Qt calcule automatiquement les dimensions;
S'assurer qu'il y a suffisamment de contenu pour dépasser la hauteur visible.
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import QtQuick.VirtualKeyboard 2.15
import "."
// Pour utiliser DatabaseManager (depuis qmlRegisterType)
import com.mkapplications.database 1.0
// Pour accéder aux éléments du module QML (déclaré dans CMake)
import com.mkapplications.GestionBudgetEmbarque 1.0
ApplicationWindow
{
id: window
//Pour les mobiles
minimumWidth: Qt.platform.os === "android" || Qt.platform.os === "ios" ? Screen.width : 800
minimumHeight: Qt.platform.os === "android" || Qt.platform.os === "ios" ? Screen.height : 400
visible: true
title: qsTr("Hello World")
//Les propriéts
property int idSousCategorie: -1 // valeur initiale par défaut
// Flag global pour éviter boucle infinie
property bool updating: false
//Le clavier virtuel
InputPanel
{
id: inputPanel
z: 99
x: 0
y: window.height
width: window.width
states: State
{
name: "visible"
when: inputPanel.active
PropertyChanges {
target: inputPanel
y: window.height - inputPanel.height
}
}
transitions: Transition
{
from: ""
to: "visible"
reversible: true
ParallelAnimation
{
NumberAnimation
{
properties: "y"
duration: 250
easing.type: Easing.InOutQuad
}
}
}
} //Fin du clavier virtuel
//---------------------------Vue principale---------------------------//
ScrollView
{
id: scrollView
anchors
{
left: parent.left
right: parent.right
top: parent.top
bottom: Qt.platform.os === "android" ?
parent.bottom :
inputPanel.top
}
clip: true
ScrollBar.vertical.policy: ScrollBar.AsNeeded // Changé de AlwaysOn à AsNeeded
ScrollBar.horizontal.policy: ScrollBar.AsNeeded
ScrollBar.vertical.interactive: true
ScrollBar.horizontal.interactive: true
// CORRECTION PRINCIPALE : Utiliser contentWidth et contentHeight
contentWidth: idLayoutPricipal.implicitWidth
contentHeight: idLayoutPricipal.implicitHeight
// La colonne qui contient tous les controles
ColumnLayout
{
id: idLayoutPricipal
// CORRECTION : Ne pas définir width/height explicitement
// Laisser le layout calculer sa taille naturellement
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
// Marges appliquées au layout principal
anchors.leftMargin: 20
anchors.rightMargin: 20
anchors.topMargin: 20
spacing: 20
//---------------------------La colonne qui contient le rectangle et l'icone de l'application---------------------------//
RowLayout
{
id: rootLayout
Layout.fillWidth: true
spacing: 10
// --------------------------------- Header ---------------------------------
Rectangle
{
id: idHeaderRect
Layout.fillWidth: true
height: idHeaderRow.implicitHeight + 20
color: "#cc65cc"
radius: 8
// Dégradé de couleur (conservé de votre version originale)
gradient: Gradient
{
GradientStop { position: 0.00; color: "#cc65cc" }
GradientStop { position: 0.01; color: "#dd1d1d" }
GradientStop { position: 1.00; color: "#ffffff" }
}
border.color: "#2129dd"
//---------------------------La ligne qui contient l'icone de l'application ainsi que le titre---------------------------//
RowLayout
{
id: idHeaderRow
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
spacing: 20
Image
{
source: "qrc:/Media/Icones/icoPrincipale64.ico"
width: 32
height: 32
}
Label
{
text: "Gestion budget"
font.pixelSize: 20
}
}
}
} //Fin de La colonne qui contient le rectangle et l'icone de l'application
//---------------------------La ligne qui contient les comboBox et leurs Labels---------------------------//
ColumnLayout // Changé de RowLayout à ColumnLayout pour plus de hauteur
{
Layout.fillWidth: true
spacing: 15
// 1-------- Colonne pour les comboBox et leurs Labels
ColumnLayout
{
Layout.fillWidth: true
spacing: 10
// Controle pour le Label Session
Label
{
text: "Session:"
Layout.preferredWidth: 100
Layout.alignment: Qt.AlignVCenter
}
// Controle pour la comboBox Session
ComboBox
{
id: idSessionCombo
Layout.fillWidth: true
Layout.minimumWidth: 250
textRole: "nom_de_session"
valueRole: "id_session"
currentIndex: 0
//Slot déclenché quand l'index de la ComboBox Session change
onCurrentIndexChanged: {
// Code à implémenter
}
}
// Controle pour le Label Catégorie
Label
{
text: "Catégorie:"
Layout.preferredWidth: 100
Layout.alignment: Qt.AlignVCenter
}
// Controle pour la comboBox Catégorie
ComboBox
{
id: idCategorieCombo
Layout.fillWidth: true
Layout.minimumWidth: 250
textRole: "nom_de_categorie"
valueRole: "id_categorie"
currentIndex: -1
//Slot déclenché quand l'index de la ComboBox Catégorie change
onCurrentIndexChanged: {
// Code à implémenter
}
}
// Controle pour le Label Sous-Catégorie
Label
{
text: "Sous-Catégorie:"
Layout.preferredWidth: 100
Layout.alignment: Qt.AlignVCenter
}
// Controle pour la comboBox Sous-Catégorie
ComboBox
{
id: idSousCategorieCombo
Layout.fillWidth: true
Layout.minimumWidth: 250
textRole: "nom_de_sc"
valueRole: "id_sous_categorie"
currentIndex: 0
onCurrentIndexChanged: {
// Code à implémenter
}
}
// Controle pour la Label Depense
Label
{
text: "Dépense:"
Layout.preferredWidth: 100
Layout.alignment: Qt.AlignVCenter
}
// Controle pour la ComboBox Depense
ComboBox
{
id: idDepenseCombo
Layout.fillWidth: true
Layout.minimumWidth: 250
textRole: "nom_de_depense"
valueRole: "id_depense"
currentIndex: 0
editable: true
}
//Controle pour Label Prix unitaire
Label
{
text: "Prix unitaire :"
Layout.preferredWidth: 100
Layout.alignment: Qt.AlignVCenter
}
// RowLayout pour le Controle TextField Prix unitaire et le Label euro
RowLayout
{
Layout.fillWidth: true
// Controle TextField Prix unitaire - Remplacer CustomTextField par TextField
TextField
{
id: idPrixUnitaireFieldText
Layout.fillWidth: true
placeholderText: "0.00"
inputMethodHints: Qt.ImhDigitsOnly
onEditingFinished: {
// Code à implémenter
}
onTextChanged: {
// Code à implémenter
}
}
//Controle Label pour symbole euro du prix unitaire
Label
{
text: " €"
Layout.preferredWidth: 20
Layout.alignment: Qt.AlignVCenter
}
}
// Controle pour Label Quantité
Label
{
text: "Quantité :"
Layout.preferredWidth: 100
Layout.alignment: Qt.AlignVCenter
}
// Controle pour TextField Quantité - Remplacer CustomTextField par TextField
TextField
{
id: idQuantiteFieldText
Layout.fillWidth: true
placeholderText: "1"
inputMethodHints: Qt.ImhDigitsOnly
onTextChanged: {
// Code à implémenter
}
onEditingFinished: {
// Code à implémenter
}
}
// Controle pour Label Prix total
Label
{
text: "Prix total :"
Layout.preferredWidth: 100
Layout.alignment: Qt.AlignVCenter
}
// Controle pour le TextField Prix total
RowLayout
{
Layout.fillWidth: true
// Prix total - Remplacer CustomTextField par TextField
TextField
{
id: idPrixTotalFieldText
Layout.fillWidth: true
placeholderText: "0.00"
inputMethodHints: Qt.ImhDigitsOnly
onTextChanged: {
// Code à implémenter
}
onEditingFinished: {
// Code à implémenter
}
}
//Controle Label pour symbole euro du prix total
Label
{
text: " €"
Layout.preferredWidth: 20
Layout.alignment: Qt.AlignVCenter
}
}
// Date
Label
{
text: "Date:"
Layout.preferredWidth: 100
}
TextField
{
id: idDateField
Layout.fillWidth: true
placeholderText: "JJ/MM/AAAA"
inputMethodHints: Qt.ImhDate
MouseArea
{
anchors.fill: parent
onClicked: dateDialog.open()
}
}
Popup
{
id: dateDialog
width: 300
height: 300
modal: true
focus: true
// Remplacer DatePicker par un calendrier simple ou un placeholder
Rectangle {
anchors.fill: parent
color: "#f0f0f0"
Text {
anchors.centerIn: parent
text: "Date Picker\n(à implémenter)"
}
MouseArea {
anchors.fill: parent
onClicked: {
idDateField.text = Qt.formatDate(new Date(), "dd/MM/yyyy")
dateDialog.close()
}
}
}
}
// Heure
Label
{
text: "Heure:"
Layout.preferredWidth: 100
}
TextField
{
id: idTimeField
Layout.fillWidth: true
placeholderText: "HH:MM"
inputMethodHints: Qt.ImhTime
MouseArea
{
anchors.fill: parent
onClicked: timeDialog.open()
}
}
Popup
{
id: timeDialog
width: 200
height: 200
modal: true
focus: true
// Remplacer TimePicker par un placeholder
Rectangle {
anchors.fill: parent
color: "#f0f0f0"
Column {
anchors.centerIn: parent
spacing: 10
Text {
text: "Time Picker\n(à implémenter)"
anchors.horizontalCenter: parent.horizontalCenter
}
Button {
text: "Valider"
anchors.horizontalCenter: parent.horizontalCenter
onClicked: {
idTimeField.text = Qt.formatTime(new Date(), "hh:mm")
timeDialog.close()
}
}
}
}
}
// Ajout d'éléments supplémentaires pour forcer le scroll
Repeater {
model: 10
Label {
text: "Élément test " + (index + 1)
Layout.fillWidth: true
Layout.preferredHeight: 40
background: Rectangle {
color: index % 2 ? "#e0e0e0" : "#f0f0f0"
}
}
}
} //Fin de Colonne pour les comboBox et leurs Labels
} //La fin de La ligne qui contient les comboBox et leurs Labels
// Ajout d'un spacer en bas
Item {
Layout.fillWidth: true
Layout.preferredHeight: 50
}
} //Fin du ColumnLayout principal
} //Fin de ScrollView
}