213 lines
7.7 KiB
QML
213 lines
7.7 KiB
QML
|
|
// =========================================
|
|||
|
|
// =============== 截图管理器 ===============
|
|||
|
|
// =========================================
|
|||
|
|
|
|||
|
|
import QtQuick 2.15
|
|||
|
|
import QtQuick.Window 2.15
|
|||
|
|
|
|||
|
|
Item {
|
|||
|
|
id: ssWinRoot
|
|||
|
|
|
|||
|
|
// ==================== 【接口】 ====================
|
|||
|
|
|
|||
|
|
// 开始一次截图。传入回调函数。
|
|||
|
|
function screenshot(callback) {
|
|||
|
|
// 重复调用验证
|
|||
|
|
if(running) {
|
|||
|
|
qmlapp.popup.simple(errorTitle, errorRepeat)
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
running = true
|
|||
|
|
// 获取所有屏幕的截图图像
|
|||
|
|
const grabList = getGrabList()
|
|||
|
|
// 遍历截图列表,收集覆盖窗口属性 argds
|
|||
|
|
let argds = []
|
|||
|
|
for(let i in grabList) {
|
|||
|
|
const g = grabList[i] // 截图属性
|
|||
|
|
// 合法性检查
|
|||
|
|
if(g.imgID.startsWith("[")) {
|
|||
|
|
qmlapp.popup.message(errorTitle,
|
|||
|
|
qsTr("显示器: %1\n错误信息: %2").arg(g.screenName).arg(g.imgID), "error")
|
|||
|
|
callback()
|
|||
|
|
running = false
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
const screen = Qt.application.screens[i] // 获取对应编号的屏幕
|
|||
|
|
if(screen.name !== g.screenName) {
|
|||
|
|
qmlapp.popup.message(errorTitle,
|
|||
|
|
qsTr("屏幕设备名称不相同:\n%1\n%2").arg(screen.name).arg(g.screenName), "error")
|
|||
|
|
callback()
|
|||
|
|
running = false
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
const argd = {
|
|||
|
|
imgID: g.imgID,
|
|||
|
|
screenName: screen.name,
|
|||
|
|
screen: screen, // 为Window设定所属屏幕属性
|
|||
|
|
screenRatio: screen.devicePixelRatio, // 屏幕缩放比
|
|||
|
|
x: screen.virtualX,
|
|||
|
|
y: screen.virtualY,
|
|||
|
|
width: screen.width,
|
|||
|
|
height: screen.height,
|
|||
|
|
screenshotEnd: ssWinRoot.ssEnd // 关闭函数
|
|||
|
|
}
|
|||
|
|
argds.push(argd)
|
|||
|
|
}
|
|||
|
|
// 记录回调
|
|||
|
|
lastCallback = callback
|
|||
|
|
if(winDict === undefined) winDict = {}
|
|||
|
|
// 生成覆盖窗口
|
|||
|
|
for(let a in argds) {
|
|||
|
|
const obj = ssWinComp.createObject(this, argds[a])
|
|||
|
|
winDict[argds[a].imgID] = obj
|
|||
|
|
}
|
|||
|
|
// 注册esc事件监听
|
|||
|
|
qmlapp.pubSub.subscribeGroup("<<esc>>", ssWinRoot, "ssEsc", "ssEsc")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 重复上一次截图区域
|
|||
|
|
function reScreenshot(callback) {
|
|||
|
|
// 重复调用验证
|
|||
|
|
if(running) {
|
|||
|
|
qmlapp.popup.simple(errorTitle, errorRepeat)
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
running = true
|
|||
|
|
if(!lastClipArgd) {
|
|||
|
|
qmlapp.popup.simple(qsTr("尚未记录截图区域"), "")
|
|||
|
|
callback()
|
|||
|
|
running = false
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
// 获取所有屏幕的截图图像
|
|||
|
|
const grabList = getGrabList()
|
|||
|
|
let errorMsg = "" // 缓存报错信息
|
|||
|
|
// 在截图列表中,寻找上一次截图所在的屏幕
|
|||
|
|
for(let i in grabList) {
|
|||
|
|
const g = grabList[i] // 截图属性
|
|||
|
|
// 合法性检查
|
|||
|
|
if(g.imgID.startsWith("[")) {
|
|||
|
|
errorMsg = g.imgID // 记录失败,跳过本轮
|
|||
|
|
continue
|
|||
|
|
}
|
|||
|
|
// 找到对应屏幕
|
|||
|
|
if(lastClipArgd.screenName === g.screenName) {
|
|||
|
|
// 向py汇报,获取裁剪后的imgID
|
|||
|
|
const clipImgID = imageConn.getClipImgID(g.imgID,
|
|||
|
|
lastClipArgd.clipX, lastClipArgd.clipY, lastClipArgd.clipW, lastClipArgd.clipH)
|
|||
|
|
// 成功 调用回调
|
|||
|
|
runLastCallback(clipImgID)
|
|||
|
|
running = false
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
// 失败,未找到相同屏幕
|
|||
|
|
lastClipArgd = undefined
|
|||
|
|
if(!errorMsg) errorMsg = qsTr("未找到匹配的屏幕")
|
|||
|
|
qmlapp.popup.simple(qsTr("重复截图失败"), errorMsg)
|
|||
|
|
runLastCallback()
|
|||
|
|
running = false
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 【同步】获取指定区域的截图ID,失败返回 "[Error]..."
|
|||
|
|
function getScreenshot(rect, screen=0) { // screen 屏幕编号
|
|||
|
|
// 无需验证 running
|
|||
|
|
// 获取所有屏幕的截图图像
|
|||
|
|
const grabList = getGrabList()
|
|||
|
|
// 参数检查
|
|||
|
|
if(!Number.isInteger(screen) || screen < 0 || screen >= grabList.length)
|
|||
|
|
return `[Error] Invalid screen=${screen}: must be an integer (0~${grabList.length-1})`
|
|||
|
|
if(rect.length != 4) // 不检查内部是否合法,getClipImgID会检查
|
|||
|
|
return `[Error] Invalid rect=${rect}: must be integers [x,y,w,h]`
|
|||
|
|
const grab = grabList[screen]
|
|||
|
|
const imgID = grab.imgID
|
|||
|
|
if(imgID.startsWith("[")) // 获取截图数据失败
|
|||
|
|
return imgID
|
|||
|
|
let [x, y, w, h] = rect
|
|||
|
|
// 补充缺省宽高
|
|||
|
|
if(w <= 0) w = grab.width - x
|
|||
|
|
if(h <= 0) h = grab.height - y
|
|||
|
|
// 返回裁剪后的imgID
|
|||
|
|
return imageConn.getClipImgID(imgID, x, y, w, h)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// =================================================
|
|||
|
|
|
|||
|
|
// 获取所有屏幕的截图图像
|
|||
|
|
function getGrabList() {
|
|||
|
|
/*
|
|||
|
|
返回列表(不为空),每项为:\n
|
|||
|
|
{
|
|||
|
|
"imgID": 图片ID 或 报错信息 "[Error]开头" ,
|
|||
|
|
"screenName": 显示器名称 ,
|
|||
|
|
"width": 截图宽度 ,
|
|||
|
|
"height": 截图高度 ,
|
|||
|
|
}
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
// 截图前等待时间
|
|||
|
|
let wait = 0
|
|||
|
|
// 需要隐藏主窗口
|
|||
|
|
if(qmlapp.globalConfigs.getValue("screenshot.hideWindow")) {
|
|||
|
|
// 若主窗口可见,则记录位置,避免linux隐藏→显示主窗口后位置偏移。
|
|||
|
|
if(qmlapp.mainWin.getVisibility())
|
|||
|
|
qmlapp.mainWin.saveGeometry()
|
|||
|
|
qmlapp.mainWin.setVisibility(false)
|
|||
|
|
wait = qmlapp.globalConfigs.getValue("screenshot.hideWindowTime")
|
|||
|
|
}
|
|||
|
|
// 获取所有屏幕的截图
|
|||
|
|
const grabList = imageConn.getScreenshot(wait)
|
|||
|
|
return grabList
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Esc退出截图
|
|||
|
|
function ssEsc() {
|
|||
|
|
const argd = {clipX: -1, clipY: -1, clipW: -1, clipH: -1}
|
|||
|
|
ssEnd(argd)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 截图窗口操作完毕的回调
|
|||
|
|
function ssEnd(argd) {
|
|||
|
|
// 注销esc事件监听
|
|||
|
|
qmlapp.pubSub.unsubscribeGroup("ssEsc")
|
|||
|
|
// 关闭所有覆盖窗口
|
|||
|
|
for (let key in winDict) {
|
|||
|
|
winDict[key].destroy()
|
|||
|
|
}
|
|||
|
|
winDict = {}
|
|||
|
|
// 检测是否有效。如果无效,可能是按Esc退出了截图流程
|
|||
|
|
if(argd.clipX<0 || argd.clipY<0 || argd.clipW<1 || argd.clipH<1 || !argd.imgID) {
|
|||
|
|
runLastCallback()
|
|||
|
|
lastClipArgd = undefined
|
|||
|
|
running = false
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
// 记录当前截图信息
|
|||
|
|
lastClipArgd = argd
|
|||
|
|
// 向py汇报,获取裁剪后的imgID
|
|||
|
|
const clipImgID = imageConn.getClipImgID(argd.imgID, argd.clipX, argd.clipY, argd.clipW, argd.clipH)
|
|||
|
|
// 调用回调
|
|||
|
|
runLastCallback(clipImgID)
|
|||
|
|
running = false
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 调用上级回调
|
|||
|
|
function runLastCallback(clipImgID) {
|
|||
|
|
if (lastCallback && typeof lastCallback === "function") {
|
|||
|
|
lastCallback(clipImgID)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
property string errorTitle: qsTr("截图失败")
|
|||
|
|
property string errorRepeat: qsTr("上次截图操作未结束,不能进行新的截图!")
|
|||
|
|
property bool running: false // 当前是否正在截图
|
|||
|
|
property var lastClipArgd: undefined // 最后一次截图的信息
|
|||
|
|
property var lastCallback: undefined // 截图完毕的回调,得到 clipImgID
|
|||
|
|
property var winDict: {} // 存放当前已打开的窗口
|
|||
|
|
property QtObject imageConn: qmlapp.imageManager.imageConnector
|
|||
|
|
|
|||
|
|
Component {
|
|||
|
|
id: ssWinComp
|
|||
|
|
ScreenshotWindowComp { }
|
|||
|
|
}
|
|||
|
|
}
|