开发环境

Qt版本: 6.5.3

构建: cmake + minGW64-bit

简介

这是一个纯QML程序,功能是一个消息列表的功能,可以进行插入,删除,清空等操作

预览图

![2024-08-21 14-28-39_converted](images/2024-08-21 14-28-39_converted.gif)

如何使用

直接导入messageQueueView文件夹即可

代码

这里的代码只包括组件的代码,不包括整个项目的代码。

结构如下:

- messageQueueView
- resource
- Background.qml
- MessageView.qml
- ScroolBar.qml
- MessageQueueView.qml

Background.qml: 消息队列的背景

MessageView.qml: 显示插入的消息

ScroolBar.qml: 滑块

MessageQueueView.qml: 消息队列组件

main.qml

展示消息列表组件功能

import QtQuick
import QtQuick.Controls
import QtQuick.Controls.Material
import "./messageQueueView" Window {
width: 640
height: 480
visible: true
title: qsTr("Hello World") Item {
id: root
width: parent.width
height: parent.height
Pane {
width: parent.width
height: parent.height
Column {
width: 80
height: 100
spacing: 10
Material.theme: Material.System
Row {
Text {
text: "插入消息: "
}
TextField {
Keys.onReturnPressed: {
messageQueueView.insert(text,{
title: "这是一个消息的标题",
message: "这是第 " + messageQueueView.count +" 条消息"
})
}
}
}
Row {
Text {
text: "移除消息: "
}
TextField {
Keys.onReturnPressed: {
messageQueueView.remove(text,1)
}
}
}
Row {
Button {
text: "清空消息"
onClicked: {
messageQueueView.clear()
}
Keys.onReturnPressed: {
messageQueueView.model.clear()
}
}
Button {
text: "打开"
onClicked: {
messageQueueView.show()
}
Keys.onReturnPressed: {
messageQueueView.show()
}
}
Button {
text: "关闭"
onClicked: {
messageQueueView.hide()
}
Keys.onReturnPressed: {
messageQueueView.hide()
}
}
} }
} MessageQueueView {
id: messageQueueView
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.bottomMargin: 20
Component.onCompleted: { }
}
}
Timer {
property var data: [
{
title: "这是一个消息的标题",
message: "这是一个消息,这是一个消息,这是一个消息,这是一个消息,这是一个消息,这是一个消息,这是一个消息"
},
{
title: "这是一个消息的标题",
message: "这不是一个消息,这不是一个消息,这不是一个消息,这不是一个消息,这不是一个消息,这不是一个消息"
},
{
title: "这是一个消息的标题",
message: "好吧,这是一一一条消息"
},
]
property int current: 0
interval: 400
onTriggered: {
if(current < data.length) {
messageQueueView.insert(0,data[current]);
current ++;
start();
}
}
Component.onCompleted: {
start()
}
}
}

MessageView.qml

消息列表组件

import QtQuick 2.15

/*
消息视图
*/
ListView {
id: listview width: content.width
height: content.height
spacing: 10
anchors.horizontalCenter: parent.horizontalCenter
verticalLayoutDirection: ListView.BottomToTop
clip: true
model: root.model delegate: messageItemDelegate
// add 添加 过渡动画 因add导致被影响的项
add: Transition {
id: addTrans
onRunningChanged: {
// console.log("addTran: " + ViewTransition.item)
}
ScriptAction { // 动态添加一个定时器 延时设置透明度
script: {
addDelayHide(addTrans.ViewTransition.item)
}
}
ParallelAnimation {
NumberAnimation {
property: "opacity"
from: 0
to: 1
duration: 300
easing.type: Easing.InOutQuad
}
PathAnimation {
duration: 400
easing.type: Easing.InOutQuad
path: Path {
startX: addTrans.ViewTransition.destination.x + 80
startY: addTrans.ViewTransition.destination.y
PathCurve {
x: (listview.width - addTrans.ViewTransition.item.width) / 2
y: addTrans.ViewTransition.destination.y
}
}
}
} }
// add 添加 过渡动画
addDisplaced: Transition {
id: dispTran
onRunningChanged: {
if(running) {
// console.log("addDispTran: " + ViewTransition.targetItems)
}
}
// 如果数据插入太快会导致动画被中断 然后动画控制的属性值无法回到正确的值,在这里手动回到正确的值
ScriptAction {
script: {
let item = dispTran.ViewTransition.item
if(root.state === "show") {
item.opacity = 1
}
if(root.state === "hide" && item.state === "NONEW") {
item.opacity = 0
console.log(item.children)
}
}
}
PropertyAction { property: "x"; value: (listview.width - dispTran.ViewTransition.item.width) / 2;} NumberAnimation {
property: "y"
duration: 300
easing.type: Easing.InOutQuad
} } // remove 移除 过渡动画
remove: Transition {
id: removeTran
onRunningChanged: {
// console.log("removeTran: " + ViewTransition.targetItems)
}
ParallelAnimation {
NumberAnimation {
property: "x"
to: listview.width
duration: 400
easing.type: Easing.OutQuart
}
NumberAnimation {
property: "opacity"
from: 1
to: 0
duration: 400
easing.type: Easing.InOutQuart
}
} }
// remove 移除 过渡动画 因romove导致被影响的项
removeDisplaced: Transition {
id: removeDispTran
onRunningChanged: {
// console.log("removeDispTran: " + ViewTransition.targetItems)
}
ParallelAnimation {
NumberAnimation {
property: "y"
duration: 500
easing.type: Easing.InOutQuart
}
}
} // populate 委托项加载时触发
populate: Transition {
id: popuTran
NumberAnimation {
property: "opacity"
duration: 300
from: 0
to: 1
easing.type: Easing.OutCubic
}
}
// 视图滑块
ScroolBar.vertical: ScroolBar { }
/*
消息视图显示时 使所有加载项显示
消息视图隐藏时 使所有加载项隐藏
*/
Connections {
target: root
function onStateChanged() {
for(let i = 0; i < contentItem.children.length;i++) {
let item = contentItem.children[i]
if(root.state === "show") {
item.opacity = 1
} else if(root.state === "hide"){
item.opacity = 0
}
}
}
} /*
添加延时定时器
如果视图隐藏时,只显示新添加的消息
*/
function addDelayHide(item) {
if(root.state === "show") return // let item = contentItem.children[contentItem.children.length-1]
let timer = Qt.createQmlObject("
import QtQml
Timer {}
",item)
let callBack = () => {
if(root.state === "show") return
timer.parent.opacity = 0
timer.parent.state = "NONEW"
console.log("timer: " + timer.parent)
} timer.interval = 3000
timer.triggered.connect(callBack)
timer.start()
} }

Background.qml

背景

// Background.qml
import QtQuick 2.15
/*
背景
*/
Loader {
id: backgroundLoader
anchors.fill: parent
sourceComponent: root.background
}

ScroolBar.qml

滑块

// ScrollBar.qml
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Controls.impl 2.12
import QtQuick.Templates 2.12 as T /*
滑动条
*/
T.ScrollBar {
id: control property color handleNormalColor: "#7FFFFFFF" //按钮颜色
property color handleHoverColor: Qt.lighter(handleNormalColor,1.1)
property color handlePressColor: Qt.darker(handleNormalColor,1.1) property real handleWidth: 10
property real handleHeight: 10
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
implicitContentWidth + leftPadding + rightPadding)
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
implicitContentHeight + topPadding + bottomPadding) padding: 1 //背景整体size和handle的间隔
visible: control.policy !== T.ScrollBar.AlwaysOff contentItem: Rectangle {
implicitWidth: control.interactive ? handleWidth : 2
implicitHeight: control.interactive ? handleHeight : 2 radius: width / 2
color: if(control.pressed) return handlePressColor
else if(control.hovered) return handleHoverColor
else return handleNormalColor
// 超出显示范围显示滚动条
opacity:(control.policy === T.ScrollBar.AlwaysOn || control.size < 1.0)?1.0:0.0 }
}

MessageQueueView.qml

使用此组件即可

// MessageQueueView.qml
import QtQuick
import QtQuick.Controls
import Qt5Compat.GraphicalEffects
import "./resource" Item {
id: root
property real margin: 20 property Component messageItemDelegate: messageDelegate
property Component background: backgourndCmp
property ListModel model: ListModel {} property alias itemsSpacing: messageView.spacing
property alias count: messageView.count signal added()
signal removed() width: 260
height: 400 state: "show"
states: [
State {
name: "hide"
PropertyChanges {
target: content
opacity: 0
x: root.width
}
PropertyChanges {
target: showIcon
parent: root
anchors.right: content.left
anchors.verticalCenter: content.verticalCenter
}
PropertyChanges {
target: messageView
interactive: false
contentY: 0
}
},
State {
name: "show"
PropertyChanges {
target: content
opacity: 1
x: 0
}
PropertyChanges {
target: showIcon
parent: root
anchors.right: content.left
anchors.verticalCenter: content.verticalCenter
}
PropertyChanges {
target: messageView
interactive: true
}
}
]
transitions: [
Transition {
from: "hide"
to: "show"
SequentialAnimation {
ScriptAction {
script: {
messageView.parent = content
console.log("AA")
}
}
ParallelAnimation {
NumberAnimation {
target: content
property: "x"
duration: 400
easing.type: Easing.OutCubic
}
NumberAnimation {
target: content
property: "opacity"
duration: 400
easing.type: Easing.InOutQuad
}
}
} },
Transition {
from: "show"
to: "hide"
SequentialAnimation {
ParallelAnimation {
NumberAnimation {
target: content
property: "x"
duration: 400
easing.type: Easing.OutCubic
}
NumberAnimation {
target: content
property: "opacity"
duration: 400
easing.type: Easing.InOutQuad
}
}
ScriptAction {
script: {
messageView.parent = root
console.log("AA")
}
}
} }
] // 主体内容
Item {
id: content
z: 0
width: parent.width
height: parent.height
// 背景加载
Background {
id: backgroundLoader
}
// 消息视图
MessageView {
id: messageView
}
} // 打开关闭按钮
ColorImage {
id: showIcon
z: 4
width: 20
height: width
rotation: 90
source: "qrc:/images/downUp.svg"
color: "#4F00FF00"
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: {
if(root.state === "show") {
root.hide()
} else {
root.show()
}
}
}
} Component {
id: backgourndCmp
Rectangle {
id: background
anchors.fill: parent
color: "#2F000000"
}
} // 单个消息委托
Component {
id: messageDelegate
Rectangle {
id: msgItem
x: (messageView.width - width) / 2
width: messageView.width - root.margin*2
height: 80
radius: 8
opacity: 1
// visible: opacity
color: "#2F000000"
clip: true Behavior on opacity {
NumberAnimation {
property: "opacity"
duration: 400
easing.type: Easing.InOutQuad
}
} Row {
width: parent.width - 20
height: parent.height - 20
spacing: 5
anchors.centerIn: parent
Image { // 消息图标
id: iconImg
width: 35
height: width
anchors.verticalCenter: parent.verticalCenter
source: iconSource
}
Column { // 消息信息
id: infoText
width: parent.width - iconImg.width - parent.spacing*2 - toolBar.width
height: parent.height
spacing: 5
Text {
property real maxHeight: parent.height * 0.3
width: parent.width
height: maxHeight
wrapMode: Text.Wrap
elide: Text.ElideRight
font.pointSize: 12
font.bold: true
text: title
color: "#FFFFFF"
}
Text {
property real maxHeight: parent.height * 0.7 - parent.spacing
width: parent.width
height: maxHeight
wrapMode: Text.Wrap
elide: Text.ElideRight
font.pointSize: 9
text: message
color: "#FFFFFF"
}
} Column { // 工具栏
id: toolBar
width: 15
MouseArea {
width: parent.width
height: width
cursorShape: Qt.PointingHandCursor
Rectangle {
width: parent.width
height: 1
anchors.centerIn: parent
rotation: 45
}
Rectangle {
width: parent.width
height: 1
anchors.centerIn: parent
rotation: -45
}
onClicked: {
remove(index)
}
}
}
}
} } function show() {
root.state = "show"
} function hide() {
root.state = "hide"
} function insert(index,info) {
let title = info.title || "标题"
let message = info.message || "信息"
let iconSource = info.iconSource || "qrc:/images/message.svg"
model.insert(index,{
title: title,
message: message,
iconSource: iconSource
})
root.added()
} function remove(index,count = 1) {
model.remove(index, count)
} function clear() {
model.clear()
}
}

Qt Quick 实现一个右下角弹出消息的组件的更多相关文章

  1. C#右下角弹出消息框

    打开QQ的时候,QQ新闻弹出窗体在屏幕的右下角就会慢慢升起一个小窗口,占用的地方不大,可以起到提示的作用.下面就让我们来看看,怎样用系统API来轻松实现这个功能.API原型函数:bool Animat ...

  2. winform C#屏幕右下角弹出消息框并自动消失

    ①弹出信息框后慢慢下降消失 在主窗体中新增按钮重命名为btnShowAndDisappearMessages,在click事件中写如下代码: private void btnShowAndDisapp ...

  3. 提问(prompt 消息对话框)用于询问一些需要与用户交互的信息。弹出消息对话框(包含一个确定按钮、取消按钮与一个文本输入框)

    提问(prompt 消息对话框) prompt弹出消息对话框,通常用于询问一些需要与用户交互的信息.弹出消息对话框(包含一个确定按钮.取消按钮与一个文本输入框). 语法: prompt(str1, s ...

  4. jquery easyui 弹出消息框 (转载) jQuery EasyUI API 中文文档 - 消息框(Messager) http://www.cnblogs.com/hantianwei/archive/2012/03/19/2407113.html

    <html> <head> <!-- 导入easyui插件的js和css样式; --> <link rel="stylesheet" ty ...

  5. jquery easyui 弹出消息框

    <html> <head> <!-- 导入easyui插件的js和css样式; --> <link rel="stylesheet" ty ...

  6. PHP自定义弹出消息类,用于弹出提示信息并返回

    一个用PHP自写的弹出消息类,用于在程序出错时弹出提示,,弹出警告框,或在程序运行到某阶段的快捷提示,需用时只需传入参数即可,函数并不复杂,但觉得挺实用.具体代码: function Alert($a ...

  7. bat脚本弹出消息示例(msg命令详细解释)

    弹出消息的bat,其实就是通过批处理调用msg命令,msg是系统自在的一个可以发送信息的命令. 示例: @echo off rem 测试MSG msg * "ok" rem 测试M ...

  8. 弹出消息对话框ScriptManager

    //直接调用WebMessageBox方法 #region 弹出消息对话框 /// <summary> /// 弹出消息对话框 /// </summary> /// <p ...

  9. 右下角弹出"Windows-延缓写入失败"或者"xxx-损坏文件 请运行Chkdsk工具"

    知识点分析: 任务栏右下角弹出“Windows-延缓写入失败”或者“xxx-损坏文件 请运行Chkdsk工具”. 操作步骤: 方法一:Chkdsk工具 在开始---运行中输入cmd,然后输入chkds ...

  10. C#利用API制作类似QQ一样的右下角弹出窗体

    C#利用API制作类似QQ一样的右下角弹出窗体 (2009-03-21 15:02:49) 转载▼ 标签: 杂谈 分类: .NET using System;using System.Collecti ...

随机推荐

  1. 【一步步开发AI运动小程序】十四、主包超出2M大小限制,如何将插件分包发布?

    随着人工智能技术的不断发展,阿里体育等IT大厂,推出的"乐动力"."天天跳绳"AI运动APP,让云上运动会.线上运动会.健身打卡.AI体育指导等概念空前火热.那 ...

  2. 初步学习Nuxt3

    Nuxt3 用于制作ssr 网页 支持vue3 所有的语法,并且支持了TypeScript, vite+vue3+composition api + ts.SPA单页面应用不能进行SEO优化,SSR应 ...

  3. Solr 的核心就是搜索

    原文  http://www.aptusource.org/2014/06/searching-is-what-its-all-about/ Solr 的主要功能就是强大的查询处理.在本文中,你将会看 ...

  4. wait、notify、notifyAll

    介绍 wait 方法前提需要拥有锁.使用wait方法后,释放锁进行等待队列. notify 方法从等待队列移除一个元素. notifyAll 将等待队列中元素全部进行移出. 注意:notify.not ...

  5. 原生JS点名器,随机数

    因为工作内容的需要自己琢磨了一个随机数的点名器,很早就写出了一版,今天无意间又看到了之前写的代码,还是有很多bug的,今天做了完善在这里分享给大家 <script type="text ...

  6. Swagger 调试,我不想再复制粘贴token啦~

    作为后端开发,进行Web Api 调试,除了使用 Postman, Apifox 等 Web Api 调试工具之外,我想使用Swagger进行调试应该是更方便,更常用的方式了吧. 那么在需要 toke ...

  7. 小程序 构建npm

    1. 在项目文件夹下 打开cmd 窗口,输入: npm init 一直回车即可 2. 安装模板 npm i @vant/weapp -S --production 3. 在微信开发者工具,左上角工具中 ...

  8. 对DenseTensor进行Transpose

    ML.NET 是微软推出的为. NET 平台设计的深度学习库,通过这个东西(ModelBuilder)可以自己构建模型,并用于后来的推理与数据处理.虽然设计是很好的,但是由于现在的 AI 发展基本上都 ...

  9. 【Linux】CentOS7 远程联机

    # CentOS7 远程联机 哔哩哔哩 萌狼蓝天 博客:https://mllt.cc 微信公众号:萌狼蓝天 检查与安装配置OpenSSH [CentOS7]检查系统是否安装OpenSSH yum - ...

  10. mac上遇到的错误sed command a expects followed by text

    上简单的替换操作 sed -i 's/apple/mac/g' full-path-file 执行后报错,"sed: 1: command a expects \ followed by t ...