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

【QQmusic自定义控件实现音乐播放器核心交互逻辑】第三章

🌹 作者: 云小逸
🤟 个人主页: 云小逸的主页
🤟 motto: 要敢于一个人默默的面对自己,强大自己才是核心。不要等到什么都没有了,才下定决心去做。种一颗树,最好的时间是十年前,其次就是现在!学会自己和解,与过去和解,努力爱自己。希望春天来之前,我们一起面朝大海,春暖花开!

🥇 专栏:

  • 动态规划
  • C 语言
  • C++
  • Java 语言
  • Linux 编程
  • 算法
  • 待续…

文章目录

    • 📚 前言
    • 一、BtForm
      • 1. BtForm界面设计
      • 2. BtForm类中实现
      • 3. 核心要点总结
    • 二、推荐页面
      • 1. 推荐页面分析
      • 2. 推荐页布局
      • 3. 自定义RecBox
      • 4. 自定义RecBoxItem
      • 5. RecBox添加RecBoxItem
      • 6. RecBox中btUp和btDown按钮clicked处理
      • 7. 核心要点总结
    • 三、自定义CommonPage
      • 1. CommonPage页面分析
      • 2. CommonPage页面布局
      • 3. CommonPage界面设置和显示
      • 4. 核心要点总结
    • 四、自定义ListItemBox
      • 1. ListItemBox页面分析
      • 2. ListItemBox页面布局
      • 3. ListItemBox显示测试
      • 4. 支持hover效果
      • 5. 核心要点总结
    • 五、自定义MusicSlider
      • 1. 功能与设计
      • 2. 交互实现
      • 3. 核心要点总结
    • 六、自定义VolumeTool
      • 1. 控件分析
      • 2. 界面布局
      • 3. 界面设置与交互
      • 4. 核心要点总结
    • 📣 结语

📚 前言

在Qt开发里,自定义控件是极为关键的,它能够帮助我们打造出交互性强且界面精美的应用程序。在QQMusic项目中,有几个重要的自定义控件,像BtForm、推荐页相关控件、CommonPage、ListItemBox、MusicSlider和VolumeTool等。下面我会详细解释这些控件的设计思路、实现方式以及关键代码,让你能更好地理解它们。


一、BtForm

1. BtForm界面设计

  • 功能定位:这个控件在音乐播放器的左侧,充当导航按钮。它不仅有图标和文本,还有动画效果。点击它能切换页面,同时会有跳动的竖条显示,提示你当前选中的是哪个按钮。
  • 界面组成
    • 整体控件大小是200*35 ,有个btStyle容器Widget。在这个容器里,btIcon用来显示图标,btText显示文本,lineBox是动画容器,里面有4个QLabel,这4个QLabel能实现跳动竖条的效果。
    • 界面采用水平布局,边距和间距都设为0。当鼠标放到按钮上时,背景色会变成#D8D8D8,让你知道鼠标移到这里了。
  • 提升操作:在bodyLeft里,把QWidget提升为BtForm自定义控件。这样就能通过属性来设置图标、文本和对应的页面ID,方便后续点击按钮切换页面。

2. BtForm类中实现

  • 数据设置
// btform.h
class BtForm : public QWidget {Q_OBJECT
public:int id = 0; // 按钮对应的页面IDvoid setIcon(QString btIcon, QString btText, int mid) {ui->btIcon->setPixmap(QPixmap(btIcon));ui->btText->setText(btText);this->id = mid;}
};

这段代码定义了BtForm类,setIcon方法用于设置按钮的图标、文本和对应的页面ID。具体来说,ui->btIcon->setPixmap(QPixmap(btIcon));把传入的图标路径对应的图片设置给btIconui->btText->setText(btText);把传入的文本设置给btTextthis->id = mid;则记录下这个按钮对应的页面ID,方便后续点击按钮时能准确切换到相应页面。

  • 点击响应
// btform.cpp
void BtForm::mousePressEvent(QMouseEvent *event) {Q_UNUSED(event);ui->btStyle->setStyleSheet("#btStyle{ background:rgb(30,206,154); color:#F6F6F6; }");emit click(id);
}

mousePressEvent方法是在鼠标点击按钮时触发。Q_UNUSED(event);是为了避免编译器警告,表示我们忽略这个事件参数。ui->btStyle->setStyleSheet("#btStyle{ background:rgb(30,206,154); color:#F6F6F6; }");把按钮的背景色设置为绿色,文本颜色设置为白色,让你能直观看到按钮被点击了。emit click(id);会发射一个点击信号,并且把按钮对应的页面ID传递出去,这样上层程序就能根据这个ID来切换页面。

  • 动画效果
// btform.cpp(构造函数)
BtForm::BtForm(QWidget *parent) : QWidget(parent) {QPropertyAnimation *animationLine1 = new QPropertyAnimation(ui->line1, "geometry", this);animationLine1->setDuration(1500);animationLine1->setKeyValueAt(0, QRect(0, 15, 2, 0));animationLine1->setKeyValueAt(0.5, QRect(0, 0, 2, 15));animationLine1->setKeyValueAt(1, QRect(0, 15, 2, 0));animationLine1->setLoopCount(-1);animationLine1->start();// 类似地为line2、line3、line4设置动画
}

在构造函数里,为line1创建了一个QPropertyAnimation对象。setDuration(1500);设置动画持续时间为1500毫秒。setKeyValueAt方法设置了动画的关键帧,在开始时(0时刻)竖条隐藏,到中间(0.5时刻)竖条完全显示,结束时(1时刻)竖条又隐藏。setLoopCount(-1);表示动画无限循环。这样,竖条就会一直跳动,增强了界面的动态感。对于line2line3line4也会做类似的动画设置。

  • 动画显示控制
// btform.cpp
void BtForm::showAnimal(bool isShow) {if (isShow) {ui->lineBox->show();} else {ui->lineBox->hide();}
}

showAnimal方法用来控制lineBox的显示或隐藏。如果传入的isShowtrue,就显示lineBox,也就是显示跳动的竖条;如果为false,就隐藏。默认情况下,本地下载按钮的动画是显示的。

3. 核心要点总结

  • 数据绑定:通过setIcon方法把图标、文本和页面ID关联起来,为按钮的功能实现奠定基础。
  • 点击交互:重写mousePressEvent方法处理点击事件,改变按钮外观并发射信号,实现页面切换的交互逻辑。
  • 动画增强:利用QPropertyAnimation实现竖条的动画效果,让界面更有活力。
  • 灵活控制:通过showAnimal方法能根据需要灵活控制动画的显示。

二、推荐页面

1. 推荐页面分析

  • 布局结构:推荐页面有“推荐”“今日为你推荐”“你的歌曲补给站”这些文本。中间是轮播图区域,能左右翻页,鼠标悬停在上面还有动画效果。
  • 核心组件
    • QScrollArea:它就像一个大容器,把所有推荐内容都装在里面,还支持滚动操作,方便你查看更多内容。
    • 自定义RecBox控件:里面有左右翻页按钮,还有推荐内容区域,负责管理推荐内容的显示和切换。
    • RecBoxItem控件:是单个的推荐项,鼠标放上去时,里面的图片会往上移动。

2. 推荐页布局

  • 层级结构
    • recPage页面添加了QScrollArea,它内部采用垂直布局。里面有标题标签,还有两个RecBox,分别对应“今日为你推荐”和“你的歌曲补给站”。
    • RecBox包含左右翻页按钮(btUp/btDown)和内容区域(recListUp/recListDown),采用水平布局。
  • 样式设置:翻页按钮的背景图是up_page.png/down_page.png,鼠标悬停在按钮上时,背景色会变成#1ECD97,有明显的交互反馈。

3. 自定义RecBox

  • 界面布局
    • 左右按钮宽度是30,内容区域分上下两行,每行能显示4个RecBoxItem
    • 通过initRecBoxUi方法接收数据和行数(1行或2行),动态生成推荐项。
// recbox.cpp
void RecBox::initRecBoxUi(const QJsonArray &data, int rows) {// 清空旧内容clearRecBox();// 根据行数和数据生成推荐项for (int i = 0; i < data.size(); ++i) {if (rows == 1) {// 处理一行的情况createRecBoxItem(data[i].toObject(), 0, i);} else {// 处理两行的情况int row = i / 4;int col = i % 4;createRecBoxItem(data[i].toObject(), row, col);}}
}

initRecBoxUi方法首先调用clearRecBox清空旧的推荐项,避免重复显示。然后根据传入的行数和数据来生成推荐项。如果是一行显示的情况,就直接调用createRecBoxItem添加到相应位置;如果是两行显示,就计算出每个推荐项所在的行和列,再调用createRecBoxItem添加。

  • 数据处理
    • 使用QJsonArray存储图片路径和文本,通过std::random_shuffle随机打乱顺序后分组显示,这样每次打开看到的推荐内容顺序都不一样。
    • createRecBoxItem方法根据行数和分组索引添加推荐项到上下布局。
// recbox.cpp
void RecBox::createRecBoxItem(const QJsonObject &obj, int row, int col) {RecBoxItem *item = new RecBoxItem(this);item->setItemData(obj["path"].toString(), obj["text"].toString());if (row == 0) {ui->recListUp->addWidget(item, 0, col);} else {ui->recListDown->addWidget(item, 0, col);}
}

createRecBoxItem方法创建一个RecBoxItem对象,调用setItemData方法设置图片路径和文本。然后根据行号判断是添加到上面的布局(recListUp)还是下面的布局(recListDown)。

4. 自定义RecBoxItem

  • 界面组成
    • musicImageBox:用来显示图片和点击按钮,鼠标放上去时会显示小手图标,提示你可以点击。
    • recBoxItemText:显示推荐文本,文本是居中对齐的。
  • 动画效果
// recboxitem.cpp
bool RecBoxItem::eventFilter(QObject *watched, QEvent *event) {if (watched == ui->musicImageBox) {int imgWidth = ui->musicImageBox->width();int imgHeight = ui->musicImageBox->height();if (event->type() == QEvent::Enter) {QPropertyAnimation *anim = new QPropertyAnimation(ui->musicImageBox, "geometry");anim->setDuration(100);anim->setStartValue(QRect(9, 10, imgWidth, imgHeight));anim->setEndValue(QRect(9, 0, imgWidth, imgHeight));anim->start();connect(anim, &QPropertyAnimation::finished, anim, &QObject::deleteLater);} else if (event->type() == QEvent::Leave) {QPropertyAnimation *anim = new QPropertyAnimation(ui->musicImageBox, "geometry");anim->setDuration(150);anim->setStartValue(QRect(9, 0, imgWidth, imgHeight));anim->setEndValue(QRect(9, 10, imgWidth, imgHeight));anim->start();connect(anim, &QPropertyAnimation::finished, anim, &QObject::deleteLater);}return true;}return QObject::eventFilter(watched, event);
}

eventFilter方法是个事件过滤器,用来拦截鼠标进入和离开musicImageBox的事件。当鼠标进入时,创建一个动画,让图片在100毫秒内从下移10px的位置移动到顶部;当鼠标离开时,创建另一个动画,让图片在150毫秒内从顶部移动回下移10px的位置。动画结束后,通过connect函数连接finished信号和deleteLater槽,释放动画对象的资源。

5. RecBox添加RecBoxItem

  • 数据准备
// qqmusic.cpp
QJsonArray QQMusic::randomPiction() {QVector<QString> imgNames;imgNames << "001.png" << "002.png" << ...;std::random_shuffle(imgNames.begin(), imgNames.end());QJsonArray objArray;for (int i = 0; i < imgNames.size(); ++i) {QJsonObject obj;obj.insert("path", ":/images/rec/" + imgNames[i]);obj.insert("text", QString("推荐-%1").arg(i, 3, 10, QChar('0')));objArray.append(obj);}return objArray;
}

randomPiction方法创建一个QVector存储图片名称,然后用std::random_shuffle打乱顺序。接着创建QJsonObject,把图片路径和推荐文本插入到对象中,再把对象添加到QJsonArray里。最后返回这个QJsonArray,这样就得到了随机顺序的推荐数据。

  • 分组逻辑
    • 上行RecBox(1行4列)和下行RecBox(2行4列)根据行数动态分配推荐项到上下布局。也就是说,根据不同的行数要求,把推荐项合理地放到对应的布局里显示。

6. RecBox中btUp和btDown按钮clicked处理

  • 翻页逻辑
// recbox.cpp
void RecBox::onBtUpClicked() {currentIndex = (currentIndex - 1 + groupCount) % groupCount;updateRecBox();
}void RecBox::onBtDownClicked() {currentIndex = (currentIndex + 1) % groupCount;updateRecBox();
}void RecBox::updateRecBox() {// 计算当前组的数据范围int start = currentIndex * 8;int end = qMin(start + 8, data.size());QJsonArray currentData;for (int i = start; i < end; ++i) {currentData.append(data[i]);}initRecBoxUi(currentData, currentIndex < groupCount - 1 ? 2 : 1);
}

onBtUpClicked方法在点击上一页按钮时调用,通过(currentIndex - 1 + groupCount) % groupCount计算新的索引,保证索引不会越界。onBtDownClicked方法在点击下一页按钮时调用,用(currentIndex + 1) % groupCount计算新索引。updateRecBox方法根据新索引计算当前组的数据范围,把这些数据添加到currentData中,然后调用initRecBoxUi方法更新显示内容。如果不是最后一组,就显示两行;如果是最后一组,就根据实际情况显示一行或两行。

  • 性能优化:更新前清除旧元素,避免重复添加,确保界面显示最新分组内容。这样可以提高界面的响应速度,避免出现显示混乱的问题。

7. 核心要点总结

  • 布局设计:采用分层布局和自定义控件组合,构建出推荐页的整体结构。
  • 数据处理:用QJsonArray存储和处理数据,随机打乱和分组显示增加了内容的多样性。
  • 交互体验:通过事件过滤器和QPropertyAnimation实现鼠标悬停动画,提升了用户的交互感受。
  • 性能保障:合理处理翻页逻辑和进行性能优化,保证了界面的流畅性和响应速度。

三、自定义CommonPage

1. CommonPage页面分析

  • 适用场景:适用于“我喜欢”“本地下载”“最近播放”等页面,这些页面布局相同,但显示的数据不同。
  • 界面结构
    • 标题QLabel:显示页面的标题,比如“本地音乐”。
    • musicPlayBox:里面有封面图和“播放全部”按钮。
    • listLabelBox:显示歌曲信息的标题,像名称、歌手、专辑等。
    • pageMusicList:使用QListWidget来显示歌曲列表。

2. CommonPage页面布局

  • 控件配置
    • 标题标签高度是30,封面图标签宽度是150,“播放全部”按钮尺寸是100*30,采用垂直弹簧布局,能自适应空间。
    • 列表标签采用水平布局,歌曲信息列对齐显示,让界面看起来更整齐。
  • 样式设置:按钮悬停时背景色变成#1ECD97,圆角为10px,增强了按钮的美观度和交互性。

3. CommonPage界面设置和显示

  • 初始化方法
// commonpage.cpp
void CommonPage::setCommonPageUI(const QString &title, const QString &image) {ui->pageTittle->setText(title);ui->musicImageLabel->setPixmap(QPixmap(image));ui->musicImageLabel->setScaledContents(true);
}

setCommonPageUI方法用于设置页面的标题和封面图。ui->pageTittle->setText(title);把传入的标题设置给标题标签;ui->musicImageLabel->setPixmap(QPixmap(image));把传入的图片路径对应的图片设置给封面图标签;ui->musicImageLabel->setScaledContents(true);让封面图自动缩放填充,保证图片显示效果。

  • 页面关联:在QQMusic::initUI中设置三个页面的标题和背景图,通过QStackedWidget管理页面切换。QStackedWidget就像一个页面管理器,能方便地在不同页面之间切换。

4. 核心要点总结

  • 复用设计:采用通用布局设计,通过自定义控件实现页面复用,减少了代码的重复编写。
  • 初始化便捷:利用setCommonPageUI方法进行页面初始化,能快速设置标题和封面图。
  • 页面管理:通过QStackedWidget管理页面切换,提高了多页面显示的效率。

四、自定义ListItemBox

1. ListItemBox页面分析

  • 功能:作为QListWidget的列表项,用来显示歌曲信息和收藏按钮。
  • 组件构成
    • musicNameBox:里面有收藏按钮(likeBtn)、歌曲名称、VIP/SQ标签。
    • musicSingerBox:显示歌手名称。
    • albumBox:显示专辑名称。
    • 采用水平弹簧控制布局对齐,让界面元素排列更整齐。

2. ListItemBox页面布局

  • 尺寸:整体尺寸是800*45,采用水平布局,分为三部分,宽度分别是380、200和剩余空间,合理分配空间显示不同信息。
  • 样式设置
    • VIP/SQ标签有边框和颜色区分,能让你快速识别歌曲的特殊属性。收藏按钮无边框,鼠标悬停时背景色变成#EFEFEF,有明显的交互反馈。

3. ListItemBox显示测试

  • 集成到CommonPage
// commonpage.cpp
void CommonPage::setCommonPageUI(const QString &title, const QString &image) {// ...ListItemBox* listItemBox = new ListItemBox(this);QListWidgetItem* listWidgetItem = new QListWidgetItem(ui->pageMusicList);listWidgetItem->setSizeHint(QSize(ui->pageMusicList->width(), 45));ui->pageMusicList->setItemWidget(listWidgetItem, listItemBox);// ...
}

CommonPage::setCommonPageUI方法中,创建一个ListItemBox对象,同时创建一个QListWidgetItem对象。listWidgetItem->setSizeHint(QSize(ui->pageMusicList->width(), 45));设置列表项的大小提示。最后通过ui->pageMusicList->setItemWidget(listWidgetItem, listItemBox);ListItemBox添加到QListWidget中显示。

4. 支持hover效果

// listitembox.cpp
void ListItemBox::enterEvent(QEvent *event) {Q_UNUSED(event);setStyleSheet("background-color:#EFEFEF");
}void ListItemBox::leaveEvent(QEvent *event) {Q_UNUSED(event);setStyleSheet("");
}

enterEvent方法在鼠标进入列表项时触发,把列表项的背景色设置为#EFEFEF。leaveEvent方法在鼠标离开列表项时触发,清除背景色设置,让列表项恢复原来的样子。这样能给用户明显的视觉反馈,知道鼠标当前的位置。

5. 核心要点总结

  • 布局合理:设计合理的界面布局,清晰显示歌曲信息和收藏按钮。
  • 集成方便:通过设置大小提示和添加到QListWidget,能方便地将ListItemBox集成到CommonPage中。
  • 交互增强:重写鼠标事件方法,实现hover效果,提升了用户的交互体验。

五、自定义MusicSlider

1. 功能与设计

  • 替代原生滑杆:自定义了一个水平进度条,由轨道(inLine)和进度条(outLine)组成,替代了原生的滑杆,能更好地满足特定的设计需求。
  • 视觉效果
    • 轨道背景色是#EBEEF5,进度条背景色是#1ECC94,没有边界,看起来更简洁美观。
    • 尺寸是800*20,进度条高度为4px,比例协调。

2. 交互实现

// musicslider.cpp
void MusicSlider::mousePressEvent(QMouseEvent *event) {currentPos = event->pos().x();moveSilder();
}void MusicSlider::mouseMoveEvent(QMouseEvent *event) {if (event->buttons() & Qt::LeftButton) {currentPos = event->pos().x();moveSilder();}
}void MusicSlider::mouseReleaseEvent(QMouseEvent *event) {Q_UNUSED(event);moveSilder();emit setMusicSliderPosition(currentPos * 1.0 / width());
}void MusicSlider::moveSilder() {currentPos = qMax(0, qMin(currentPos, width()));ui->outLine->setGeometry(0, 8, currentPos, 4);
}
  • 鼠标事件mousePressEvent在鼠标按下时记录鼠标相对于控件的x坐标,并调用moveSilder方法更新进度条。mouseMoveEvent在鼠标移动且左键按下时,同样更新坐标并调用moveSildermouseReleaseEvent在鼠标释放时,调用moveSilder更新进度条,然后发射setMusicSliderPosition信号,传递当前进度条的比例。
  • 信号槽:通过发射信号,关联到QQMusic更新播放位置,实现了进度条和音乐播放位置的同步。
  • 进度条更新moveSilder方法把currentPos限制在0到控件宽度范围内,然后根据这个位置更新outLine的几何位置,也就是更新进度条的显示长度。

3. 核心要点总结

  • 视觉优化:自定义水平进度条,优化了视觉效果,让界面更美观。
  • 交互实现:通过重写鼠标事件方法,实现了进度条的拖拽操作,方便用户控制音乐播放进度。
  • 功能交互:利用信号槽机制,将进度信息传递给上层模块,实现了进度条和音乐播放的交互。

六、自定义VolumeTool

1. 控件分析

  • 功能:是一个音量调节弹出窗口,包含静音按钮、滑杆和音量显示,方便用户调节音量。
  • 界面组成
    • silenceBtn:用于切换静音状态,图标会根据静音状态动态变化。
    • sliderBox:是垂直滑杆,里面有小圆球(sliderBtn)和音量比例显示。
    • 倒三角绘制:通过paintEvent手动绘制提示按钮位置,让界面更直观。

2. 界面布局

  • 尺寸:整体尺寸是100*350,采用弹出窗口样式,没有边框,带有阴影,看起来更美观。
  • 样式设置
    • 背景色是#FFFFFF,边框圆角为5px,滑杆轨道是#ECECEC,进度条是#1ECC94,滑块圆角为7px,整体界面风格统一。

3. 界面设置与交互

  • 弹出逻辑
// volumetool.cpp
void VolumeTool::showVolumeTool(const QPoint &pos) {move(pos.x() - width() / 2, pos.y());show();
}

showVolumeTool方法在点击主界面音量按钮时调用,根据传入的位置信息,把窗口移动到按钮下方居中的位置,然后显示窗口。

  • 静音按钮逻辑
// volumetool.cpp
void VolumeTool::onSilenceBtnClicked() {isMuted = !isMuted;ui->silenceBtn->setIcon(isMuted ? QIcon(":/images/silent.png") : QIcon(":/images/volumn.png"));emit setSilence(isMuted);
}

onSilenceBtnClicked方法在点击静音按钮时触发,切换isMuted标志位的状态。如果是静音状态,就把按钮图标设置为静音图标;如果是非静音状态,就设置为音量图标。然后发射setSilence信号,通知QMediaPlayer设置静音或取消静音。

  • 滑杆操作
// volumetool.cpp
bool VolumeTool::eventFilter(QObject *watched, QEvent *event) {if (watched == ui->sliderBox) {if (event->type() == QEvent::MouseMove) {QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);int y = mouseEvent->pos().y();int height = ui->sliderBox->height();volumeRatio = 1 - y * 1.0 / height;updateSlider();emit setMusicVolume(volumeRatio);}return true;}return QObject::eventFilter(watched, event);
}void VolumeTool::updateSlider() {int height = ui->sliderBox->height();int sliderY = (1 - volumeRatio) * height;ui->sliderBtn->move(0, sliderY - ui->sliderBtn->height() / 2);ui->volumeLabel->setText(QString::number(qRound(volumeRatio * 100)) + "%");
}

eventFilter方法是事件过滤器,当鼠标在sliderBox上移动时,计算鼠标位置对应的音量比例volumeRatio,调用updateSlider方法更新滑块位置和音量显示,然后发射setMusicVolume信号,将音量比例传递给播放器更新音量。updateSlider方法根据音量比例计算滑块的位置,移动滑块并更新音量显示。

4. 核心要点总结

  • 界面设计:设计弹出式音量调节窗口,提供了直观的音量调节界面。
  • 静音控制:实现了静音按钮的切换逻辑和图标更新,方便用户控制静音状态。
  • 滑杆交互:通过事件过滤器处理滑杆操作,实时更新音量显示并发送音量信号,实现了音量的灵活调节。

📣 结语

感谢你耐心看完,这里是我送给你(也给我自己)的几句话:

  • 更好的自己,而不是完美的别人。
  • 做你喜欢的事情容易,但做你该做的事,才叫成长。
  • 努力让自己变得切实,而不只是一团混乱的情感。
  • 有时候放弃容易,但坚持一定很酷。
  • 知识不是力量,只有应用知识才是真正的力量。
  • 有两种选择活着:忙着死,或忙着活。坚持住就能突出,坚持不住就会被淘汰。你的野心很大,所以你没资格停下来。
  • 白天向生活投降,夜晚忠于自己。

如果你觉得我写的不错,记得给我点赞,收藏 和 关注哦(。・ω・。)

让我们一起加油,向美好的未来奔去。让我们从一无所知的新手逐渐成为专家。为自己点赞吧!


相关文章:

  • OpenHarmony - 小型系统内核(LiteOS-A)(十),魔法键使用方法,用户态异常信息说明
  • git版本回退 | 远程仓库的回退 (附实战Demo)
  • 从零开始掌握Linux数据流:管道与重定向完全指南
  • 支持Function Call的本地ollama模型对比评测-》开发代理agent
  • 工业排风轴流风机:强劲动力与节能设计的完美融合
  • websheet 之 VUE使用
  • 基于 Netmiko 的网络设备自动化操作
  • 【器件专题1——IGBT第2讲】IGBT 基本工作原理:从结构到特性,一文解析 “电力电子心脏” 的核心机制
  • 人工智能与机器学习:Python从零实现性回归模型
  • react和vue的区别之一
  • 【Mybatis】MyBatisPlus的saveBatch真的是批量插入吗?深度解析与性能优化
  • 全球玻璃纸市场深度洞察:环保浪潮下的材料革命与产业重构(2025-2031)
  • 算法 | 基于SSA-CNN-LSTM(麻雀算法优化卷积长短期记忆神经网络)的股票价格预测(附完整matlab代码,公式,原理,可用于毕业论文设计)
  • 【持续更新】 CDC 跨时钟域处理
  • 解读《数据资产质量评估实施规则》:企业数据资产认证落地的关键指南
  • 数据挖掘技术与应用课程论文——数据挖掘中的聚类分析方法及其应用研究
  • 从原生检索到异构图:Native RAG、GraphRAG 与 NodeRAG 架构全景解析
  • 高效使用DeepSeek对“情境+ 对象 +问题“型课题进行开题!
  • JavaScript学习教程,从入门到精通,Ajax数据交换格式与跨域处理(26)
  • PubMed PDF下载 cloudpmc-viewer-pow逆向
  • 精准滴灌“种企业”,苏南强县常熟新的进阶密码
  • 拉卡拉一季度净利约1亿降超五成,去年净利3.5亿降逾23%
  • 文昌市委原书记龙卫东已任海南省人社厅党组书记
  • 猿辅导武汉公司一员工猝死,死者亲属:他原计划5月2日举行婚礼
  • 岳阳一管道疑似有黑水直排东洞庭湖,生态环境局:已赶往现场核查
  • 肖扬任武钢集团董事长、党委书记