Qt Quick Image Viewer/bg
[toc align_right="yes" depth="3"]
Български English
Плавно приплъзване на изображенията в Qt Quick
[YouTubeID:zg6GxFpQeWU]
Въведение
Тази къса статия показва как да създадете програма за разглеждане на картинки с плавен и приятен интерфейс, като използвате Qt Quick. Ще използваме "ListView":http://developer.qt.nokia.com/doc/qt-4.7/qml-listview.html и "FolderListModel":http://developer.qt.nokia.com/doc/qt-4.7/src-imports-folderlistmodel.html за да създадем програма за разглеждане на картинки на 25 реда код. Въпреки, че може да изглежда като доста лесен проблем, трябва да знаете няколко концепции. Стъпка по стъпка, ще покажем, че ListView може да служи като такава програма.
За да следвате тези напътствия, вие се нуждаете от инструмента qmlviewer и допълнителният qtquick компонент folderlistmodel. Ако използвате някоя от последните версии на Убунту Линукс, просто инсталирайте пакетите qt4-qmlviewer, libqt4-declarative-folderlistmodel и libqt4-dev packages. Също така всички файлове в този урок могат да бъдат свалени от "gitorious":https://www.gitorious.org/qt-training/qml-demos/trees/master/flickscroller.
Минималните изисквания за Qt Quick са версия 1.0, която идва с Qt от версия 4.7.1.
Създаване на приложението
Създайте една папка, сложете в нея някакви картинки и нека да започнем със следният код:
import QtQuick 1.0
import Qt.labs.folderlistmodel 1.0
ListView {
id: view
width: 640
height: 360
model: FolderListModel {
nameFilters: [ "'''.JPG", "'''.jpg" ]
folder: "images"
sortField: FolderListModel.Name
}
delegate: Image {
source: filePath
width: view.width
height: view.height
smooth: true
}
orientation: ListView.Horizontal
snapMode: ListView.SnapToItem
}
Запазете кода в същата директория като картинките с име FlickScroller.qml. Нашият подход е тривиален: Създаване на хоризонтално ListView, използване на FolderListModel, за да получим имената на картинките и използване на Image компонента, за да покажем картинките. Докато това изглежда като очевидният начин за справяне с проблема, ще забележете, че има няколко проблема. Пуснете кода в qmlviewer, за да видите какво не е наред. Първо картинките са деформирани. Второ, производителността е ужасна, или поне далече от плавното предвижване, въпреки че ListView го поддържа много добре. Та, какво става тук? В общи линии ListView-to създава своите Image делегати, когато те трябва да е покажат, т.е когато картинката влезе във видимата част на ListView-то. Което е добре, защото не зареждаме цялата папка със снимки предварително, туй като може да имаме стотици картинки. Можем да подобрим скоростта на зареждането като използваме атрибута Image.sourceSize. Вътрешно той ще използва "QImageReader":http://developer.qt.nokia.com/doc/qt-4.7/qimagereader.html и ще зареди картинката с необходимите размери, което ще намали използването на паметта и времето за зареждане. Добавете следният ред към атрибутите на Image и опитайте пак:
sourceSize.width: width
Друго нещо, което трябва да знаете тук е, че ако зададете само единият размер на картинката, за другият ще бъде използван реалният размер. Ако зададете и двата размера, това неминуемо ще наруши съотношенето височина/ширина. Което ни води до следващият проблем - развалено съотношение височина/ширина. Имате два избора за да оправите това:
fillMode: Image.PreserveAspectCrop // или: Image.PreserveAspectFit
Добавете този параметър към Image делегата и вижте какво се случва. Image.PreserveAspectCrop прави картинката с размери ширина и височина, без да нарушава съотнощението , но някои части от картинката може да са отрязани. Image.PreserveAspectFit от друга страна смалява картинката така, че да се събере в дадените ширина и височина, но може да има празни полета.
Използване на много ядра
Qt Quick ви позволява да използвате повече от една нишка, но това зависи от вас и за какво устройство правите приложението. Като за начало трябва да знаете, че картинките винаги се зареждат синхронно. Това означава, че Image задържа изпълнението на QML, кода докато не успее да зареди изобравението. Може да звучи лошо, но няма ли да е по-добре простo да показва празен правоъгълник докато картинката се зареди? Можете да пробвате този вариант като добавите следният ред към Image делегата:
asynchronous: true
Както може би сте забелязали, скролирането е доста по гладко от преди, но с цената на премигвания, тъй като може да отнеме до 100мс, докато картинката се зареди. За наш късмет, това може да се оправи! За да постигнем напълно гладко и плавно скролиране, ще направим така, че асинхронното зареждане на картинките да става извън видимата част, като използваме кеш буфера на ListView. ListView ни предоставя атрибута cacheBuffer, който дефинира колко делегата да да бъдат заредени преди и след видимата зона. cacheBuffer се измерва в брой пиксели и дефинира размера на частта от ListView-то, в която делегатите трябва да се кешират. Ако делегати излязат от тази област, те се унищожават. Ако навлязат в зоната, те се създават. По подразбиране cacheBuffer е нула и за това ние виждаме как се създават делегатите. За това нека да сложим cacheBuffer на някаква достатъчна стойност:
ListView {
…
cacheBuffer: width * 4
…
}
В нашият пример, това ще зарежда предварително по 4 картинки преди и след видимата зона. Когато потребителя започне да се движи по ListView-то, там ще има вече до 4 заредени в паметта изображения, които да гарантират плавно придвижване и други ще се зареждат в невидимата част.
Фина настройка
Ако продължава да има някакви премигвания, можете да стартирате qmlviewer с опцията -opengl.