En esta página

Lugares (QML)

El ejemplo Lugares muestra cómo buscar Lugares y acceder al contenido relacionado.

El ejemplo Lugares muestra cómo buscar Lugares. En particular, muestra cómo se puede recuperar más información, como reseñas, imágenes y contenido relacionado.

Ejecución del ejemplo

Para ejecutar el ejemplo desde Qt Creatorabra el modo Welcome y seleccione el ejemplo de Examples. Para más información, consulte Qt Creator: Tutorial: Construir y ejecutar.

El ejemplo puede funcionar con cualquiera de los plugins de geo services disponibles. Sin embargo, algunos plugins pueden requerir plugin parameters adicional con el fin de funcionar correctamente. Plugin parameters se puede pasar en la línea de comandos utilizando el argumento --plugin, que toma la forma:

--plugin.<parameter name> <parameter value>

Consulte la documentación de cada uno de los plugins de servicios geográficos para obtener más información sobre los parámetros que admiten. El plugin por defecto utilizado en este ejemplo es Qt Location Open Street Map Plugin, que no requiere ningún parámetro.

Resumen

El ejemplo Lugares presenta una ventana de aplicación que muestra un mapa. En la parte superior de la ventana hay un cuadro de búsqueda, que se utiliza para introducir una consulta de búsqueda de lugar. Para buscar un lugar, introduzca un término de búsqueda en el cuadro de texto y haga clic en el icono de la lupa. Para buscar un lugar por categoría, haga clic en el icono de categoría para mostrar la lista de categorías disponibles y seleccione la categoría deseada. La consulta de búsqueda de lugares se referirá a lugares que estén cerca de la ubicación actual mostrada en el mapa.

Para algunos plugins, el cuadro de búsqueda proporciona sugerencias de términos de búsqueda cuando se introducen tres o más caracteres. Al seleccionar una de las sugerencias se realizará una búsqueda de lugares con el texto de búsqueda seleccionado.

Al hacer clic en un resultado de búsqueda, se mostrarán detalles sobre el lugar. Si un lugar tiene contenido enriquecido (editoriales, reseñas e imágenes), se puede acceder a él mediante los botones de la página de detalles. Para encontrar lugares similares, pulse el botón "Encontrar similares".

El proveedor de servicios geográficos puede cambiarse accediendo al menú "Proveedor".

Visualización de categorías

Antes de poder realizar una búsqueda por categorías, es necesario recuperar la lista de categorías disponibles. Para ello hay que crear un archivo CategoryModel.

CategoryModel {
    id: categoryModel
    hierarchical: true
}

El tipo CategoryModel proporciona un modelo de las categorías disponibles. Puede proporcionar una lista plana o un modelo de árbol jerárquico. En este ejemplo, utilizamos un modelo de árbol jerárquico, estableciendo la propiedad hierarchical en true. La propiedad plugin se establece durante la inicialización del ejemplo.

A continuación creamos un ListView para mostrar el modelo de categorías.

ListView {
    id: root
    property var categoryModel
    property var rootIndex

    signal searchCategory(var category)
    signal showSubcategories(var index)

    snapMode: ListView.SnapToItem

    model: DelegateModel {
        id: delegeteDataModel
        model: root.categoryModel
        rootIndex: root.rootIndex
        delegate: CategoryDelegate {
            width: ListView.view.width
            onSearchCategory: root.searchCategory(category);
            onShowSubcategories: root.showSubcategories(delegeteDataModel.modelIndex(index));
        }
    }
}

Debido a que se está utilizando un modelo jerárquico, se necesita un DelegateModel para proporcionar la funcionalidad de navegación. Si se utilizara un modelo de lista plana, la vista podría utilizar directamente CategoryModel.

La propiedad rootIndex establece el índice raíz del DelegateModel. Las categorías se muestran mediante el CategoryDelegate, que proporciona dos señales. La señal onShowSubcategories emite la señal showSubcategories() con el índice raíz al índice actual haciendo que se muestren las subcategorías de la categoría seleccionada. El manejador onSearchCategory emite la señal searchCategory() con un parámetro de categoría que indica qué categoría específica se ha elegido.

El CategoryDelegate muestra el nombre de la categoría y emite la señal searchCategory() cuando se hace clic en Label:

Label {
    id: labelItem
    text: category.name
    anchors.left: icon.right
    anchors.right: parent.right
    anchors.verticalCenter: parent.verticalCenter
}

TapHandler {
    id: tapHanlder
    onTapped: {
        if (model.hasModelChildren) {
            root.showSubcategories()
        } else {
            root.searchCategory()
        }
    }
}

Presentación de sugerencias de búsqueda

El tipo PlaceSearchSuggestionModel se utiliza para obtener sugerencias de términos de búsqueda basadas en un término de búsqueda parcialmente introducido.

Cada vez que se modifica el término de búsqueda introducido, se activa una nueva búsqueda de sugerencias.

SearchBar {
    id: searchBar
    onSearchTextChanged: function (searchText) {
        if (searchText.length >= 3 && suggestionModel != null) {
            suggestionModel.searchTerm = searchText;
            suggestionModel.update();
        }
    }
}

Las sugerencias sólo se consultan si la longitud del término de búsqueda es igual o superior a tres caracteres.

Cuando cambia el estado de PlaceSearchSuggestionModel, se muestran las sugerencias de búsqueda.

PlaceSearchSuggestionModel {
    id: suggestionModel
    searchArea: searchRegion

    onStatusChanged: {
        if (status == PlaceSearchSuggestionModel.Ready)
            stackView.showSuggestions()
    }
}

El objeto principal en el estado "SuggestionsShown" es el ListView que muestra las sugerencias de búsqueda.

ListView {
    id: suggestionView
    property var suggestionModel
    signal suggestionSelected(string text)

    model: suggestionModel
    delegate: Item {
        width: ListView.view.width
        height: label.height * 1.5
        Label {
            id: label
            text: suggestion
        }
        MouseArea {
            anchors.fill: parent
            onClicked: suggestionSelected(suggestion)
        }
    }
}

Se utiliza un objeto Label como delegado para mostrar el texto de la sugerencia. Al hacer clic en el término de búsqueda sugerido, se actualiza el término de búsqueda y se activa una búsqueda de lugar utilizando la sugerencia de búsqueda.

Búsqueda de lugares

El tipo PlaceSearchModel se utiliza para buscar lugares.

PlaceSearchModel {
    id: placeSearchModel
    searchArea: searchRegion

    function searchForCategory(category) {
        searchTerm = "";
        categories = category;
        recommendationId = "";
        searchArea = searchRegion
        limit = -1;
        update();
    }

    function searchForText(text) {
        searchTerm = text;
        categories = null;
        recommendationId = "";
        searchArea = searchRegion
        limit = -1;
        update();
    }

    function searchForRecommendations(placeId) {
        searchTerm = "";
        categories = null;
        recommendationId = placeId;
        searchArea = null;
        limit = -1;
        update();
    }

    onStatusChanged: {
        switch (status) {
        case PlaceSearchModel.Ready:
            if (count > 0)
                stackView.showPlaces()
            else
                stackView.showMessage(qsTr("Search Place Error"),qsTr("Place not found !"))
            break;
        case PlaceSearchModel.Error:
            stackView.showMessage(qsTr("Search Place Error"),errorString())
            break;
        }
    }
}

Primero se establecen algunas de las propiedades del modelo, que se utilizarán para formar la petición de búsqueda. La propiedad searchArea se establece en el objeto searchRegion que es un geoCircle con un centro que está vinculado a la ubicación actual mostrada en el Map.

Por último, definimos tres funciones de ayuda searchForCategory(), searchForText() y searchForRecommendations() que establecen las propiedades categories o searchTerm o recommendationId e invocan el método update() para iniciar la búsqueda de lugares. Los resultados de la búsqueda se muestran en ListView.

ListView {
    id: searchView

    property var placeSearchModel
    signal showPlaceDetails(var place, var distance)
    signal showMap()

    model: placeSearchModel
    delegate: SearchResultDelegate {
        width: ListView.view.width
        onShowPlaceDetails: function (place, distance) { searchView.showPlaceDetails(place, distance) }
        onSearchFor: function (query) { placeSearchModel.searchForText(query) }
    }

    footer: RowLayout {
        width: parent.width

        Button {
            text: qsTr("Previous")
            enabled: placeSearchModel.previousPagesAvailable
            onClicked: placeSearchModel.previousPage()
            Layout.alignment: Qt.AlignHCenter
        }

        Button {
            text: qsTr("Clear")
            onClicked: {
                placeSearchModel.reset()
                showMap()
            }
            Layout.alignment: Qt.AlignHCenter
        }

        Button {
            text: qsTr("Next")
            enabled: placeSearchModel.nextPagesAvailable
            onClicked: placeSearchModel.nextPage()
            Layout.alignment: Qt.AlignHCenter
        }
    }
}

El delegado utilizado en ListView, SearchResultDelegate, está diseñado para manejar múltiples tipos de resultados de búsqueda a través de un objeto Loader. Para resultados de tipo PlaceResult el delegado es:

Component {
    id: placeComponent
    Item {
        id: placeRoot
        width: root.width
        height: Math.max(icon.height, 3 * placeName.height)

        Rectangle {
            anchors.fill: parent
            color: "#44ffffff"
            visible: mouse.pressed
        }

        Rectangle {
            anchors.fill: parent
            color: "#dbffde"
            visible: model.sponsored !== undefined ? model.sponsored : false

            Label {
                text: qsTr("Sponsored result")
                horizontalAlignment: Text.AlignRight
                anchors.right: parent.right
                anchors.bottom: parent.bottom
                font.pixelSize: 8
                visible: model.sponsored !== undefined ? model.sponsored : false
            }
        }

        GridLayout {
            rows: 2
            columns: 2
            anchors.fill: parent
            anchors.leftMargin: 30
            flow: GridLayout.TopToBottom

            Image {
                // anchors.verticalCenter: parent.verticalCenter
                id:icon
                source: place.favorite ? Qt.resolvedUrl("../resources/star.png") : place.icon.url()
                Layout.rowSpan: 2
            }

            Label {
                id: placeName
                text: place.favorite ? place.favorite.name : place.name
                Layout.fillWidth: true
            }

            Label {
                id: distanceText
                font.italic: true
                text: Helper.formatDistance(distance)
                Layout.fillWidth: true
            }
        }

        Rectangle {
            anchors.left: parent.left
            anchors.right: parent.right
            anchors.margins: 15
            height: 1
            color: "#46a2da"
        }

        MouseArea {
            id: mouse
            anchors.fill: parent
            onClicked: {
                if (model.type === undefined || type === PlaceSearchModel.PlaceResult) {
                    if (!place.detailsFetched)
                        place.getDetails();
                    root.showPlaceDetails(model.place, model.distance);
                }
            }
        }
    }
}

Visualización del contenido del lugar

Los lugares pueden tener contenido enriquecido adicional, incluyendo editoriales, reseñas e imágenes. Al contenido enriquecido se accede a través de un conjunto de modelos. Los modelos de contenido no suelen ser creados directamente por el desarrollador de la aplicación, sino que se obtienen a partir de las propiedades editorialModel, reviewModel y imageModel del tipo Place.

ListView {
    id:view
    property Place place
    signal showEditorial(var editorial)
    model: place.editorialModel
    delegate: EditorialDelegate {
        width: ListView.view.width
        onShowEditorial: view.showEditorial(model)
    }
}

Proyecto de ejemplo @ code.qt.io

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.