176 lines
6.5 KiB
QML
176 lines
6.5 KiB
QML
|
|
// =======================================
|
|||
|
|
// =============== 结果文本 ===============
|
|||
|
|
// =======================================
|
|||
|
|
|
|||
|
|
import QtQuick 2.15
|
|||
|
|
import QtQuick.Controls 2.15
|
|||
|
|
import QtQuick.Layouts 1.15
|
|||
|
|
import "../"
|
|||
|
|
|
|||
|
|
Item {
|
|||
|
|
id: resultRoot
|
|||
|
|
|
|||
|
|
property string status_: "" // 状态, text / noText / error
|
|||
|
|
property alias textLeft: textLeft_.text
|
|||
|
|
property string textRight: ""
|
|||
|
|
property alias textMain: textMain_.text
|
|||
|
|
property alias activeFocus_: textMain_.activeFocus // 输入框焦点
|
|||
|
|
property int index_
|
|||
|
|
// 选取文字
|
|||
|
|
property int selectL: -1
|
|||
|
|
property int selectR: -1
|
|||
|
|
property int selectUpdate: 0 // 只要有变化,就刷新选中
|
|||
|
|
// 外部函数
|
|||
|
|
property var copy: undefined // 复制选中
|
|||
|
|
property var copyAll: undefined // 复制全部
|
|||
|
|
property var selectSingle: undefined // 选中单个文本框
|
|||
|
|
property var selectAll: undefined // 所有文本框全选
|
|||
|
|
property var selectDel: undefined // 删除单个
|
|||
|
|
property var selectAllDel: undefined // 清空
|
|||
|
|
|
|||
|
|
// 传入一个相对于item的坐标,返回该坐标位于this组件的什么位置。
|
|||
|
|
// undefined:不在组件中 | -1:顶部信息栏 | 0~N:所在字符的下标
|
|||
|
|
function where(item, mx, my) {
|
|||
|
|
const localPoint = this.mapFromItem(item, mx, my)
|
|||
|
|
if(!this.contains(localPoint)) {
|
|||
|
|
return undefined
|
|||
|
|
}
|
|||
|
|
if(resultTop.contains(localPoint)) {
|
|||
|
|
return -1
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
const textPoint = textMain_.mapFromItem(item, mx, my)
|
|||
|
|
const textPos = textMain_.positionAt(textPoint.x, textPoint.y)
|
|||
|
|
return textPos
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
// 将光标移到指定位置并激活焦点。
|
|||
|
|
function focus(pos=-1) {
|
|||
|
|
if(pos >= 0 && textMain_.cursorPosition !== pos) {
|
|||
|
|
textMain_.cursorPosition = pos
|
|||
|
|
}
|
|||
|
|
if(!textMain_.activeFocus) {
|
|||
|
|
textMain_.forceActiveFocus() // 获取焦点
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
function toUpdateSelect() {
|
|||
|
|
if(selectL<0 || selectR<0)
|
|||
|
|
textMain_.deselect()
|
|||
|
|
else
|
|||
|
|
textMain_.select(selectL, selectR)
|
|||
|
|
}
|
|||
|
|
onSelectUpdateChanged: toUpdateSelect()
|
|||
|
|
TableView.onReused: toUpdateSelect()
|
|||
|
|
Component.onCompleted: toUpdateSelect()
|
|||
|
|
|
|||
|
|
|
|||
|
|
// 高度适应子组件
|
|||
|
|
implicitHeight: resultTop.height+resultBottom.height+size_.smallSpacing
|
|||
|
|
height: resultTop.height+resultBottom.height+size_.smallSpacing
|
|||
|
|
property var onTextHeightChanged // 当文字输入导致高度改变时,调用的函数
|
|||
|
|
|
|||
|
|
onHeightChanged: { // 高度改变时,通知父级
|
|||
|
|
// 必须文本框获得焦点时才触发
|
|||
|
|
if(textMain_.activeFocus && (typeof onTextHeightChanged === "function"))
|
|||
|
|
onTextHeightChanged()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 顶部信息
|
|||
|
|
Item {
|
|||
|
|
id: resultTop
|
|||
|
|
anchors.top: parent.top
|
|||
|
|
anchors.left: parent.left
|
|||
|
|
anchors.right: parent.right
|
|||
|
|
anchors.leftMargin: size_.smallSpacing
|
|||
|
|
anchors.rightMargin: size_.smallSpacing
|
|||
|
|
height: size_.smallLine + size_.spacing*2
|
|||
|
|
|
|||
|
|
// 图片名称
|
|||
|
|
Text_ {
|
|||
|
|
id: textLeft_
|
|||
|
|
anchors.left: parent.left
|
|||
|
|
anchors.right: textRight_.left
|
|||
|
|
anchors.bottom: parent.bottom
|
|||
|
|
anchors.rightMargin: size_.spacing
|
|||
|
|
anchors.bottomMargin: size_.smallSpacing
|
|||
|
|
color: theme.subTextColor
|
|||
|
|
font.pixelSize: size_.smallText
|
|||
|
|
font.family: theme.dataFontFamily
|
|||
|
|
clip: true
|
|||
|
|
elide: Text.ElideLeft
|
|||
|
|
}
|
|||
|
|
// 日期时间
|
|||
|
|
Text_ {
|
|||
|
|
id: textRight_
|
|||
|
|
anchors.right: btnRight.left
|
|||
|
|
anchors.bottom: parent.bottom
|
|||
|
|
anchors.bottomMargin: size_.smallSpacing
|
|||
|
|
color: theme.subTextColor
|
|||
|
|
font.pixelSize: size_.smallText
|
|||
|
|
text: textRight + " | "
|
|||
|
|
}
|
|||
|
|
// 复制按钮
|
|||
|
|
Text_ {
|
|||
|
|
id: btnRight
|
|||
|
|
anchors.right: parent.right
|
|||
|
|
anchors.bottom: parent.bottom
|
|||
|
|
anchors.bottomMargin: size_.smallSpacing
|
|||
|
|
color: theme.specialTextColor
|
|||
|
|
font.pixelSize: size_.smallText
|
|||
|
|
text: qsTr("复制")
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 下方主要文字内容
|
|||
|
|
Rectangle {
|
|||
|
|
id: resultBottom
|
|||
|
|
color: theme.bgColor
|
|||
|
|
anchors.top: resultTop.bottom
|
|||
|
|
anchors.left: parent.left
|
|||
|
|
anchors.right: parent.right
|
|||
|
|
// anchors.topMargin: size_.smallSpacing
|
|||
|
|
radius: size_.baseRadius
|
|||
|
|
height: textMain_.height
|
|||
|
|
|
|||
|
|
TextEdit_ {
|
|||
|
|
id: textMain_
|
|||
|
|
anchors.left: parent.left
|
|||
|
|
anchors.right: parent.right
|
|||
|
|
anchors.leftMargin: size_.smallSpacing
|
|||
|
|
anchors.rightMargin: size_.smallSpacing
|
|||
|
|
readOnly: false // 可编辑
|
|||
|
|
persistentSelection: true // 丢失焦点时,保留选区
|
|||
|
|
color: status_==="error"? theme.noColor:theme.textColor
|
|||
|
|
|
|||
|
|
// 按键事件。响应并拦截:单双击 Ctrl+C ,双击 Ctrl+A
|
|||
|
|
property int keyDoubleTime: 300 // 双击毫秒
|
|||
|
|
property int lastUpTime: -1 // 上次按键抬起的时间戳。需要截取后8位以免int放不下
|
|||
|
|
property int lastKey: -1 // 上次按键的键值
|
|||
|
|
property var listeningKeys: [Qt.Key_A, Qt.Key_C, Qt.Key_D]
|
|||
|
|
Keys.onPressed: {
|
|||
|
|
if (event.modifiers & Qt.ControlModifier) {
|
|||
|
|
if (listeningKeys.includes(event.key)) {
|
|||
|
|
event.accepted = true // 拦截按键
|
|||
|
|
const t = Date.now() & 0xFFFFFFFF
|
|||
|
|
// 双击
|
|||
|
|
if(t - lastUpTime <= keyDoubleTime && lastKey==event.key) {
|
|||
|
|
event.key===Qt.Key_A && resultRoot.selectAll && resultRoot.selectAll()
|
|||
|
|
event.key===Qt.Key_C && resultRoot.copyAll && resultRoot.copyAll()
|
|||
|
|
event.key===Qt.Key_D && resultRoot.selectAllDel && resultRoot.selectAllDel()
|
|||
|
|
}
|
|||
|
|
else { // 单击
|
|||
|
|
event.key===Qt.Key_A && resultRoot.selectSingle && resultRoot.selectSingle()
|
|||
|
|
event.key===Qt.Key_C && resultRoot.copy && resultRoot.copy()
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
Keys.onReleased: {
|
|||
|
|
if (listeningKeys.includes(event.key)) {
|
|||
|
|
lastUpTime = Date.now() & 0xFFFFFFFF
|
|||
|
|
lastKey = event.key
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|