尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
Qt 的原理及使用(7)——Q组件:从 QWidget 到自定义控件的完整实践
1. 从 QWidget 说起为什么每个 Qt 控件都绕不开它如果你刚开始写 Qt 桌面程序大概率会遇到一个疑问QPushButton、QLabel、QLineEdit 这些控件到底是怎么组织起来的它们之间有没有共同的“祖先”答案是有的而且这个祖先就是 QWidget。理解 QWidget是理解整个 Qt Q组件体系的第一步也是从“拖控件”进阶到“写自定义控件”的必经之路。QWidget 是 Qt 中所有用户界面对象的基类。它本身可以是一个窗口也可以是一个嵌入到其他窗口里的子控件。换句话说你在界面上看到的每一个按钮、标签、输入框甚至整个主窗口本质上都是一个 QWidget 或者 QWidget 的子类。它负责的事情包括绘制自己、响应鼠标和键盘事件、管理几何位置、处理焦点、承载布局等。我习惯把 QWidget 理解成一块“空白画布”。它默认什么都不画但提供了完整的交互框架。你继承它之后可以决定这块画布长什么样、怎么响应点击、怎么和外界通信。Qt 内置的那些控件其实就是官方在这块画布上画好了各种图案并封装了常用行为。从继承关系上看大致是这样的QObject └── QPaintDevice └── QWidget ├── QLabel ├── QPushButton ├── QLineEdit ├── QFrame │ └── QAbstractScrollArea └── ...QObject 提供了信号槽机制和对象树管理QPaintDevice 提供了绘制能力QWidget 把这两者结合起来再加上事件系统就成了所有可视控件的根基。这个结构决定了 Qt 控件的两个核心特征一是可以通过信号槽互相通信二是可以通过父子关系自动管理内存和生命周期。对于桌面端 GUI 开发来说掌握 QWidget 的意义在于当内置控件不能满足需求时你可以自己继承 QWidget重写绘制和事件处理做出完全自定义的组件。比如一个圆形的状态指示灯、一个带刻度的滑块、一个可以拖拽排序的列表项这些都可以通过子类化 QWidget 实现。这一篇会从 QWidget 的常用属性讲起然后梳理内置组件的使用方式最后给出一个完整的自定义控件示例并说明如何编译运行验证。过程中会涉及窗口透明度、光标、字体、提示、焦点策略这些实际开发中高频用到的点。2. QWidget 常用属性与内置组件实战窗口透明度、光标、字体、提示与焦点策略QWidget 提供了一大批属性方法覆盖外观、交互、状态等各个方面。与其死记硬背不如按使用场景来分类。下面挑几个最常用的属性结合可运行的代码说明。2.1 窗口透明度 windowOpacitywindowOpacity()返回当前窗口的不透明度类型是 float范围 0.0 到 1.0。0.0 表示全透明1.0 表示完全不透明。setWindowOpacity(float n)用来设置这个值。这个属性只对顶层窗口生效对嵌入的子控件无效。一个典型用法是做淡入淡出效果或者做一个半透明的悬浮面板。在界面上放两个按钮objectName 分别为pushButton_add和pushButton_sub然后在 widget.cpp 里写槽函数void Widget::on_pushButton_add_clicked() { float opacity this-windowOpacity(); if (opacity 1.0) { return; } qDebug() opacity; opacity 0.1; this-setWindowOpacity(opacity); } void Widget::on_pushButton_sub_clicked() { float opacity this-windowOpacity(); if (opacity 0.0) { return; } qDebug() opacity; opacity - 0.1; this-setWindowOpacity(opacity); }运行后点击减号窗口逐渐变透明能透过窗口看到后面的内容点击加号又慢慢恢复。控制台会打印每次的 opacity 值。这里有个坑要注意C 的 float 遵循 IEEE 754 标准运算会有精度误差。所以1 - 0.1的结果并不是精确的 0.9而是 0.90000004 之类。如果你用去比较浮点数很容易出问题。判断边界时用和更稳妥。2.2 光标 cursorcursor()返回当前控件的 QCursor 对象setCursor(const QCursor)设置鼠标悬停在该控件上时显示的光标形状。另外QGuiApplication::setOverrideCursor()可以设置全局光标会覆盖所有控件的单独设置。在 Qt Designer 里选中按钮后直接在右侧属性编辑区把 cursor 改成“等待”运行后鼠标悬停就能看到沙漏形状。用代码设置也很简单#include QPushButton Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui-setupUi(this); QPushButton* button new QPushButton(this); button-resize(100, 50); button-move(100, 100); button-setText(这是一个按钮); button-setCursor(QCursor(Qt::WaitCursor)); }Qt 内置的光标形状由Qt::CursorShape枚举定义常用的有枚举值含义Qt::ArrowCursor标准箭头Qt::CrossCursor十字Qt::WaitCursor沙漏/等待Qt::IBeamCursor文本输入竖线Qt::PointingHandCursor手型常用于链接Qt::ForbiddenCursor禁止Qt::OpenHandCursor张开的手Qt::ClosedHandCursor握紧的手如果要自定义光标可以用 QPixmap 加载图片再构造 QCursor#include QPixmap Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui-setupUi(this); QPixmap pixmap(:/huaji.png); pixmap pixmap.scaled(64, 64); QCursor cursor(pixmap, 2, 2); this-setCursor(cursor); }这里(2, 2)是“热点”坐标也就是鼠标点击时实际生效的位置。图片需要先加入 qrc 资源文件前缀设为/。热点一般设在图片的视觉中心否则点击位置会偏移。2.3 字体 fontfont()返回 QFont 对象setFont(const QFont)设置字体。QFont 的常用属性包括 family字体家族如“微软雅黑”“仿宋”、pointSize字号、weight粗细0 到 99、bold加粗、italic倾斜、underline下划线、strikeOut删除线。Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui-setupUi(this); ui-label-setText(这是一段文本); QFont font; font.setFamily(仿宋); font.setPointSize(20); font.setBold(true); font.setItalic(true); font.setUnderline(true); font.setStrikeOut(true); ui-label-setFont(font); }运行后 label 上的文字会变成仿宋、20 号、加粗、倾斜、带下划线和删除线。实际项目里不建议同时开这么多效果这里只是为了演示属性。需要注意的是字体家族名要和系统里已安装的字体匹配。如果写了系统没有的字体名Qt 会回退到默认字体不会报错但效果和预期不符。跨平台开发时最好用QFontDatabase查询可用字体或者用通用家族名如sans-serif。2.4 提示 toolTipsetToolTip()设置鼠标悬停时的提示文字setToolTipDuration()设置提示显示时长单位毫秒。toolTip 只是给用户看的代码里一般不需要读取。Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui-setupUi(this); ui-pushButton_yes-setToolTip(这个是 yes 按钮); ui-pushButton_yes-setToolTipDuration(3000); ui-pushButton_no-setToolTip(这个是 no 按钮); ui-pushButton_no-setToolTipDuration(10000); }运行后鼠标停在按钮上会弹出提示时间到后自动消失。toolTip 支持简单的 HTML 格式比如b加粗/b、br换行做复杂提示时很有用。2.5 焦点策略 focusPolicy焦点指的是当前能接收键盘输入的那个控件。比如你在输入框里打字那个输入框就拥有焦点。setFocusPolicy(Qt::FocusPolicy)决定控件如何获取焦点。Qt::FocusPolicy的取值Qt::NoFocus不接收键盘焦点无法通过 Tab 或鼠标选中。Qt::TabFocus只能通过 Tab 键获取焦点。Qt::ClickFocus只能通过鼠标点击获取焦点。Qt::StrongFocusTab 和鼠标点击都可以这是默认值。Qt::WheelFocus在 StrongFocus 基础上增加鼠标滚轮获取焦点很少用。在界面上放四个 QLineEdit默认都是 StrongFocus可以用鼠标点击或 Tab 切换。把第二个改成 NoFocus它就完全无法被选中也就无法输入。改成 TabFocus只能 Tab 选中鼠标点不进去。改成 ClickFocus只能鼠标点Tab 跳过它。这个属性对输入框、单选框、复选框这类需要键盘交互的控件特别重要。做自定义控件时如果你希望它能被 Tab 聚焦记得设置合适的 focusPolicy并在paintEvent里根据hasFocus()画出焦点框否则用户用键盘操作时会迷失位置。2.6 内置组件与布局嵌套Qt 内置组件大致分几类显示类QLabel、QProgressBar、输入类QLineEdit、QTextEdit、QSpinBox、按钮类QPushButton、QCheckBox、QRadioButton、容器类QGroupBox、QTabWidget、QScrollArea、列表类QListWidget、QTableWidget、QTreeWidget。这些组件都继承自 QWidget所以前面讲的属性它们都有。实际开发中很少单独放一个控件而是用布局管理器把它们组织起来。常用的布局有 QVBoxLayout垂直、QHBoxLayout水平、QGridLayout网格、QFormLayout表单。布局可以嵌套。比如一个设置面板外层是垂直布局里面每一行是一个水平布局左边标签右边输入框。嵌套布局能让界面自适应窗口大小比手动 setGeometry 靠谱得多。QVBoxLayout* mainLayout new QVBoxLayout(this); QHBoxLayout* row1 new QHBoxLayout(); row1-addWidget(new QLabel(用户名)); row1-addWidget(new QLineEdit()); QHBoxLayout* row2 new QHBoxLayout(); row2-addWidget(new QLabel(密码)); row2-addWidget(new QLineEdit()); mainLayout-addLayout(row1); mainLayout-addLayout(row2); mainLayout-addWidget(new QPushButton(登录));这段代码创建了一个两行输入加一个按钮的界面窗口缩放时控件会跟着调整。布局的父子关系由addLayout和addWidget自动建立不需要手动 delete。3. 自定义控件继承 QWidget 并重写绘制与事件内置组件够用的时候直接用就好。但当需求变成“画一个圆形的状态灯”“做一个带刻度的旋钮”“实现一个可拖拽的卡片”时就需要自定义控件了。自定义控件的标准做法是继承 QWidget重写paintEvent负责绘制重写鼠标或键盘事件负责交互通过信号槽对外通信。下面做一个完整的例子一个圆形的状态指示灯支持设置颜色点击时切换开关状态并发出信号。3.1 头文件 StatusLight.h#ifndef STATUSLIGHT_H #define STATUSLIGHT_H #include QWidget #include QColor class StatusLight : public QWidget { Q_OBJECT public: explicit StatusLight(QWidget *parent nullptr); void setColor(const QColor color); QColor color() const; bool isOn() const; signals: void toggled(bool on); protected: void paintEvent(QPaintEvent* event) override; void mousePressEvent(QMouseEvent* event) override; QSize sizeHint() const override; private: QColor m_color; bool m_on; }; #endif // STATUSLIGHT_H这里用到了Q_OBJECT宏它让类支持信号槽。只要类里声明了 signals 或 slots就必须加这个宏否则 moc 不会生成元对象代码编译会报 undefined reference to vtable 之类的错误。3.2 实现文件 StatusLight.cpp#include StatusLight.h #include QPainter #include QMouseEvent StatusLight::StatusLight(QWidget *parent) : QWidget(parent) , m_color(Qt::gray) , m_on(false) { setFixedSize(40, 40); setCursor(Qt::PointingHandCursor); setToolTip(点击切换状态); } void StatusLight::setColor(const QColor color) { m_color color; update(); } QColor StatusLight::color() const { return m_color; } bool StatusLight::isOn() const { return m_on; } void StatusLight::paintEvent(QPaintEvent* event) { Q_UNUSED(event); QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); QRect rect this-rect().adjusted(2, 2, -2, -2); if (m_on) { painter.setBrush(m_color); painter.setPen(QPen(m_color.darker(150), 2)); } else { painter.setBrush(Qt::lightGray); painter.setPen(QPen(Qt::gray, 2)); } painter.drawEllipse(rect); } void StatusLight::mousePressEvent(QMouseEvent* event) { if (event-button() Qt::LeftButton) { m_on !m_on; update(); emit toggled(m_on); } QWidget::mousePressEvent(event); } QSize StatusLight::sizeHint() const { return QSize(40, 40); }几个关键点paintEvent里用 QPainter 绘制。setRenderHint(QPainter::Antialiasing)开启抗锯齿圆形边缘才平滑。adjusted(2, 2, -2, -2)把绘制区域往里缩 2 像素避免边框被裁掉。mousePressEvent里判断左键切换状态调用update()触发重绘然后emit toggled(m_on)发出信号。update()是异步的Qt 会在合适时机调用paintEvent不要手动调paintEvent。sizeHint()返回建议尺寸布局管理器会参考它。配合setFixedSize可以固定大小。3.3 在主窗口中使用#include widget.h #include ui_widget.h #include StatusLight.h #include QVBoxLayout #include QLabel Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui-setupUi(this); StatusLight* light new StatusLight(this); light-setColor(Qt::green); QLabel* label new QLabel(状态关闭, this); connect(light, StatusLight::toggled, this, [label](bool on) { label-setText(on ? 状态开启 : 状态关闭); }); QVBoxLayout* layout new QVBoxLayout(this); layout-addWidget(light, 0, Qt::AlignCenter); layout-addWidget(label, 0, Qt::AlignCenter); }这里用 lambda 连接信号捕获 label 指针更新文字。运行后点击圆形指示灯颜色在灰色和绿色之间切换下方标签同步变化。3.4 编译配置如果用 qmake在 .pro 文件里加上QT widgets SOURCES main.cpp widget.cpp StatusLight.cpp HEADERS widget.h StatusLight.h如果用 CMake在 CMakeLists.txt 里cmake_minimum_required(VERSION 3.16) project(StatusLightDemo) set(CMAKE_CXX_STANDARD 17) set(CMAKE_AUTOMOC ON) find_package(Qt6 REQUIRED COMPONENTS Widgets) add_executable(StatusLightDemo main.cpp widget.cpp StatusLight.cpp StatusLight.h widget.h ) target_link_libraries(StatusLightDemo PRIVATE Qt6::Widgets)CMAKE_AUTOMOC ON很重要它让 CMake 自动处理 Q_OBJECT 宏需要的 moc 编译。如果忘了开链接时会报 vtable 相关的错误。4. 验证请求与运行结果从编译到交互的完整检查代码写完之后需要实际编译运行来验证。这一步不能省因为 Qt 的很多问题比如信号槽没连上、绘制不显示、moc 没生成只有跑起来才能发现。4.1 编译步骤用 qmake 的话在项目目录下执行qmake StatusLightDemo.pro makeWindows 上用 MinGW 的话是mingw32-make用 MSVC 的话是nmake。用 CMake 的话cmake -B build -DCMAKE_PREFIX_PATH/path/to/Qt/6.x.x/gcc_64 cmake --build buildCMAKE_PREFIX_PATH指向 Qt 安装目录具体路径根据你的环境调整。如果 Qt 已经加入系统 PATH可以省略这个参数。4.2 预期运行结果程序启动后窗口中央有一个灰色圆形下方文字显示“状态关闭”。鼠标移到圆形上光标变成手型并弹出“点击切换状态”的提示。点击圆形它变成绿色文字变成“状态开启”。再点一次恢复灰色和“状态关闭”。如果圆形边缘有锯齿检查setRenderHint(QPainter::Antialiasing)是否生效。如果点击没反应检查mousePressEvent是否被正确重写以及Q_OBJECT宏和 AUTOMOC 配置。4.3 用调试输出验证信号在 lambda 里加一行 qDebug可以确认信号确实发出了connect(light, StatusLight::toggled, this, [label](bool on) { qDebug() StatusLight toggled: on; label-setText(on ? 状态开启 : 状态关闭); });运行后点击控制台会打印StatusLight toggled: true和StatusLight toggled: false。这是验证信号槽连接最直接的方式。4.4 结合窗口透明度做联动把前面讲的 windowOpacity 和自定义控件结合可以做一个有趣的效果点击指示灯时同时改变窗口透明度。connect(light, StatusLight::toggled, this, [this, label](bool on) { label-setText(on ? 状态开启 : 状态关闭); this-setWindowOpacity(on ? 1.0 : 0.7); });开启时窗口完全不透明关闭时变成 70% 不透明度。这样就把属性设置和自定义控件串起来了也验证了信号槽的灵活性。5. 常见报错与排查undefined reference、moc 缺失、控件不显示自定义控件和 QWidget 开发中有几类错误出现频率特别高。下面按现象、原因、解决方式整理。5.1 undefined reference to vtable for StatusLight这是最典型的错误几乎每个刚写 Q_OBJECT 的人都会遇到。原因通常是类里声明了 Q_OBJECT 宏但没有执行 moc 处理或者 moc 生成的代码没有参与链接。排查步骤第一确认头文件里确实写了Q_OBJECT。注意它必须写在类声明的第一行不能写在注释里也不能写在 namespace 外面。第二确认构建系统开启了 moc。qmake 默认会处理但如果你手动写了 Makefile 就可能漏掉。CMake 需要set(CMAKE_AUTOMOC ON)。第三如果改了头文件后报这个错先执行一次 clean 再重新构建。有时候旧的 moc 文件残留会导致链接混乱。make clean qmake makeCMake 的话删掉 build 目录重新来rm -rf build cmake -B build cmake --build build5.2 控件不显示或绘制空白自定义控件继承 QWidget 后如果没有重写paintEvent默认什么都不画所以是空白的。这是正常行为不是 bug。要显示内容必须重写paintEvent并用 QPainter 绘制。另一个常见原因是控件尺寸为 0。QWidget 默认尺寸可能是 0x0如果没放进布局也没手动 resize就看不见。解决办法是setFixedSize、resize或者重写sizeHint并放进布局。还有一种情况是绘制了但颜色和背景一样。比如在白色背景上画白色圆自然看不见。调试时可以先用醒目的颜色确认绘制逻辑生效后再改回来。5.3 信号槽连接失败如果点击控件后槽函数没执行先检查 connect 的返回值。可以在连接后加判断bool ok connect(light, StatusLight::toggled, this, [label](bool on) { label-setText(on ? 状态开启 : 状态关闭); }); qDebug() connect result: ok;返回 false 说明连接失败。常见原因是信号或槽的签名不匹配比如信号带 bool 参数lambda 却没写参数或者参数类型对不上。用函数指针语法StatusLight::toggled时编译器会做类型检查比旧的 SIGNAL/SLOT 宏更安全。如果运行时提示QObject::connect: Cannot connect (nullptr)::toggled(bool) to ...说明发送者指针是空的检查控件是否已经 new 出来。5.4 焦点相关的问题自定义控件默认的 focusPolicy 是Qt::NoFocus也就是说它不会接收键盘焦点。如果你希望它能被 Tab 选中需要setFocusPolicy(Qt::StrongFocus)。同时在paintEvent里根据hasFocus()画一个焦点框否则用户看不出当前焦点在哪。if (hasFocus()) { painter.setPen(QPen(Qt::blue, 2, Qt::DashLine)); painter.drawRect(rect.adjusted(-2, -2, 2, 2)); }这段代码在控件获得焦点时画一个蓝色虚线框提升键盘操作的可访问性。5.5 内存与父子关系Qt 的对象树机制会自动管理内存父对象销毁时所有子对象也会被销毁。所以new QPushButton(this)之后不需要手动 delete。但如果你 new 了一个没有父对象的控件就要自己负责释放否则会内存泄漏。布局里的控件会自动设置父子关系所以layout-addWidget(button)之后button 的父对象就是布局所在的窗口。这一点在排查“控件找不到父对象”的问题时很有用。6. 把 QWidget 体系用起来从内置组件到自定义控件的实践路径走到这里QWidget 的核心用法基本覆盖了。回头看整个 Q组件体系其实就三层QObject 提供信号槽和对象树QPaintDevice 提供绘制能力QWidget 把两者结合并加上事件系统。内置控件是官方封装好的常用组合自定义控件是你按需组合这三层能力。实际开发中我的建议是能用内置组件就用内置组件它们经过充分测试样式和交互都符合平台习惯。只有当内置组件确实无法满足需求时才考虑自定义。自定义时优先继承现有的相近控件比如做一个特殊按钮就继承 QPushButton只重写需要改的部分而不是从 QWidget 从零开始。信号槽是贯穿始终的通信方式。自定义控件通过 signals 对外通知状态变化通过 slots 接收外部指令。这种松耦合设计让控件可以独立开发和测试也方便在不同界面里复用。如果你在练习过程中遇到编译或运行问题可以对照第 5 节的排查清单逐项检查。需要查阅 Qt 官方文档时可以从接入文档入手把环境配置和 API 调用方式理清楚。模型对话入口适合快速验证一些 API 用法和参数含义Coding Plan 则更适合需要长期写 Qt 项目、反复调试编译的场景。把工具用顺手自定义控件的开发效率会明显提升。
RELATED

相关推荐

Spring策略模式+工厂模式重构支付if-else实战指南

Spring策略模式+工厂模式重构支付if-else实战指南

如果你写过几年Java后端,大概率对一长串if-else或者switch已经形成了“条件反射式”的厌恶。最近我在订单支付模块里做了一次重构,核心就是用Spring容器配合策略模式(Strategy Pattern)和工厂模式(Factory Pattern&…

📅 2026/10/2 6:05:16
Hermes Agent 常见报错排查与问题解决:TaoToken 统一 Key 配置与 Docker/MCP 环境验证

Hermes Agent 常见报错排查与问题解决:TaoToken 统一 Key 配置与 Docker/MCP 环境验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📅 2026/10/2 6:05:16
OpenClaw 要求自配大模型 API Key:把 endpoint 改到 TaoToken 后,开源自由还是责任甩锅?

OpenClaw 要求自配大模型 API Key:把 endpoint 改到 TaoToken 后,开源自由还是责任甩锅?

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📅 2026/10/2 6:00:16
MORE NEWS

更多资讯

📰

木材防霉剂,木材防霉粉,防霉乳浆木材托盘料改如何选择

木材防霉处理的效果,很大程度上取决于剂型与木材特性的匹配度。同为防霉产品,水剂型防霉剂、粉剂型防霉粉与乳浆型防霉乳浆在渗透机理、施工方式和适用场景上存在明显差异。本文以杂木托盘为基准场景,从渗透性与施工参数两个维度对三种剂型做…

📰

不换ERP,如何让AI Agent替企业查数、分析与办理业务

老板半夜给我打电话,说要看华东区上个月的销售毛利,但公司ERP里的报表模块导出来的Excel,光是预处理就要半小时。这不是个例。我去年帮好几家企业做过类似的数字化项目,大家几乎都卡在同一个地方:ERP这套核心系统不是说…

📰

从 0 到 1:基于 FastAPI + Vue + YOLOv8 打造 AI 智慧教室专注度监控系统(附完整源码与避坑指南)

picture 1st 从 0 到 1:基于 FastAPI + Vue + YOLOv8 打造 AI 智慧教室专注度监控系统(附完整源码与避坑指南) 前言:晚自习老师巡课太累?学生偷偷走神、趴桌睡觉难以察觉?在线教育缺乏课堂反馈?今天,我将带你从零构建一个实时的 AI 学生专注度监控系统。本文将毫无…

📰

无人机飞行数据录放析闭环:ULOG与ROS2 Bag对齐实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

Java虚拟线程(四)

SpringBoot3.2 全局开启虚拟线程后,业务代码使用虚拟线程处理业务前置:spring.threads.virtual.enabledtrue这个配置只作用于 Web 容器(Tomcat/Jetty):HTTP 请求进来,由虚拟线程处理 Controller。⚠️ 重要…

📰

医学影像设备学综合实验台:X线机核心电路设计与实验原理解析

摘要医学影像设备学是医学影像技术、医学工程专业的核心课程,教学难点在于X线机高压发生器是一个高度集成的"黑箱":整流、逆变、稳压、定时、保护等多个子系统紧密耦合在一块高压油箱和控制柜里,学生在教材上看到的只是密密麻麻的电…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬