目录引言一、模态对话框accept /reject 消息机制1. 项目搭建2. 主界面 ↔ 登录界面互相切换二、QT内置标准对话框2.1 QColorDialog 颜色对话框2.2 QFileDialog 文件选择对话框2.3 QInputDialog 输入对话框4 种类型2.4 QMessageBox 消息提示框2.5 QProgressDialog 进度对话框2.6 QWizard 向导对话框三、QLineEdit 单行输入框详解3.1 四种 EchoMode 回显模式3.2 实战训练3.3 QRegularExpressionValidator 正则校验四、Qt 布局管理4.1 通过ui设置布局4.2 通过代码设置布局结语引言Qt GUI 开发中弹窗、输入框、布局是基础模块。初学者常混淆模态对话框 exec() 返回逻辑、分不清标准对话框适用场景、控件错乱或窗口变形、界面切换内存泄漏、窗口隐藏/关闭逻辑踩坑。本文从模态对话框消息机制讲起实现登录与主界面跳转覆盖 Qt 标准对话框颜色、文件、输入框、消息提示、进度条、向导讲解 QLineEdit 回显模式、输入掩码、正则校验演示 Qt Designer 与纯 C 手动布局并结合登录/注册切换案例用 shared_ptr 与 weak_ptr 解决循环引用内存泄漏。代码可直接编译运行适合作学习资料与速查手册。前置说明本文使用 Qt6 语法信号槽采用新式函数指针写法所有示例代码可直接新建 Qt Widgets 项目测试一、模态对话框accept /reject 消息机制我们创建一个模态对话框调用exec函数后可以根据其返回值进行不同的处理exec的返回值有两种Qt的官方文档记录的为QDialog::Accepted QDialog::RejectedAccepted 表示接受消息 Rejected表示拒绝消息。常见误区很多同学以为accept()/reject()是信号它们本质是 QDialog 的成员函数函数内部会自动发出 accept/reject 信号最终让exec()结束阻塞并返回对应枚举。1. 项目搭建新建 Qt Widgets Application主窗口类MainWindow再新增 Qt 设计师界面类MyDialog基类QDialog作为登录弹窗。在mydialog.ui放置两个按钮pushButton文本【进入主界面】pushButton_2文本【退出程序】在设计师界面点击Edit Signal/Slots 信号槽的按钮进入信号槽编辑界面, 鼠标按住退出程序按钮不松开拖动将另一端连接到MyDialog对话框QPushbutton这边信号选择clicked() MyDialog信号选择reject这样就将两个信号连接起来了我们点击退出程序按钮会触发MyDialog发送reject信号因为MyDialog调用exec后等待信号返回此时收到reject信号exec就会返回Rjected值。同样道理MyDialog发送accetp()信号后, exec返回值为Accepted。我们也能用手写代码的方式点击Edit Widget 按钮 然后右键点击键入主界面按钮点击进入槽在Qt 为我们生成的槽函数里添加accetp()信号发送逻辑void MyDialog::on_pushButton_clicked() { accept(); // 触发Acceptedexec返回QDialog::Accepted }main 函数逻辑先弹出登录对话框根据返回值决定是否打开主窗口int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; MyDialog dialog; if(dialog.exec() QDialog::Accepted){ w.show(); return a.exec(); }else{ return 0; } }运行后我们点击进入主界面按钮界面跳转至主界面点击退出按钮程序退出。2. 主界面 ↔ 登录界面互相切换现在我们要实现主界面和登录界面的互相切换我们刚才创建的对话框界面MyDialog界面是登录界面主界面是MainWindow类。我们在mainwindow.ui添加两个按钮返回登录按钮和退出程序按钮, 再添加一个label表示这是主界面.然后点击Edit Signal/Slot 进入信号编辑界面点击退出程序按钮不松开拖动到尾部连接MainWindow的主界面上选择退出程序的clicked()信号MainWindow选择reject信号,将两个信号连接起来。然后右击登录按钮转到槽在槽函数里添加这个逻辑void MainWindow::on_pushButton_clicked() { this-close(); // close()只是隐藏窗口对象没有销毁 MyDialog mydialog; if(mydialog.exec() QDialog::Accepted) { this-show(); // 登录确认重新显示主窗口 } else { // 登录弹窗选择退出不再打开主界面 return; } }点击返回登陆按钮就会close主窗口但是并不是真的关闭只是将主窗口隐藏Qt回收机制是所有窗口都关闭后才回收。再次运行程序点击进入主界面按钮就可以进入主界面点击返回登录按钮就可以返回登录界面可以实现两个界面的切换了。注意close()不等于对象析构。对于栈上创建的窗口close 只是隐藏只有堆 new 出来的窗口设置setAttribute(Qt::WA_DeleteOnClose)之后close 才会自动释放内存。本案例中 MainWindow 在 main 函数是栈对象所以 close 只是隐藏后续可以再次 show。二、QT内置标准对话框本文介绍几种标准对话框都是Qt封装好的我们先创建一个界面添加几个按钮然后分别在几个按钮的回调函数里添加创建不同对话框的逻辑2.1 QColorDialog 颜色对话框颜色对话框用来选择颜色创建后会显示各种颜色和透明度信息//创建颜色对话框 void MainWindow::on_colorBtn_clicked() { //默认父窗口是主窗口蓝色 QColorDialog colorDlg(Qt::blue,this); //开启透明度通道Alpha可以选择带透明的颜色 colorDlg.setOption(QColorDialog::ShowAlphaChannel); //阻塞等待用户操作 colorDlg.exec(); //获取当前颜色 QColor colorcolorDlg.currentColor(); qDebug()color is color; }2.2 QFileDialog 文件选择对话框getOpenFileName静态函数最常用支持文件过滤器用;;分隔多种文件类型void MainWindow::on_pushButton_2_clicked() { QString path QDir::currentPath(); QString title tr(文件对话框); QString filter tr(文本文件(*.txt);;图片文件(*.jpg *.gif *.png);;所有文件(*.*)); QString aFileNameQFileDialog::getOpenFileName(this,title,path,filter); qDebug() aFileName endl; }2.3 QInputDialog 输入对话框4 种类型统一参数最后一个bool *ok用来判断用户是点击【确定】还是【取消】。输入对话框分几种包括文本输入对话框整数输入对话框浮点数输入对话框条目输入对话框。文本输入对话框void MainWindow::on_pushButton_3_clicked() { bool ok false; auto text QInputDialog::getText(this, tr(文字输入对话框), tr(请输入用户的姓名), QLineEdit::Normal, tr(admin), ok); if(ok){ qDebug() text endl; } }整形输入对话框void MainWindow::on_pushButton_4_clicked() { bool ok false; auto intdata QInputDialog::getInt(this,tr(数字输入对话框),tr(请输入数字),200,-200,400,10,ok); if(ok){ qDebug() intdata endl; } }浮点输入对话框//浮点数对话框 void MainWindow::on_pushButton_clicked() { bool ok; auto floatdataQInputDialog::getDouble(this,tr(浮点数对话),tr(请输入浮点数),0.1,-2,4,2,ok); if(ok) { qDebug()floatdata\n; } }条目输入对话框//条目输入对话框 void MainWindow::on_pushButton_5_clicked() { QStringList items; //创建字符串列表下拉选项 itemstr(条目1)tr(条目2); bool ok; //允许编辑 auto itemDataQInputDialog::getItem(this,tr(条目对话框),tr(输入或选择条目),items,0,true,ok); if(ok) { qDebug()item is itemData\n; } }2.4 QMessageBox 消息提示框四种级别question 提问 /information 通知 /warning 警告 /critical 严重错误//提示/通知/警告/关键提示 对话框 void MainWindow::on_pushButton_6_clicked() { auto retQMessageBox::question(this,tr(提问对话框),tr(你喜欢读书吗)); if(retQMessageBox::Yes){ qDebug()ret is ret; qDebug()你很牛; }else{ return; } auto ret2QMessageBox::information(this,tr(通知对话框),tr(你好读书人),QMessageBox::Yes); if(ret2QMessageBox::Yes) { qDebug()ret2 isret2; }else{ return; } auto retsQMessageBox::warning(this,tr(警告对话框),tr(不要过度学习小心秃头),QMessageBox::Yes); if(retsQMessageBox::Yes) { qDebug()rets is rets; }else{ return ; } auto ret4QMessageBox::critical(this,tr(关键提示对话框),tr(试炼尽头是花开万里),QMessageBox::Yes); if(ret4QMessageBox::Yes) { qDebug()ret4 is ret4\n; }else{ return; } }2.5 QProgressDialog 进度对话框当我们复制或进行文件传输时会显示一个进度条的对话框我们可以使用QProcessDialog来操作。void MainWindow::on_pushButton_8_clicked() { // 进度提示框一闪而逝不是逻辑问题是5000量级太小了 QProgressDialog progressDialog(tr(正在复制),tr(取消复制),0,5000,this); progressDialog.setWindowTitle(tr(文件复制进度对话框)); progressDialog.setWindowModality(Qt::ApplicationModal); progressDialog.show(); for(int i 0; i 5000; i){ progressDialog.setValue(i); QApplication::processEvents(); if(progressDialog.wasCanceled()){ break; } } progressDialog.setValue(5000); }因为循环很快完成所以进度条一闪而逝那么我们可以通过定时器的方式定时更新进度这样就可以更清楚的看到进度条对话框更新情况了void MainWindow::on_pushButton_8_clicked() { //改用定时器 _progressDialog new QProgressDialog(tr(正在复制),tr(取消复制),0,5000,this); _progressDialog-setWindowTitle(tr(文件复制进度对话框)); _progressDialog-setWindowModality(Qt::ApplicationModal); _timer new QTimer(this); connect(_timer, QTimer::timeout, this, MainWindow::on_updateProgressDialog); connect(_progressDialog, QProgressDialog::canceled, this, MainWindow::on_cancelProgressDialog); _timer-start(2); qDebug(复制结束); }上面代码连接了定时器的timeout信号和主窗口的on_updateProgressDialog函数, 该函数的主要作用就是定时更新进度条逻辑如下//加载对话框 void MainWindow::on_updateProgressDialog() { _counter; if(_counter5000) { _timer-stop(); delete _timer; _timer nullptr; delete _progressDialog; _counter0; return ; } _progressDialog-setValue(_counter); //调用 setValue()、进度开始变化之后才自动弹出窗口。 }另外我们需要在进度条满了的时候发消息通知主窗口关闭//通过取消关闭对话框 void MainWindow::on_cancelProgressDialog(){ _timer-stop(); delete _timer; _timernullptr; //避免二次删除崩溃 delete _progressDialog; _progressDialognullptr; _counter0; return; }这样进度条满了之后我们就可以回收定时器资源了。2.6 QWizard 向导对话框当我们想引导用户操作时可以采用向导对话框类似软件安装向导由多个QWizardPage页面组成自带上一步 / 下一步 / 完成按钮//向导对话框 void MainWindow::on_pushButton_7_clicked() { //向导容器 管理多个页面 QWizard wizard(this); wizard.setWindowTitle(tr(全民偶像)); //每一页单独的页面 QWizardPage* page1new QWizardPage(); page1-setTitle(tr(快来pick你心仪的偶像吧)); auto label1new QLabel(); //展示文本、图片的标签 label1-setText(tr(该程序助力于爱豆出道)); //QVBoxLayout垂直布局管理器控件从上往下竖直排列 QVBoxLayout *layoutnew QVBoxLayout(); layout-addWidget(label1); //将标签添加到垂直布局中 page1-setLayout(layout); //布局加到页面中 wizard.addPage(page1); //布局加到向导中成为向导第一页 QWizardPage* page2new QWizardPage(); page2-setTitle(tr(选择心动类型)); //按钮组由page2管理开启互斥逻辑只能选一个 QButtonGroup *groupnew QButtonGroup(page2); QRadioButton *btn1new QRadioButton(); btn1-setText(tr(小奶狗)); group-addButton(btn1); QRadioButton *btn2new QRadioButton(); btn2-setText(tr(成熟年上)); group-addButton(btn2); QRadioButton *btn3new QRadioButton(); btn3-setText(tr(阳光年下)); group-addButton(btn3); QRadioButton *btn4new QRadioButton(); btn4-setText(tr(顶级天蝎男)); group-addButton(btn4); QRadioButton *btn5new QRadioButton(); btn5-setText(tr(清风霁月君子)); group-addButton(btn5); QRadioButton *btn6new QRadioButton(); btn6-setText(tr(腹黑病娇男配)); group-addButton(btn6); QVBoxLayout *vboxLayout2 new QVBoxLayout(); //将所有按钮添加到垂直布局 for(int i0;igroup-buttons().size();i) { vboxLayout2-addWidget(group-buttons()[i]); } page2-setLayout(vboxLayout2); wizard.addPage(page2); QWizardPage* page3new QWizardPage(); page3-setTitle(tr(出道名单即将确定)); auto label3new QLabel(); label3-setText(tr(感谢助力期待首场团体演出)); QVBoxLayout *layout3new QVBoxLayout(); layout3-addWidget(label3); page3-setLayout(layout3); wizard.addPage(page3); wizard.show(); wizard.exec(); }三、QLineEdit 单行输入框详解QLineEdit用于单行文本录入核心两大功能回显模式输入校验掩码 / 正则3.1 四种 EchoMode 回显模式QLineEdit 属于输入插件用来实现单行录入。支持几种录入模式。Normal 表示正常录入,录入的信息会显示在QLineEdit上。Password 表示密码录入的方式录入的信息不显示QLineEdit只是通过黑色圆点显示。NoEcho 表示不显示录入信息类似于Linux输入密码时显示的是一片空白。PasswordEchoOnEdit 表示在输入的一刹那可以看到字符但是立刻变为不可见的黑色圆点显示。3.2 实战训练我们创建一个QApplication项目名字叫editline。项目主界面取名MainWindow类继承于QMainWindow。Qt为我们自动生成ui文件。然后在ui界面里添加四个QLineEdit和Label我将ip的QLineEdit名字改为ipedit,设置ipedit的输入方式为Normal这样可以在输入时看到输入的字符。我们可以给ipedit设置mask规定输入的字符只能为0~9的数字// IP地址掩码 000.000.000.000下划线是占位符 ui-ipedit-setEchoMode(QLineEdit::Normal); QString ip_mask 000.000.000.000;_; ui-ipedit-setInputMask(ip_mask);具体的mask规则可以参考Qt官方文档这里列举一下常见的mask规则利用上面的规则我们可以编写一些常用的mask接下来我们设置mac地址的mask和录入模式,mac地址的edit被命名为macedit// MAC地址掩码H代表十六进制 0-9 A-F ui-macedit-setEchoMode(QLineEdit::Normal); QString mac_mask HH:HH:HH:HH:HH:HH;_; ui-macedit-setInputMask(mac_mask);通过设置mask规定mac的输入内容只能为A~F以及0~9的字符。3.3 QRegularExpressionValidator 正则校验其实除了通过mask限制edit录入的内容外还可以通过正则表达式限制,比如我们设置邮箱edit的录入内容ui-emailedit-setEchoMode(QLineEdit::Normal); //正则类 邮箱正则表达式 QRegularExpression regx([a-zA-Z0-9_-][a-zA-Z0-9]\.[a-zA-Z0-9]); //正则校验第二个参数为父对象 QValidator * validatornew QRegularExpressionValidator(regx,ui-emailEdit); //给输入框绑定校验原则 ui-emailEdit-setValidator(validator);我们通过正则表达式限定了有限的规则为 “字符串和数子组合 字符串和数子组合 . 字符串和数子组合”。具体的正则表达式可以去Qt文档查看也可以看看下边这个图接下来我们可以设置密码输入框的输入模式为Password保证录入时不显示密码ui-passwdedit-setEchoMode(QLineEdit::Password);四、Qt 布局管理布局的核心目的窗口拉伸时控件自动适配、不会错位。Qt 三大基础布局QHBoxLayout水平布局横向排列QVBoxLayout垂直布局纵向排列QGridLayout栅格布局表格多行多列弹簧QSpacerItemSpacer用来占位、留白、控制对齐方式sizePolicy 控制拉伸策略4.1 通过ui设置布局我们先创建一个窗口应用程序程序名叫layout基类选择QMainWindow。但我们不使用这个mainwindow我们创建一个Qt应用程序类LoginQt会为我们自动生成login.ui文件。我们进入ui文件编辑添加一个label提示改为用户: 在后边添加一个lineedit控件按住ctrl鼠标依次点击这两个控件选中后再点击工具栏的水平布局按钮就可以看到用户label和输入框处于同一水平线了。但是输入框会被拉长而且label和输入框占满了整个水平空间。这时我们可以通过拖动左侧控件列表中的Horizonal Spacer将其放入用户标签的左侧再拖动一个Horizonal Spacer将其放在输入框的右侧就可以看到用户标签和输入框被挤在中间了并且两侧留有空间了。Spacer可以设置几种模式包括fixedexpanding, maximum, minimum等模式。依次类推我们在添加密码标签和输入框以及登录和注册按钮通过ui界面的控件调整布局。4.2 通过代码设置布局上面我们通过ui设置了布局接下来我们通过代码设置布局设置注册界面的布局注册类的声明如下#ifndef REGISTER_H #define REGISTER_H #includememory #include QDialog class Login; namespace Ui { class Register; } class Register : public QDialog { Q_OBJECT public: explicit Register(QWidget *parent nullptr); ~Register(); void set_login(const std::weak_ptrLogin login); void slot_register(); private: Ui::Register *ui; //std::shared_ptrLogin _login; //互相锁住内存泄漏 std::weak_ptrLogin _login; //弱引用不增加引用计数 }; #endif // REGISTER_H因为要实现登录和注册界面之间的切换所以Register类包含了Login类的弱指针Register类的具体实现如下#include register.h #include ui_register.h #includeQHBoxLayout #includeQSpacerItem #includeQLabel #includeQLineEdit #includeQVBoxLayout #includeQPushButton #includelogin.h Register::Register(QWidget *parent) : QDialog(parent) , ui(new Ui::Register) { ui-setupUi(this); //用户窗口尺寸锁死 this-setMaximumSize(QSize(400,550)); this-setMinimumSize(QSize(400,550)); auto vbox_layoutnew QVBoxLayout(); //创建垂直布局主布局 //QSpacerItem 不用手动删 //加到主垂直布局放在最顶部用来把下面内容往下挤。 auto verticalSpacer1new QSpacerItem(40,20,QSizePolicy::Minimum,QSizePolicy::Expanding); vbox_layout-addItem(verticalSpacer1); QSpacerItem *name_item1new QSpacerItem(40,20,QSizePolicy::Fixed,QSizePolicy::Minimum); QLabel *name_label new QLabel(); name_label-setText(邮箱); QLineEdit *name_editnew QLineEdit(); //邮箱一行使用水平布局 QHBoxLayout auto name_layoutnew QHBoxLayout(); name_layout-addItem(name_item1); name_layout-addWidget(name_label); name_layout-addWidget(name_edit); QSpacerItem *name_item2new QSpacerItem(40,20,QSizePolicy::Fixed,QSizePolicy::Minimum); name_layout-addItem(name_item2); vbox_layout-addLayout(name_layout); //将水平布局一行加入垂直布局 QLabel *pwd_labelnew QLabel(); pwd_label-setText(密码); QLineEdit *pwd_editnew QLineEdit(); auto verticalSpacer2new QSpacerItem(40,20,QSizePolicy::Maximum,QSizePolicy::Maximum); //密码行之前先加一个垂直方向的间隔弹簧 vbox_layout-addItem(verticalSpacer2); auto pwd_layoutnew QHBoxLayout(); QSpacerItem *pwd_item2new QSpacerItem(40,20,QSizePolicy::Fixed,QSizePolicy::Minimum); QSpacerItem *pwd_item1new QSpacerItem(40,20,QSizePolicy::Fixed,QSizePolicy::Minimum); pwd_layout-addItem(pwd_item1); pwd_layout-addWidget(pwd_label); pwd_layout-addWidget(pwd_edit); pwd_layout-addItem(pwd_item2); vbox_layout-addLayout(pwd_layout); //密码行 和 注册按钮之间的间隔 auto verticalSpacer3new QSpacerItem(40,30,QSizePolicy::Fixed,QSizePolicy::Maximum); vbox_layout-addItem(verticalSpacer3); QSpacerItem *reg_btn_item1new QSpacerItem(150,20,QSizePolicy::Fixed,QSizePolicy::Minimum); QSpacerItem *reg_btn_item2new QSpacerItem(150,20,QSizePolicy::Fixed,QSizePolicy::Minimum); auto _reg_btnnew QPushButton(); _reg_btn-setText(注册); auto regbtn_layoutnew QHBoxLayout(); regbtn_layout-addItem(reg_btn_item1); regbtn_layout-addWidget(_reg_btn,5); //拉伸系数这一行多余空间优先分给按钮 regbtn_layout-addItem(reg_btn_item2); vbox_layout-addLayout(regbtn_layout); //最底部弹性弹簧 auto verticalSpacer4new QSpacerItem(40,20,QSizePolicy::Fixed,QSizePolicy::Expanding); vbox_layout-addItem(verticalSpacer4); this-setLayout(vbox_layout); connect(_reg_btn,QPushButton::clicked,this,Register::slot_register); } Register::~Register() { delete ui; } void Register::set_login(const std::weak_ptrLogin login) { _loginlogin; } void Register::slot_register() { this-close(); auto shared_login_login.lock(); shared_login-show(); }Register的构造函数中用代码的方式创建了一个垂直布局垂直布局中增加了两个spacer分别是verticalSpacer1和verticalSpacer4以及三个水平布局pwd_layoutname_layout以及regbtn_layout然后分别用代码的方式在三个布局中添加spacer和控件。Login类的声明如下#ifndef LOGIN_H #define LOGIN_H #include QDialog QT_BEGIN_NAMESPACE namespace Ui { class Login; } QT_END_NAMESPACE //做个声明 class Register; class Login : public QDialog,public std::enable_shared_from_thisLogin { Q_OBJECT public: Login(QWidget *parent nullptr); ~Login(); void initSignals(); //初始化信号和槽 private slots: void on_pushButton_2_clicked(); private: Ui::Login *ui; std::shared_ptrRegister _register; //智能指针 }; #endif // LOGIN_HLogin实现如下#include login.h #include ui_login.h #includeregister.h #includeQPainter Login::Login(QWidget *parent) : QDialog(parent) , ui(new Ui::Login) { ui-setupUi(this); } Login::~Login() { delete ui; } void Login::initSignals(){ _registerstd::make_sharedRegister(); _register-set_login(shared_from_this()); //返回login类的智能指针 } void Login::on_pushButton_2_clicked() { this-close(); _register-show(); }main函数的实现如下#include login.h #include QStyleHints #include QApplication #includeregister.h int main(int argc, char *argv[]) { QApplication a(argc, argv); // 全局浅色样式所有控件生效 a.setStyleSheet(R( QWidget { background: #ffffff; color: #202020; } QPushButton { background: #f5f5f5; border: 1px solid #cccccc; padding: 4px; } QLineEdit { background: white; border:1px solid #aaa; } QDialog { background-color: white; } )); std::shared_ptrLogin wstd::make_sharedLogin(); w-initSignals(); w-show(); return a.exec(); }点击运行按钮程序运行起来就可以从登录界面切换到注册界面了重要纠正weak_ptr.lock()必须判断返回值防止 Login 对象已经销毁野指针访问崩溃。结语对话框、单行输入框、布局是 Qt GUI 开发的地基。模态对话框exec()阻塞逻辑、accept/reject 返回值控制弹窗流转标准对话框把高频弹窗场景封装到位不用重复造轮子QLineEdit 配合掩码、正则实现表单输入校验是登录注册页面必备布局管理器解决窗口自适应问题而动态代码布局结合智能指针能安全实现多界面跳转规避循环引用内存泄漏的经典坑。很多 Qt 初学者写界面只靠绝对坐标固定控件位置一旦窗口大小变化界面直接崩盘弹窗逻辑分不清 hide、close、delete频繁出现内存泄漏或者偶发崩溃。吃透本篇内容后续开发表单、登录系统、配置弹窗、向导页面都可以直接复用这套思路。
企业数字化 ERP 产品动态
相关推荐
alertmanger 告警rule文件配置(二) #样例groups:
- name: dev-node-exporterrules:- alert: dev-node-exporter-down #告警名称expr: up{job"node-exporter"} 0 # PromQL表达式for: 5m #最大持续时间labels: serverity: 100 # 告警程度
# team: test #team分组 Alertmanager对应值分组告警an… · 2026/11/5 3:48:17
Linux 学习笔记(五十四):内网穿透实战——用 frp 让外网访问你的私人电脑 📌 核心结论(TL;DR):内网穿透背景:由于 NAT 技术的存在,外部网络无法主动连接内网的私有 IP。核心思路:利用一台拥有公网 IP 的服务器作为中转站。frp 架构:由运行在公网的 frps 和运… · 2026/11/5 3:47:17
Linux 学习笔记(五十三):NAT 技术与代理服务——正反向代理的本质区别 📌 核心结论(TL;DR):NAT 技术:将私有 IP 替换为公网 IP,利用端口号区分不同主机(NAPT),拯救了 IPv4。正向代理:代表客户端,隐藏客户端身份。如翻墙… · 2026/11/5 3:47:17
零基础3个月速成网络安全工程师实战指南 1. 项目概述作为一名在网络安全领域摸爬滚打多年的从业者,我经常被问到同一个问题:"零基础如何快速入门网络安全?"今天我就把自己当年用3个月时间从完全不懂到能够独立完成基础渗透测试的学习路径完整分享出来。这份清单之所以被称… · 2026/11/5 4:40:54
AI驱动的数据采集:Bright Data MCP与Trae实践指南 1. 项目概述:AI时代的数据采集新范式最近半年我一直在探索如何将AI能力融入传统数据采集工作流。作为一名长期从事网络数据采集的开发者,我深刻感受到大模型技术对爬虫领域的颠覆性影响。过去我们需要花费大量时间处理反爬机制、解析网页结构、维护代理I… · 2026/11/5 4:40:54
Java C++算法题解leetcode801使序列递增的最小交换次数 前言
LeetCode 801 的题意是:给定两个长度相同的整数数组 nums1 和 nums2,每次操作可以交换某个下标 i 上的两个元素,问最少交换多少次,能使两个数组都严格递增。题目保证答案存在。
这道题最容易掉进的坑是贪心:看到某… · 2026/11/5 4:40:54
基于ECharts的实时天气可视化开发实践 1. 项目背景与核心价值去年夏天帮朋友改造民宿时,发现他们前台用的天气显示还是老式LED屏,不仅信息单一,遇到极端天气也缺乏预警提示。于是用周末时间做了这个网页版天气可视化工具,现在已经成为他们日常运营的标配。相比传统方案… · 2026/11/5 4:40:54
MySQL 把 GROUP_CONCAT 结果当 IN 条件失效的原因与改写 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 4:40:54
TED精读如何训练高阶英语思维与认知能力 1. 项目概述:这不是一节普通英语课,而是一次认知升级的实操训练“跟TED演讲学英文:How AI can save our humanity by Kai-Fu Lee”——这个标题乍看是语言学习类内容,但真正懂行的人一眼就能看出,它根本不是在教“how … · 2026/11/5 4:39:54
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 3:16:49
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 6:59:29
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 7:02:38
多智能体协作系统架构设计与实践优化 1. 多智能体协作系统的时代背景2017年Transformer架构的诞生彻底改变了人工智能的发展轨迹。当行业还沉浸在单一大模型带来的性能突破时,Anthropic的研究团队已经将目光投向了更前沿的领域——如何让多个智能体通过协作产生超越单体能力的系统智能。这就像交响乐团中… · 2026/11/5 0:00:39
大模型系统性入门实战指南:从原理到部署微调的全链路路线 提到大模型的系统性入门,我先说个结论:这事真不难,难的是资料太散、路线太多,今天这个框架明天那个工具,新人很容易在“收藏夹吃灰”和“教程看到一半放弃”之间反复横跳。市面上关于大模型的内容少说有几十万篇&#… · 2026/11/5 0:00:39
鸿蒙文件系统沙箱机制解析与开发实践 1. 鸿蒙文件系统沙箱机制深度解析作为一名从Android转向鸿蒙开发的工程师,我深刻体会到文件系统访问是迁移过程中最先遇到的"拦路虎"。在Android上运行良好的文件读写代码,在鸿蒙真机环境却频频出现文件写入后神秘消失或直接抛出权限拒绝错误的… · 2026/11/5 0:00:39
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 3:16:49
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 6:59:29
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 7:02:38