功能描述
读取文本后进行显示,Qt中提供了QTextBrowser等控件可以用于显示文本内容;但是指定某一行文本高亮的功能,没有找到相应的方法。本人利用Qml实现了一个能够指定某行文本高亮的功能,但存在部分限制,还需完善。
效果
这里采用的是定时器,每隔1s更改行数号,自动递增。
环境
Ubuntu16.04+Qt5.7.1
功能分割
- 文件打开与读取部分由C++实现——class OpenFile;为Qml显示提供文本数据等;
- 显示部分由Qml实现——main.qml;
实现
这里使用了Qml中的ListView来进行显示,并写一个Component用于显示高亮,而指定某行高亮则使用index行号进行高亮显示。
class OpenFile
OpenFile.h文件中提供了如下的接口:
#ifndef OPENFILE_H
#define OPENFILE_H
#include <QObject>
#include <QFile>
#include <QApplication>
#include <QTimer>
#include <QUrl>
class OpenFile : public QObject
{
Q_OBJECT
public:
explicit OpenFile(QObject *parent = 0);
~OpenFile();
Q_INVOKABLE QStringList getFileTextList(QVariant filePath);
Q_INVOKABLE void start();//启动定时器,用于模拟行号改变
signals:
void lineIndexOutput(int index);
public slots:
void onTimeOut();
private:
QStringList m_fileContentList;
QTimer m_timer;
int m_lineIndex;
};
#endif // OPENFILE_H
OpenFile.cpp文件如下:
#include "OpenFile.h"
OpenFile::OpenFile(QObject *parent) : QObject(parent)
{
m_timer.setInterval(1000);
m_lineIndex = 0;
connect(&m_timer, SIGNAL(timeout()), this, SLOT(onTimeOut()));
}
OpenFile::~OpenFile()
{
}
QStringList OpenFile::getFileTextList(QVariant filePath)
{
//由于Qml中获取到的文件路径是Url类型,所以使用QVariant进行转化
QFile file(filePath.toUrl().toLocalFile());
QString fileContent = "";
/* open failed */
if (! file.open(QIODevice::ReadOnly|QIODevice::Text)) {
return m_fileContentList;
}
fileContent = file.readAll();
m_fileContentList = fileContent.split("\n");
return m_fileContentList;
}
void OpenFile::start()
{
m_timer.start();
}
void OpenFile::onTimeOut()
{
emit lineIndexOutput(m_lineIndex);
m_lineIndex++;
}
main.qml
qml文件如下:
import QtQuick 2.5
import QtQuick.Controls 1.4
import MyModel 1.0
import QtQuick.Dialogs 1.2
Rectangle {
id: root
width: 320
height: 480
color: "lightGray"
OpenFile {
id: openFile
}
MyTextBrowser {
id: textBrowser
width: parent.width
height: parent.height - 40
}
Connections {
target: openFile
onLineIndexOutput: {
textBrowser.lineIndex = index
}
}
FileDialog {
id: fileSelectDialog
nameFilters: ["Text files (*.txt *.c *.h *.cpp *.qml)", "All files (*)"]
onAccepted: {
textBrowser.model = openFile.getFileTextList(fileSelectDialog.fileUrl)
openFile.start()
}
}
Button {
id: openFileBtn
anchors.top: textBrowser.bottom
anchors.horizontalCenter: textBrowser.horizontalCenter
anchors.topMargin: 5
text: "OpenFile"
onClicked: {
fileSelectDialog.open()
}
}
}
MyTextBrowser.qml
自定义的文本显示控件内容如下:
import QtQuick 2.0
import QtQuick.Controls 1.4
Item {
id: root
property int lineIndex: 0
// property variant model
property alias model: textView.model
width: parent.width
height: parent.height
ScrollView {
width: parent.width
height: parent.height
ListView {
id: textView
width: parent.width - 20
currentIndex: lineIndex
delegate: delegateItem
highlight: highlightComponent
focus: true
}
}
Component {
id: delegateItem
Item {
width: textView.width
height: 65
Text {
//此处存疑,不明白modelData是什么意思,为什么必须这样写?
text: modelData
width: parent.width
height: parent.height
wrapMode: Text.WrapAnywhere
font.pixelSize: 14
}
}
}
Component {
id: highlightComponent
Rectangle {
color: "lightblue"
radius: 5
}
}
}
过程中遇到的问题
- 一开始不知道用什么组件来实现这样的效果,后面是想到Listview有每一行的分割以及自定义高亮的功能,因此耍了一个小聪明用Listview来实现;
- 在打开文件对话框中,使用了QML的FileDialog,FileDialog选中返回的文件路径时是以Url/Urls类型返回的,因此我将OpenFile中getFileTextList的参数处理为QVariant类型,通过QVariant->toUrl->toLocalFile得到本地的绝对文件路径;
- 在上面MyTextBrowser.qml中,Text此处的text:modelData,modelData是QML中某种内部变量吗?这里不明白为什么这样写(我这样写是因为参考了其他代码这样处理字符串进行显示)。希望大神不吝赐教。
Component {
id: delegateItem
Item {
width: textView.width
height: 65
Text {
//此处存疑,不明白modelData是什么意思,为什么必须这样写?
text: modelData
width: parent.width
height: parent.height
wrapMode: Text.WrapAnywhere
font.pixelSize: 14
}
}
}
问题与不足
- 从上面的gif图可以看出,当高亮达到最下面时,高亮行没有居中显示;
- 每一行的显示受限制,比如当每一行的文本很长时,需要修改Listview中每一行的高度或宽度,否则会造成文本显示重叠;