弹窗功能
This commit is contained in:
+25
-5
@@ -31,7 +31,7 @@ qt_add_executable(FancyInputQt
|
|||||||
src/main.cpp
|
src/main.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
# ============ QML 模块 1:FancyInput.Controls(用户自定义控件) ============
|
# ============ QML 模块 1:FancyInput.Controls(用户自定义控件,≈ WPF UserControl) ============
|
||||||
# 控件文件放在 src/qml/controls/ 目录下,GLOB 自动收集:
|
# 控件文件放在 src/qml/controls/ 目录下,GLOB 自动收集:
|
||||||
# 以后新增控件只需放 .qml 文件,无需修改本文件。
|
# 以后新增控件只需放 .qml 文件,无需修改本文件。
|
||||||
file(GLOB CONTROLS_QML_FILES CONFIGURE_DEPENDS
|
file(GLOB CONTROLS_QML_FILES CONFIGURE_DEPENDS
|
||||||
@@ -53,20 +53,40 @@ qt_add_qml_module(FancyInputControls
|
|||||||
${CONTROLS_QML_FILES}
|
${CONTROLS_QML_FILES}
|
||||||
)
|
)
|
||||||
|
|
||||||
# ============ QML 模块 2:FancyInputQt(App 主界面) ============
|
# ============ QML 模块 2:FancyInput.Windows(窗口组件,≈ WPF Window) ============
|
||||||
|
# 窗口文件放在 src/qml/windows/ 目录下,GLOB 自动收集:
|
||||||
|
# 以后新增窗口只需放 .qml 文件,无需修改本文件。
|
||||||
|
file(GLOB WINDOWS_QML_FILES CONFIGURE_DEPENDS
|
||||||
|
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||||
|
"src/qml/windows/*.qml"
|
||||||
|
)
|
||||||
|
|
||||||
|
qt_add_qml_module(FancyInputWindows
|
||||||
|
STATIC # 编译为静态库,链接进 exe
|
||||||
|
URI FancyInput.Windows
|
||||||
|
VERSION 1.0
|
||||||
|
QML_FILES
|
||||||
|
${WINDOWS_QML_FILES}
|
||||||
|
DEPENDENCIES
|
||||||
|
FancyInputControls # 窗口里会用自定义控件
|
||||||
|
)
|
||||||
|
|
||||||
|
# ============ QML 模块 3:FancyInputQt(App 主界面) ============
|
||||||
qt_add_qml_module(FancyInputQt
|
qt_add_qml_module(FancyInputQt
|
||||||
URI FancyInputQt
|
URI FancyInputQt
|
||||||
VERSION 1.0
|
VERSION 1.0
|
||||||
QML_FILES
|
QML_FILES
|
||||||
src/qml/Main.qml
|
src/qml/Main.qml # 主界面内容(Rectangle 根,可可视化编辑)
|
||||||
|
src/qml/MainWindow.qml # 主窗口包装(Window 根)
|
||||||
DEPENDENCIES
|
DEPENDENCIES
|
||||||
FancyInputControls
|
FancyInputControls
|
||||||
|
FancyInputWindows
|
||||||
)
|
)
|
||||||
|
|
||||||
# ============ 链接 ============
|
# ============ 链接 ============
|
||||||
target_link_libraries(FancyInputQt PRIVATE
|
target_link_libraries(FancyInputQt PRIVATE
|
||||||
FancyInputControls # 控件模块(含 QML 资源)
|
FancyInputControls # 控件模块(含 QML 资源)
|
||||||
FancyInputControlsplugin # 控件模块的静态插件,必须链接,否则运行时找不到模块
|
FancyInputWindows # 窗口模块(含 QML 资源)
|
||||||
Qt6::Core Qt6::Gui Qt6::Qml Qt6::Quick Qt6::QuickControls2
|
Qt6::Core Qt6::Gui Qt6::Qml Qt6::Quick Qt6::QuickControls2
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -94,7 +114,7 @@ if(WIN32)
|
|||||||
# 2. 体积优化:删除未使用的 Qt 组件
|
# 2. 体积优化:删除未使用的 Qt 组件
|
||||||
set(DEPLOY_DIR "${CMAKE_SOURCE_DIR}/bin/${CMAKE_BUILD_TYPE}")
|
set(DEPLOY_DIR "${CMAKE_SOURCE_DIR}/bin/${CMAKE_BUILD_TYPE}")
|
||||||
|
|
||||||
# 2.1 未使用的 QuickControls2 风格(默认只需 Windows/Basic/Fusion)
|
# 2.1 未使用的 QuickControls2 风格(程序显式锁定 Basic,其余全部可删)
|
||||||
set(UNUSED_STYLES
|
set(UNUSED_STYLES
|
||||||
"${DEPLOY_DIR}/qml/QtQuick/Controls/FluentWinUI3"
|
"${DEPLOY_DIR}/qml/QtQuick/Controls/FluentWinUI3"
|
||||||
"${DEPLOY_DIR}/qml/QtQuick/Controls/Material"
|
"${DEPLOY_DIR}/qml/QtQuick/Controls/Material"
|
||||||
|
|||||||
+8
-1
@@ -9,6 +9,11 @@ int main(int argc, char *argv[])
|
|||||||
app.setApplicationName("FancyInput");
|
app.setApplicationName("FancyInput");
|
||||||
app.setApplicationVersion("1.2.0");
|
app.setApplicationVersion("1.2.0");
|
||||||
|
|
||||||
|
// 显式锁定 QuickControls2 风格为 Basic:
|
||||||
|
// 部署时裁剪掉了 Material/Universal/Imagine/FluentWinUI3,
|
||||||
|
// 若不显式指定,Qt 6.7+ 默认 FluentWinUI3,找不到会直接崩溃。
|
||||||
|
qputenv("QT_QUICK_CONTROLS_STYLE", "Basic");
|
||||||
|
|
||||||
// Qt 6 默认启用高 DPI 缩放,叠层/遮罩坐标后续用 devicePixelRatio 归一化
|
// Qt 6 默认启用高 DPI 缩放,叠层/遮罩坐标后续用 devicePixelRatio 归一化
|
||||||
|
|
||||||
QQmlApplicationEngine engine;
|
QQmlApplicationEngine engine;
|
||||||
@@ -24,7 +29,9 @@ int main(int argc, char *argv[])
|
|||||||
&app, []() { QCoreApplication::exit(-1); },
|
&app, []() { QCoreApplication::exit(-1); },
|
||||||
Qt::QueuedConnection);
|
Qt::QueuedConnection);
|
||||||
|
|
||||||
engine.loadFromModule("FancyInputQt", "Main");
|
// 加载 MainWindow.qml(Window 壳,内含 Rectangle 根的主界面 Main.qml):
|
||||||
|
// 窗口级属性与内容自适应由 QML 侧处理,C++ 保持最简。
|
||||||
|
engine.loadFromModule("FancyInputQt", "MainWindow");
|
||||||
|
|
||||||
return app.exec();
|
return app.exec();
|
||||||
}
|
}
|
||||||
|
|||||||
+77
-7
@@ -2,18 +2,66 @@
|
|||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import FancyInput.Controls
|
import FancyInput.Controls
|
||||||
|
import FancyInput.Windows
|
||||||
|
|
||||||
// 阶段 0:Hello World 骨架
|
// 主界面(根元素为 Rectangle —— Qt Creator 设计模式可可视化编辑)
|
||||||
// 窗口尺寸沿用 WPF 主窗 600x480,主题色 #651F65
|
// 由 main.cpp 用 QQuickWindow 包装成主窗口。
|
||||||
ApplicationWindow {
|
Rectangle {
|
||||||
id: root
|
id: root
|
||||||
width: 600
|
width: 600
|
||||||
height: 480
|
height: 480
|
||||||
visible: true
|
|
||||||
title: qsTr("FancyInput · Qt 迁移版(阶段 0)")
|
|
||||||
|
|
||||||
color: Theme.background
|
color: Theme.background
|
||||||
|
|
||||||
|
property int clickCount: 0
|
||||||
|
|
||||||
|
// 弹独立窗口:统一包装器现包装(等价 WPF 的 new SettingsWindow().Show())
|
||||||
|
// 关键:createObject 的 parent 传 root(主窗口)→ FancyWindow 自动成为
|
||||||
|
// transient parent 窗口(= WPF 的 Owner)。有了它:
|
||||||
|
// · 非模态:随主窗口最小化/关闭,任务栏不单列
|
||||||
|
// · 模态:Qt.WindowModal 在同一窗口组内生效,主窗口被系统禁用,
|
||||||
|
// 点击主窗口时 Windows 自带标题栏闪烁反馈(同 WPF ShowDialog)
|
||||||
|
function openSettingsWindow(modal) {
|
||||||
|
var win = settingsWindowComp.createObject(modal ? root : null, { modal: modal })
|
||||||
|
if (win) win.show()
|
||||||
|
}
|
||||||
|
// 打开无边框透明悬浮窗(WPF WindowStyle=None + AllowsTransparency + Topmost)
|
||||||
|
function openOverlayWindow() {
|
||||||
|
var win = overlayWindowComp.createObject(null, {})
|
||||||
|
if (win) win.show()
|
||||||
|
}
|
||||||
|
// 设置窗口:FancyWindow 包装 SettingsWindow 内容
|
||||||
|
Component {
|
||||||
|
id: settingsWindowComp
|
||||||
|
FancyWindow {
|
||||||
|
width: 480
|
||||||
|
height: 360
|
||||||
|
windowTitle: qsTr("设置 · FancyInput")
|
||||||
|
|
||||||
|
SettingsWindow {
|
||||||
|
anchors.fill: parent
|
||||||
|
onCloseRequested: rootWindow.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 悬浮窗:无边框 + 透明 + 置顶 + 工具窗(FancyWindow 一键配置)
|
||||||
|
Component {
|
||||||
|
id: overlayWindowComp
|
||||||
|
FancyWindow {
|
||||||
|
width: 280
|
||||||
|
height: 180
|
||||||
|
frameless: true
|
||||||
|
transparent: true
|
||||||
|
alwaysOnTop: true
|
||||||
|
toolWindow: true
|
||||||
|
|
||||||
|
OverlayWindow {
|
||||||
|
anchors.fill: parent
|
||||||
|
onCloseRequested: rootWindow.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
spacing: 16
|
spacing: 16
|
||||||
@@ -63,7 +111,29 @@ ApplicationWindow {
|
|||||||
console.log("点击次数:", root.clickCount)
|
console.log("点击次数:", root.clickCount)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 打开独立窗口(WPF Window.Show 等价)
|
||||||
|
Button {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
text: qsTr("打开设置窗口")
|
||||||
|
font.family: Theme.fontFamily
|
||||||
|
onClicked: root.openSettingsWindow(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
property int clickCount: 0
|
// 打开模态窗口(WPF Window.ShowDialog 等价)
|
||||||
|
Button {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
text: qsTr("打开模态窗口")
|
||||||
|
font.family: Theme.fontFamily
|
||||||
|
onClicked: root.openSettingsWindow(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打开无边框透明悬浮窗(WPF 悬浮窗等价)
|
||||||
|
Button {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
text: qsTr("打开悬浮窗")
|
||||||
|
font.family: Theme.fontFamily
|
||||||
|
onClicked: root.openOverlayWindow()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import QtQuick
|
||||||
|
import FancyInput.Controls
|
||||||
|
import FancyInput.Windows
|
||||||
|
|
||||||
|
// 主窗口:用统一包装器 FancyWindow 包装主界面内容
|
||||||
|
// 内容在 Main.qml(Rectangle 根,Qt Creator 可可视化编辑)
|
||||||
|
// main.cpp 通过 loadFromModule("FancyInputQt", "MainWindow") 加载本文件。
|
||||||
|
FancyWindow {
|
||||||
|
id: win
|
||||||
|
width: 600
|
||||||
|
height: 480
|
||||||
|
visible: true
|
||||||
|
windowTitle: qsTr("FancyInput · Qt 迁移版(阶段 0)")
|
||||||
|
|
||||||
|
// 内容组件:anchors.fill 跟随窗口缩放
|
||||||
|
Main {
|
||||||
|
anchors.fill: parent
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
import QtQuick
|
||||||
|
|
||||||
|
// 统一窗口包装器(等价 WPF 的 Window 类)
|
||||||
|
//
|
||||||
|
// 用法:内容组件一律保持 Rectangle 根(Qt Creator 设计模式可可视化编辑),
|
||||||
|
// 需要窗口时用本包装器现包装即可:
|
||||||
|
//
|
||||||
|
// FancyWindow {
|
||||||
|
// width: 480
|
||||||
|
// height: 360
|
||||||
|
// windowTitle: qsTr("设置")
|
||||||
|
// modal: true // 模态(WPF ShowDialog 等价)
|
||||||
|
// SettingsWindow { anchors.fill: parent }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // 无边框透明悬浮窗(WPF WindowStyle=None + AllowsTransparency + Topmost)
|
||||||
|
// FancyWindow {
|
||||||
|
// frameless: true
|
||||||
|
// transparent: true
|
||||||
|
// alwaysOnTop: true
|
||||||
|
// toolWindow: true
|
||||||
|
// OverlayWindow { anchors.fill: parent }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// 子项(内容组件)直接写在包装器里即可 —— Window 的 data 默认行为
|
||||||
|
// 会自动把 Item 子项挂到内容区(contentItem)。
|
||||||
|
Window {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
// 内容组件可通过 rootWindow 访问包装器(如 rootWindow.close() 关窗)
|
||||||
|
// 固定别名,统一命名,避免每个包装处都要 id 转发
|
||||||
|
property alias rootWindow: root
|
||||||
|
|
||||||
|
// ===== 窗口级属性(对齐 WPF Window) =====
|
||||||
|
property string windowTitle: "" // 标题(WPF Title)
|
||||||
|
property bool modal: false // true=ShowDialog(WindowModal),false=Show
|
||||||
|
property bool frameless: false // 无边框(WPF WindowStyle=None)
|
||||||
|
property bool transparent: false // 透明背景(WPF AllowsTransparency=True)
|
||||||
|
property bool alwaysOnTop: false // 置顶(WPF Topmost)
|
||||||
|
property bool toolWindow: false // 工具窗口:任务栏不显示、随 Owner 关闭
|
||||||
|
|
||||||
|
title: windowTitle
|
||||||
|
modality: modal ? Qt.WindowModal : Qt.NonModal
|
||||||
|
flags: Qt.Window
|
||||||
|
| (frameless ? Qt.FramelessWindowHint : 0)
|
||||||
|
| (alwaysOnTop ? Qt.WindowStaysOnTopHint : 0)
|
||||||
|
| (toolWindow ? Qt.Tool : 0)
|
||||||
|
color: transparent ? "transparent" : "#FFFFFF"
|
||||||
|
}
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import FancyInput.Controls
|
||||||
|
|
||||||
|
// 悬浮窗内容(根元素 Rectangle —— Qt Creator 设计模式可可视化编辑)
|
||||||
|
// 使用场景:无边框透明窗口,只呈现内容本身,对应 WPF:
|
||||||
|
// · WindowStyle=None → 包装层 flags: Qt.FramelessWindowHint
|
||||||
|
// · AllowsTransparency=True → 包装层 color: "transparent"
|
||||||
|
// · Topmost= true → 包装层 Qt.WindowStaysOnTopHint
|
||||||
|
// 由调用方(Main.qml)用 Window 现包装,包装层负责窗口级属性。
|
||||||
|
Rectangle {
|
||||||
|
id: content
|
||||||
|
width: 280
|
||||||
|
height: 180
|
||||||
|
color: "transparent" // 内容自身透明,只有卡片可见
|
||||||
|
|
||||||
|
// 请求关闭(Window 包装层监听后调用 close())
|
||||||
|
signal closeRequested
|
||||||
|
|
||||||
|
// 无边框窗口没有标题栏,需自行实现拖拽移动。
|
||||||
|
// 用系统原生拖拽(startSystemMove,等同拖标题栏):
|
||||||
|
// 窗口系统接管整个移动过程(DWM 合成,移动的是窗口快照),
|
||||||
|
// 流畅无闪烁 —— 手动跟踪鼠标坐标逐帧改 x/y 在透明窗口上会
|
||||||
|
// 触发重绘同步,造成卡顿和残影(Windows 合成器下尤其明显)。
|
||||||
|
MouseArea {
|
||||||
|
id: dragArea
|
||||||
|
anchors.fill: parent
|
||||||
|
z: 0
|
||||||
|
cursorShape: Qt.SizeAllCursor
|
||||||
|
|
||||||
|
onPressed: {
|
||||||
|
var w = content.Window.window
|
||||||
|
if (w) w.startSystemMove()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 半透明圆角卡片(真正呈现的内容)
|
||||||
|
Rectangle {
|
||||||
|
id: card
|
||||||
|
anchors.centerIn: parent
|
||||||
|
width: 240
|
||||||
|
height: 140
|
||||||
|
radius: 16
|
||||||
|
color: "#CC1E1E24" // 半透明主题 surface 色(alpha=0xCC)
|
||||||
|
border.color: Theme.border
|
||||||
|
border.width: 1
|
||||||
|
z: 1
|
||||||
|
|
||||||
|
// 浅色描边让卡片在任意背景下都可见
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
radius: 16
|
||||||
|
color: "transparent"
|
||||||
|
border.color: "#33FFFFFF"
|
||||||
|
border.width: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: 16
|
||||||
|
spacing: 10
|
||||||
|
|
||||||
|
Label {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
text: qsTr("悬浮窗")
|
||||||
|
font.family: Theme.fontFamily
|
||||||
|
font.pixelSize: 16
|
||||||
|
font.bold: true
|
||||||
|
color: Theme.textPrimary
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
text: qsTr("无边框 · 透明 · 置顶\n拖拽本窗口移动")
|
||||||
|
font.family: Theme.fontFamily
|
||||||
|
font.pixelSize: 12
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
color: Theme.textSecondary
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
text: qsTr("关闭")
|
||||||
|
font.family: Theme.fontFamily
|
||||||
|
onClicked: content.closeRequested()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import FancyInput.Controls
|
||||||
|
|
||||||
|
// 设置窗口界面(根元素为 Rectangle —— Qt Creator 设计模式可可视化编辑)
|
||||||
|
// 需要弹窗时由调用方(Main.qml)现场用 Window 包装,本组件只负责内容。
|
||||||
|
Rectangle {
|
||||||
|
id: content
|
||||||
|
width: 480
|
||||||
|
height: 360
|
||||||
|
color: Theme.background
|
||||||
|
|
||||||
|
// 请求关闭(Window 包装层监听后调用 close())
|
||||||
|
signal closeRequested
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
spacing: 16
|
||||||
|
|
||||||
|
Label {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
text: qsTr("设置窗口(来自 FancyInput.Windows)")
|
||||||
|
font.family: Theme.fontFamily
|
||||||
|
font.pixelSize: 18
|
||||||
|
font.bold: true
|
||||||
|
color: Theme.textPrimary
|
||||||
|
}
|
||||||
|
|
||||||
|
// 复用 controls 模块的自定义控件,验证跨模块引用
|
||||||
|
Button {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
text: qsTr("关闭")
|
||||||
|
font.family: Theme.fontFamily
|
||||||
|
onClicked: content.closeRequested()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user