当前位置: 首页 > news >正文

QML 常用控件(二)

QML(Qt Modeling Language)作为Qt框架中用于构建用户界面的声明式语言,提供了丰富多样的控件来满足各种交互需求。本文将深入探讨QML中常用的基础控件,包括ProgressBar、BusyIndicator、ComboBox、Dial、Slider、SpinBox、Tumbler、TextField和TextArea。

进度条控件:ProgressBar

ProgressBar是QML中最常用的进度指示控件,用于向用户展示任务的完成情况。根据Qt官方文档,ProgressBar控件提供了一种直观的方式来显示操作的进度,无论是确定进度还是不确定进度的情况都能很好地支持。

核心属性解析​:

  • value:当前进度值,范围在fromto之间
  • from/to:进度范围的最小值和最大值(默认0.0-1.0)
  • orientation:进度条方向(水平或垂直)
  • indeterminate:是否启用不确定模式(用于未知进度时显示动画)

基础使用示例​:

import QtQuick 2.15
import QtQuick.Controls 2.15ProgressBar {id: progressBarwidth: 200value: 0.5  // 当前进度50%from: 0to: 1
}

动态进度更新是ProgressBar的常见应用场景,通常结合Timer或后台任务实现:

Timer {interval: 100running: truerepeat: trueonTriggered: {if(progressBar.value < 1) progressBar.value += 0.01elseprogressBar.value = 0}
}

样式定制是ProgressBar的高级用法,通过修改backgroundcontentItem可以完全自定义外观:

ProgressBar {id: customProgressBarvalue: 0.75background: Rectangle {implicitWidth: 200implicitHeight: 6color: "#e0e0e0"radius: 3}contentItem: Item {implicitWidth: 200implicitHeight: 6Rectangle {width: customProgressBar.visualPosition * parent.widthheight: parent.heightradius: 3color: "#21be2b"}}
}

在实际应用中,ProgressBar经常需要与其他控件联动。例如,与Slider结合实现进度调节:

Column {spacing: 20anchors.centerIn: parentProgressBar {width: 300value: slider.value}Slider {id: sliderwidth: 300from: 0to: 1value: 0.5}
}

对于不确定进度的场景(如网络请求),可以使用不确定模式:

ProgressBar {indeterminate: truewidth: 200
}

最佳实践建议​:

  1. 对于长时间操作,始终提供进度反馈
  2. 确定进度尽量提供百分比数值
  3. 不确定进度使用动画让用户知道系统仍在工作
  4. 根据应用主题定制进度条样式以保持UI一致性
  5. 移动设备上考虑增加触摸交互区域

ProgressBar的性能优化主要涉及大数据量更新时的节流处理,避免过于频繁的界面重绘。在QML中,可以使用Qt.binding或定时批量更新来优化性能。

忙碌指示器:BusyIndicator

BusyIndicator是QML中用于表示应用程序正在处理任务的视觉组件,当应用执行耗时操作时,它通过旋转动画提示用户等待,防止用户误以为程序无响应。与ProgressBar不同,BusyIndicator不显示具体进度,而是通过持续的动画效果表明后台正在工作。

核心属性​:

  • running:布尔值,控制动画是否激活(默认true)
  • visible:控制组件是否显示
  • padding:内边距,影响指示器与边界的距离

基本使用方法非常简单:

import QtQuick 2.15
import QtQuick.Controls 2.15BusyIndicator {running: trueanchors.centerIn: parent
}

全屏覆盖实现是BusyIndicator的常见应用场景,模拟类似Android中ProgressDialog的效果:

ApplicationWindow {id: mainWindowvisible: truewidth: 400height: 300Rectangle {id: overlayanchors.fill: parentcolor: Qt.rgba(0, 0, 0, 0.5)  // 半透明黑色背景visible: falseBusyIndicator {anchors.centerIn: parentrunning: parent.visible}MouseArea {anchors.fill: parentonClicked: {}  // 阻止点击穿透}}Button {text: "开始任务"onClicked: overlay.visible = true}
}

自定义样式可以通过替换contentItem实现。默认的BusyIndicator使用系统主题样式,但我们可以完全自定义:

BusyIndicator {id: busyIndicatoranchors.centerIn: parentcontentItem: Item {implicitWidth: 64implicitHeight: 64Item {id: containeranchors.fill: parentopacity: busyIndicator.running ? 1 : 0RotationAnimator {  //旋转的核心动画target: containerfrom: 0to: 360  //从0°到360°无限循环旋转duration: 1000loops: Animation.Infiniterunning: busyIndicator.visible && busyIndicator.running}Repeater {  //重复器id: repeatermodel: 8   //生成8个圆点(model: 8),每个圆点通过Rectangle实现Rectangle {x: container.width / 2 - width / 2y: container.height / 2 - height / 2width: 10height: 10radius: 5color: "#21be2b"transform: [Translate {y: -container.height * 0.4 //将圆点沿Y轴向上移动容器高度的40%(y: -container.height * 0.4),形成环形布局},Rotation {angle: index * 45 //每个圆点按索引(index)旋转45°(angle: index * 45),使8个圆点均匀分布在圆周上origin.x: 5origin.y: 5 //元素会围绕(5,5)这个点旋转}]}}}}}

应用场景​:

  1. 网络请求等待期间
  2. 文件读写操作时
  3. 复杂计算过程中
  4. 页面加载或初始化时
  5. 数据库查询执行时

性能注意事项​:

  1. 避免同时显示多个BusyIndicator
  2. 不需要时及时设置为running: false以节省资源
  3. 动画复杂度影响CPU使用率,移动设备上需特别注意
  4. 考虑低端设备的性能,提供简化动画选项

BusyIndicator与ProgressBar的选择取决于场景:当可以计算进度百分比时使用ProgressBar,当无法确定完成时间时使用BusyIndicator。两者也可以结合使用,如主进度使用ProgressBar,子任务使用BusyIndicator。

组合选择控件:ComboBox

ComboBox是QML中常用的下拉选择控件,它结合了按钮和弹出列表的特点,为用户提供了一种节省空间的方式来从预定义选项中进行选择。ComboBox在表单填写、设置选项等场景中广泛应用,能够有效提升用户交互体验。

基本属性​:

  • model:数据模型,可以是ListModel、数组或整数
  • currentIndex:当前选中项的索引
  • currentText:当前选中项的文本
  • editable:是否允许编辑(可输入非列表项)
  • displayText:控件上显示的文本(可自定义格式)

基础示例​:

import QtQuick 
import QtQuick.Controls ComboBox {x: 20y: 20// editable: truemodel: ListModel {id: modelListElement { text: "Banana" }ListElement { text: "Apple" }ListElement { text: "Coconut" }}}

动态模型更新是实际开发中的常见需求:

ComboBox {id: dynamicCombowidth: 200model: []Component.onCompleted: {// 模拟异步加载Qt.callLater(function() {dynamicCombo.model = ["动态加载1", "动态加载2", "动态加载3"]})}Button {anchors.left: parent.righttext: "添加选项"onClicked: {if(dynamicCombo.model instanceof Array) {var newModel = dynamicCombo.model.slice()newModel.push("新选项" + (newModel.length + 1))dynamicCombo.model = newModel}}}
}

分组显示可以提升复杂选项的可浏览性:

ComboBox {width: 250height: 30model: [{ display: "水果", isGroup: true },{ display: "苹果", isGroup: false },{ display: "香蕉", isGroup: false },{ display: "蔬菜", isGroup: true },{ display: "胡萝卜", isGroup: false },{ display: "西红柿", isGroup: false }]displayText: currentIndex >= 0 ? model[currentIndex].display : "请选择"currentIndex: -1delegate: ItemDelegate {width: parent.widthheight: modelData.isGroup ? 30 : implicitHeightenabled: !modelData.isGrouphighlighted: comboBox.highlightedIndex === index && !modelData.isGroupcontentItem: Text {text: modelData.displayfont.bold: modelData.isGroupcolor: modelData.isGroup ? "#999999" : (highlighted ? "#ffffff" : "#333333")}}
}

自定义样式允许开发者完全控制ComboBox的外观:

ComboBox {id: controlmodel: ["经典风格", "现代风格", "简约风格"]// 下拉箭头indicator: Canvas {x: control.width - width - control.rightPaddingy: control.topPadding + (control.availableHeight - height) / 2width: 12height: 8contextType: "2d"Connections {target: controlfunction onPressedChanged() { indicator.requestPaint() }}onPaint: {var ctx = getContext("2d")ctx.reset()ctx.moveTo(0, 0)ctx.lineTo(width, 0)ctx.lineTo(width / 2, height)ctx.closePath()ctx.fillStyle = control.pressed ? "#17a81a" : "#21be2b"ctx.fill()}}// 背景background: Rectangle {implicitWidth: 120implicitHeight: 40border.color: control.pressed ? "#17a81a" : "#21be2b"border.width: control.visualFocus ? 2 : 1radius: 2}// 委托项delegate: ItemDelegate {width: control.widthhighlighted: control.highlightedIndex === indexcontentItem: Text {text: modelDatacolor: highlighted ? "#ffffff" : "#333333"font: control.fontelide: Text.ElideRightverticalAlignment: Text.AlignVCenter}background: Rectangle {color: highlighted ? "#21be2b" : "transparent"}}// 下拉弹出层popup: Popup {y: control.height - 1width: control.widthimplicitHeight: contentItem.implicitHeightpadding: 1contentItem: ListView {clip: trueimplicitHeight: contentHeightmodel: control.popup.visible ? control.delegateModel : nullcurrentIndex: control.highlightedIndexScrollIndicator.vertical: ScrollIndicator { }}background: Rectangle {border.color: "#21be2b"radius: 2}}
}

旋钮控件:Dial

Dial是QML中模拟物理旋钮的圆形交互控件,允许用户通过旋转手势调整数值。这种控件在音频处理、参数调整、仪表盘等场景中非常有用,能够提供直观的参数调节体验。

核心属性​:

  • value:当前旋钮的值(范围由from和to决定)
  • from/to:最小值和最大值(默认0.0-1.0)
  • stepSize:步进值(调整时的最小单位)
  • snapMode:对齐模式(是否自动对齐步进值)
  • wrap:是否允许循环旋转
  • inputMode:输入模式(圆形或水平/垂直)
  • angle:当前旋钮的旋转角度(只读)

基础示例​:

import QtQuick 2.15
import QtQuick.Controls 2.15Dial {id: dialwidth: 200height: 200from: 0to: 100value: 50stepSize: 1snapMode: Dial.SnapOnReleaseonValueChanged: console.log("当前值:", value.toFixed(1))Text {anchors.top: dial.bottomtext: "当前值: " + dial.value.toFixed(1)}
}

样式定制是Dial控件最具特色的方面,可以通过background和handle属性完全自定义外观:

Dial {id: controlwidth: 200height: 200anchors.centerIn: parentfrom: 0to: 100stepSize: 5snapMode: Dial.SnapAlwaysonValueChanged: {console.log("value: " + value)}background: Rectangle {x: control.width / 2 - width / 2y: control.height / 2 - height / 2implicitWidth: 140implicitHeight: 140width: Math.max(64, Math.min(control.width, control.height))height: widthcolor: "transparent"radius: width / 2border.color: control.pressed ? "#17a81a" : "#21be2b"opacity: control.enabled ? 1 : 0.3Label {anchors.centerIn: parenthorizontalAlignment: Text.AlignHCenterverticalAlignment: Text.AlignVCenterfont.pixelSize: 50font.bold: truecolor: "#21be2b"text: control.value}}handle: Rectangle {  //手柄  即旋钮的那个小圆点id: handleItemx: control.background.x + control.background.width / 2 - width / 2y: control.background.y + control.background.height / 2 - height / 2width: 16height: 16color: control.pressed ? "#17a81a" : "#21be2b"radius: 8antialiasing: trueopacity: control.enabled ? 1 : 0.3transform: [Translate {y: -Math.min(control.background.width, control.background.height) * 0.4 + handleItem.height / 2},Rotation {angle: control.angleorigin.x: handleItem.width / 2origin.y: handleItem.height / 2}]}}

高级定制包括添加刻度标记和值显示,这需要使用Canvas绘制:

Dial {id: dialwidth: 200height: 200Canvas {anchors.fill: parentonPaint: {var ctx = getContext("2d")ctx.reset()// 绘制刻度ctx.strokeStyle = "#808080"ctx.lineWidth = 1var centerX = width / 2var centerY = height / 2var radius = Math.min(width, height) * 0.4// 主刻度for (var i = 0; i <= 10; i++) {var angle = (i * 30) * (Math.PI / 180)var x1 = centerX + radius * Math.sin(angle)var y1 = centerY - radius * Math.cos(angle)var x2 = centerX + (radius + 10) * Math.sin(angle)var y2 = centerY - (radius + 10) * Math.cos(angle)ctx.beginPath()ctx.moveTo(x1, y1)ctx.lineTo(x2, y2)ctx.stroke()// 刻度标签if (i % 2 == 0) {var labelX = centerX + (radius + 20) * Math.sin(angle)var labelY = centerY - (radius + 20) * Math.cos(angle)ctx.font = "12px Arial"ctx.textAlign = "center"ctx.textBaseline = "middle"ctx.fillText(i, labelX, labelY)}}}}Text {anchors.centerIn: parenttext: dial.value.toFixed(1)font.pixelSize: 20}
}

应用场景​:

  1. 音频均衡器界面
  2. 仪表盘控制面板
  3. 图像处理参数调整
  4. 工业控制界面
  5. 游戏控制器设置

Dial控件的最佳实践包括提供足够的视觉反馈、确保触摸目标足够大、考虑添加辅助显示(如当前值)以及根据应用主题定制外观。通过合理的设计,Dial可以成为用户界面中最直观的参数调节方式之一。

滑动输入控件:Slider

Slider是QML中用于让用户通过拖动滑块选择数值的标准控件,适用于音量控制、亮度调节、进度指示等需要从连续或离散范围中选择值的场景。Qt Quick的Slider控件不仅功能丰富,还具有高度可定制性,能够满足各种应用场景的需求。

核心属性​:

  • value:当前滑块的值
  • from/to:滑块的最小值和最大值(默认0-1)
  • stepSize:滑块的步进大小
  • orientation:滑块方向(水平或垂直)
  • snapMode:对齐模式(NoSnap/SnapOnRelease/SnapAlways)
  • live:拖动时是否实时更新value
  • pressed:滑块是否正被交互
  • visualPosition:滑块的视觉位置(0.0-1.0)

基础示例​:

import QtQuick 2.15
import QtQuick.Controls 2.15Slider {width: 200from: 0to: 100value: 50stepSize: 1onMoved: console.log("滑块值:", value.toFixed(1))
}

垂直滑块通过设置orientation属性实现:

Slider {orientation: Qt.Verticalheight: 200from: 0to: 100value: 50
}

样式定制是Slider最强大的特性之一,可以通过handle和background属性完全自定义外观:

Slider {id: sliderx: 100y: 50width: 300height: 20from: 0to: 100stepSize: 1onValueChanged: {console.log("value: " + value)// volumeLabel.text = value}background: Rectangle { //外层Rectangle定义了滑块的背景轨道x: slider.leftPaddingy: slider.topPadding + slider.availableHeight / 2 - height /2implicitWidth: 200implicitHeight: 12width: slider.availableWidthheight: implicitHeightradius: implicitHeight / 2color: "#bdbebf"Rectangle { //内层Rectangle作为滑块的填充指示器width: slider.visualPosition * parent.width height: parent.heightcolor: "#21be2b"radius: height / 2}}handle: Rectangle {x: slider.leftPadding + slider.visualPosition * (slider.availableWidth - width)y: slider.topPadding + slider.availableHeight / 2 - height /2implicitWidth: 24implicitHeight: 24radius: implicitHeight / 2color: slider.pressed ? "#333333" : "#f0f0f0"border.color: "#bdbebf"}}Label {id: volumeLabelanchors.left: slider.rightanchors.leftMargin: 10anchors.verticalCenter: slider.verticalCenterfont.pixelSize: 32color: "#21be2b"text: slider.value}

添加刻度标记可以提升Slider的专业感和可用性:

Slider {id: sliderwidth: 300from: 0to: 100stepSize: 10snapMode: Slider.SnapAlwaysItem {width: parent.widthheight: 30Repeater {model: 11  // 0到100,每10一个刻度Rectangle {x: index * (slider.availableWidth / 10) - width/2y: 10width: 2height: 10color: "#808080"}Text {x: index * (slider.availableWidth / 10) - width/2y: 22text: (index * 10).toString()color: "#808080"font.pixelSize: 12}}}
}

应用场景​:

  1. 音量控制面板
  2. 图像编辑参数调整
  3. 范围选择过滤器
  4. 播放进度控制
  5. 设置界面参数调节

Slider控件的最佳实践包括提供足够的视觉反馈、确保触摸目标足够大、考虑添加辅助显示(如当前值)以及根据应用主题定制外观。通过合理的设计,Slider可以成为用户界面中最直观的参数调节方式之一。

数值输入控件:SpinBox与Tumbler

SpinBox和Tumbler是QML中两种常用的数值输入控件,它们以不同的交互方式允许用户输入数值。SpinBox提供传统的增减按钮输入方式,而Tumbler则采用滚轮式选择界面,两者各有适用场景和优势。

SpinBox

SpinBox是用于数字输入的经典控件,支持整数和浮点数输入,适用于需要精确数值调整的场景。

核心属性​:

  • value:当前值
  • from/to:取值范围
  • stepSize:步进大小
  • editable:是否允许直接编辑
  • validator:输入验证器
  • up/down:增减按钮相关属性
  • textFromValue:自定义值显示格式的函数
  • valueFromText:从文本解析值的函数

基础示例​:

import QtQuick 2.15
import QtQuick.Controls 2.15SpinBox {width: 100height: 30x: 50y: 50from: -20to: 20stepSize: 5onValueChanged: {console.log("value: " + value)}}

Tumbler

Tumbler是滚轮式选择器控件,提供直观的滚动选择体验,常用于日期、时间选择等场景。

核心属性​:

  • model:数据模型(数字、列表或自定义模型)
  • currentIndex:当前选中项的索引
  • visibleItemCount:可见项数量(奇数)
  • wrap:是否循环滚动
  • delegate:项的委托组件
  • path:自定义项的路径

基础示例​:

import QtQuick 2.15
import QtQuick.Controls 2.15Tumbler {model: 10  // 显示0-9的数字width: 100height: 150
}

多列Tumbler组合​(如时间选择器):

Row {spacing: 10Tumbler {id: hoursTumblermodel: 24width: 60currentIndex: 12}Tumbler {id: minutesTumblermodel: 60width: 60}Tumbler {id: amPmTumblermodel: ["AM", "PM"]width: 80}
}

应用场景对比​:

特性SpinBoxTumbler
交互方式按钮增减/直接输入滚轮选择
精度支持小数通常整数
空间占用紧凑需要更多空间
适用场景精确数值输入离散值/范围选择
移动友好性一般优秀
自定义难度中等较高

选择建议​:

  1. 需要精确数值输入时选择SpinBox
  2. 需要快速范围选择时选择Tumbler
  3. 移动设备优先考虑Tumbler
  4. 紧凑界面考虑SpinBox
  5. 需要特殊视觉效果选择Tumbler

SpinBox和Tumbler都是强大的数值输入控件,选择取决于具体应用场景、目标平台和用户交互需求。通过合理的样式定制,两者都能完美融入应用的整体设计中。

文本编辑控件:TextField与TextArea

TextField和TextArea是QML中用于文本输入的核心控件,分别针对单行和多行文本输入场景设计。它们在表单填写、搜索框、文本编辑等交互中扮演着重要角色,是构建用户界面的基础组件。

TextField

TextField是单行文本输入控件,适用于用户名、密码、搜索词等简短文本输入场景。

核心属性​:

  • text:输入的文本内容
  • placeholderText:未输入时显示的提示文字
  • echoMode:文本显示模式(Normal/Password/NoEcho)
  • validator:输入验证器
  • inputMask:输入格式掩码
  • maximumLength:最大输入长度
  • readOnly:是否只读
  • selectByMouse:是否允许鼠标选择文本

基础示例​:

import QtQuick 2.15
import QtQuick.Controls 2.15TextField {width: 200placeholderText: "请输入用户名..."onAccepted: console.log("输入完成:", text)
}

输入验证是TextField的重要功能,可以通过多种方式实现:

  • 整数验证​:
TextField {validator: IntValidator {bottom: 0top: 150}placeholderText: "请输入年龄(0-150)"
}
  • 正则表达式验证​:
TextField {validator: RegularExpressionValidator {regularExpression: /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/}placeholderText: "请输入邮箱"
}
  • 输入掩码​:
TextField {inputMask: "9999-99-99"placeholderText: "请输入日期(YYYY-MM-DD)"
}

密码输入框通过echoMode实现:

TextField {echoMode: TextField.PasswordpasswordCharacter: "•"placeholderText: "请输入密码"
}

自定义样式​:

 TextField {width: 300height: 50anchors.centerIn: parentcolor: "black"font.pixelSize: 32verticalAlignment: Text.AlignVCenterhorizontalAlignment: Text.AlignHCenterleftPadding: 15rightPadding: 15placeholderText: "Enter" //预编辑文本echoMode: TextInput.PasswordonTextEdited: {console.log("#1 text: " + text)if(text === "123abc"){label.text = "Your password is right."}}onEditingFinished: {console.log("#2 text: " + text)}background: Rectangle {implicitWidth: parent.widthimplicitHeight: parent.heightradius: implicitHeight / 2color: "lightgray"border.width: 1border.color: "limegreen"}}

TextArea

TextArea是多行文本输入控件,适用于长文本输入、代码编辑等场景。

核心属性​:

  • text:文本内容
  • placeholderText:提示文字
  • wrapMode:换行模式(NoWrap/Wrap/WordWrap)
  • textFormat:文本格式(PlainText/RichText/AutoText)
  • readOnly:是否只读
  • selectByMouse:是否允许鼠标选择

基础示例​:

import QtQuick
import QtQuick.ControlsWindow {width: 640height: 480visible: truetitle: qsTr("Hello World")ScrollView {width: 300height: 200anchors.centerIn: parentTextArea {width: parent.width - 10height: parent.height - 10anchors.centerIn: parentcolor: "blue"font.pixelSize: 32leftPadding: 10rightPadding: 10wrapMode: TextEdit.WrapselectionColor: "darkgreen"selectedTextColor: "red"placeholderText: "请输入你的消息"onTextChanged: {console.log("text: " + text)}background: Rectangle {implicitWidth: parent.widthimplicitHeight: parent.heightradius: 4color: "white"border.width: 1border.color: "limegreen"}}}}

应用场景对比​:

特性TextFieldTextArea
行数单行多行
滚动自动水平滚动需ScrollView支持
用途简短输入长文本编辑
性能高效大数据量需优化
验证支持多种验证基本验证
样式较简单复杂样式支持

性能优化技巧​:

  1. 大数据集使用动态加载
  2. 考虑分页或虚拟滚动
  3. 避免频繁的文本分析操作
  4. 复杂语法高亮使用专业组件

TextField和TextArea是QML文本输入的基础,通过合理的使用和样式定制,可以构建出既美观又功能强大的文本输入界面,满足从简单表单到复杂文本编辑的各种需求。

http://www.lryc.cn/news/587800.html

相关文章:

  • vue中配置Eslint的步骤
  • Why C# and .NET are still relevant in 2025
  • lightgbm算法学习
  • Python----NLP自然语言处理(中文分词器--jieba分词器)
  • 《大数据技术原理与应用》实验报告一 熟悉常用的Linux操作和Hadoop操作
  • .NET控制台应用程序中防止程序立即退出
  • 2025年大数据、建模与智能计算国际会议(ICBDMIC 2025)
  • spring-ai-alibaba 接入Tushare查询股票行情
  • 【C++进阶】---- 多态
  • SpringBoot3整合“Spring Security+JWT”快速实现demo示例与Apifox测试
  • 鸿蒙开发NDK之---- 如何将ArkTs的类型转化成C++对应的类型(基础类型,包含部分代码解释)
  • 系统化构建产品开发体系
  • androidstudio 高低版本兼容
  • 机构参与度及其Python数据获取示例
  • 迁移学习:知识复用的智能迁移引擎 | 从理论到实践的跨域赋能范式
  • 【Canvas与五星】六种五星画法
  • MIPI DSI (一) MIPI DSI 联盟概述
  • 【leetcode】231. 2的幂
  • ASP.NET Core中数据绑定原理实现详解
  • Android模块化架构:基于依赖注入和服务定位器的解耦方案
  • iOS如何查看电池容量?理解系统限制与开发者级能耗调试方法
  • H.264编解码(NAL)
  • 前端docx库实现将html页面导出word
  • 蜻蜓I即时通讯水银版系统直播功能模块二次开发文档-详细的直播功能模块文档范例-卓伊凡|麻子
  • 文档处理控件Aspose.Words教程:从 C# 中的 Word 文档中提取页面
  • 【飞牛云fnOS】告别数据孤岛:飞牛云fnOS私人资料管家
  • Python爬虫实战:研究PyMongo库相关技术
  • crawl4ai--bitcointalk爬虫实战项目
  • 嵌入式硬件篇---ne555定时器
  • 嵌入式硬件篇---晶体管的分类