Qt自定义标题栏
效果如下:
代码如下:
// widget.h
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();
protected:bool nativeEvent(const QByteArray&eventType,void *message,long*result) override;
private slots:void on_close();private:void mousePressEvent(QMouseEvent*ev);void mouseMoveEvent(QMouseEvent*ev);QPoint pos;
private:Ui::Widget *ui;int m_BorderWidth =5;
};//2、titlebar
#ifndef CTABTITLEWIDGET_H
#define CTABTITLEWIDGET_H#include <QObject>
#include <QWidget>
#include<QPushButton>class CTabTitleWidget : public QWidget
{Q_OBJECT
public:explicit CTabTitleWidget(QWidget *parent = nullptr);~CTabTitleWidget();void setEmptyWidgetWidth(int w);protected:void paintEvent(QPaintEvent*event);void mousePressEvent(QMouseEvent*ev);void mouseDoubleClickEvent(QMouseEvent*event);signals:void sig_close();void sig_addtab();
private slots:void on_clicked();private:QPushButton* m_pAddBtn = nullptr;QWidget* m_pEmptyWidget = nullptr;QPushButton* m_pUserBtn = nullptr;QPushButton* m_pMinBtn = nullptr;QPushButton* m_pMaxBtn = nullptr;QPushButton* m_pCloseBtn = nullptr;
};#endif // CTABTITLEWIDGET_H#endif // WIDGET_H//3.tabbrowser
#ifndef TABBROWSER_H
#define TABBROWSER_H#include <QObject>
#include <QWidget>
#include <QTabWidget>
#include <QMenu>
#include "ctabtitlewidget.h"
class tabbrowser : public QTabWidget
{Q_OBJECT
public:explicit tabbrowser(QWidget *parent = nullptr);enum TAB_FLAG{NEW,CLOSE,NORMAL,SPECIAL};protected:void resizeEvent(QResizeEvent*ev) override;private:void initTabWidget();void setTabBarFlag(TAB_FLAG);void createTabMenu();private slots:void on_newTab();void on_closeTab(int index);void onMenuShow(const QPoint&pos);void on_closeAllTab();private:CTabTitleWidget*m_pRightWidget = nullptr;QMenu* m_pTabMenu = nullptr;
signals:void sig_close();};#endif // TABBROWSER_H
.cpp
/./1.widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include "tabbrowser.h"
#ifdef Q_OS_WIN
#include <qt_windows.h>
#include <Windows.h>
#include <windowsx.h>
#include <QHBoxLayout>
#include <QMouseEvent>
#endifWidget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);// 设置窗口为无边框setWindowFlag(Qt::FramelessWindowHint);setStyleSheet("background-color:#E3E4E7;");// 创建一个新的 tabbrowser 实例,并将其设置为此窗口的小部件tabbrowser* pTab = new tabbrowser(this);// 创建一个水平布局,并将 tabbrowser 添加到布局中QHBoxLayout* pHLay = new QHBoxLayout(this);pHLay->addWidget(pTab);pHLay->setContentsMargins(6, 6, 6, 6);setLayout(pHLay);// 连接 tabbrowser 的关闭信号到此窗口的 on_close 槽函数connect(pTab, &tabbrowser::sig_close, this, &Widget::on_close);
}Widget::~Widget()
{delete ui;
}// 处理自定义窗口行为的原生事件(例如,调整大小和移动)
bool Widget::nativeEvent(const QByteArray &eventType, void *message, long *result)
{Q_UNUSED(eventType)MSG* param = static_cast<MSG*>(message);switch (param->message){case WM_NCHITTEST:{int nX = GET_X_LPARAM(param->lParam) - this->geometry().x();int nY = GET_Y_LPARAM(param->lParam) - this->geometry().y();// 如果鼠标位于子控件上,则忽略此事件if (childAt(nX, nY) != nullptr)return QWidget::nativeEvent(eventType, message, result);// 当鼠标靠近边框时,进行调整大小操作if ((nX > 0) && (nX < m_BorderWidth))*result = HTLEFT;if ((nX > this->width() - m_BorderWidth) && (nX < this->width()))*result = HTRIGHT;if ((nY > 0) && (nY < m_BorderWidth))*result = HTTOP;if ((nY > this->height() - m_BorderWidth) && (nY < this->height()))*result = HTBOTTOM;if ((nX > 0) && (nX < m_BorderWidth) && (nY > 0) && (nY < m_BorderWidth))*result = HTTOPLEFT;if ((nX > this->width() - m_BorderWidth) && (nX < this->width()) && (nY > 0) && (nY < m_BorderWidth))*result = HTTOPRIGHT;if ((nX > 0) && (nX < m_BorderWidth) && (nY > this->height() - m_BorderWidth) && (nY < this->height()))*result = HTBOTTOMLEFT;if ((nX > this->width() - m_BorderWidth) && (nX < this->width()) && (nY > this->height() - m_BorderWidth) && (nY < this->height()))*result = HTBOTTOMRIGHT;return true;}}return QWidget::nativeEvent(eventType, message, result);
}// 处理关闭信号的槽函数
void Widget::on_close()
{close();
}// 处理鼠标按下事件以移动窗口
void Widget::mousePressEvent(QMouseEvent *ev)
{if (Qt::LeftButton == ev->button()){// 计算鼠标相对于窗口左上角的位置pos = ev->globalPos() - frameGeometry().topLeft();ev->accept();}
}// 处理鼠标移动事件以移动窗口
void Widget::mouseMoveEvent(QMouseEvent *ev)
{if (Qt::LeftButton & ev->buttons()){// 移动窗口到鼠标移动后的位置move(ev->globalPos() - pos);ev->accept();}
}
//2.titlebar
#include “CTabTitleWidget.h”
#include
#include
#include
#include
#ifdef Q_OS_WIN
#include <qt_windows.h>
#pragma comment(lib, “user32.lib”)
#endif
CTabTitleWidget::CTabTitleWidget(QWidget *parent)
: QWidget{parent}
{
setStyleSheet(“background-color:#E3E4E7”);
m_pAddBtn = new QPushButton(this);
m_pAddBtn->setFlat(true);
m_pAddBtn->setFixedSize(32, 32);
m_pAddBtn->setStyleSheet(“background-image:url(:/resources/add.svg)”);
m_pEmptyWidget = new QWidget(this);m_pUserBtn = new QPushButton(this);
m_pUserBtn->setFlat(true);
m_pUserBtn->setFixedSize(32, 32);
m_pUserBtn->setStyleSheet("background-image:url(:/resources/user)");m_pMinBtn = new QPushButton(this);
m_pMinBtn->setFlat(true);
m_pMinBtn->setFixedSize(32, 32);
m_pMinBtn->setStyleSheet("background-image:url(:/resources/min.svg)");m_pMaxBtn = new QPushButton(this);
m_pMaxBtn->setFlat(true);
m_pMaxBtn->setFixedSize(32, 32);
m_pMaxBtn->setStyleSheet("background-image:url(:/resources/max.svg)");m_pCloseBtn = new QPushButton(this);
m_pCloseBtn->setFlat(true);
m_pCloseBtn->setFixedSize(32, 32);
m_pCloseBtn->setStyleSheet("background-image:url(:/resources/close.svg)");QHBoxLayout* pHLay = new QHBoxLayout(this);
pHLay->addWidget(m_pAddBtn);
pHLay->addWidget(m_pEmptyWidget);
this->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding);
pHLay->addWidget(m_pUserBtn);
pHLay->addSpacing(8);
pHLay->addWidget(m_pMinBtn);
pHLay->addWidget(m_pMaxBtn);
pHLay->addWidget(m_pCloseBtn);
pHLay->setContentsMargins(1, 0, 1, 3);
setLayout(pHLay);connect(m_pAddBtn, &QPushButton::clicked, this, &CTabTitleWidget::on_clicked);
connect(m_pMinBtn, &QPushButton::clicked, this, &CTabTitleWidget::on_clicked);
connect(m_pMaxBtn, &QPushButton::clicked, this, &CTabTitleWidget::on_clicked);
connect(m_pCloseBtn, &QPushButton::clicked, this, &CTabTitleWidget::on_clicked);
}
CTabTitleWidget::~CTabTitleWidget()
{
}
void CTabTitleWidget::setEmptyWidgetWidth(int w)
{
m_pEmptyWidget->setMinimumWidth(w);
}
void CTabTitleWidget::paintEvent(QPaintEvent *event)
{
QStyleOption opt;
opt.init(this);
QPainter p(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
QWidget::paintEvent(event);
}
void CTabTitleWidget::mousePressEvent(QMouseEvent ev)
{
if(ReleaseCapture())
{
QWidgetwin = this->window();
if(win->isTopLevel())
{
SendMessage(HWND(win->winId()),WM_SYSCOMMAND,SC_MOVE+HTCAPTION,0);
}
}
ev->ignore();
}
void CTabTitleWidget::mouseDoubleClickEvent(QMouseEvent *event)
{
emit m_pMaxBtn->clicked();
}
void CTabTitleWidget::on_clicked()
{
QPushButtonbtn = qobject_cast<QPushButton>(sender());
QWidget*win = this->window();
if(win->isTopLevel())
{
if (btn == m_pAddBtn)
{
emit sig_addtab();
}
else if (btn == m_pMinBtn)
{
win->showMinimized();
}
else if (btn == m_pMaxBtn)
{
win->isMaximized() ? win->showNormal() : win->showMaximized();
}
else if (btn == m_pCloseBtn)
{
emit sig_close();
}
}
}
//3.tabbrowser
#include “tabbrowser.h”
#include
#include
#include
#include
#include
QString qss0 = “QTabBar::tab{
font: 75 12pt Arial;
text-align:left;
width:184px;
height:32;
background:#FFFFFF;
border:2px solid #FFFFFF;
border-bottom-color:#FFFFFF;
border-top-left-radius:4px;
border-top-right-radius:4px;
padding:2px;
margin-top:0px;
margin-right:1px;
margin-left:1px;
margin-bottom:0px;}
QTabBar::tab:selected{
color:#333333; /文字颜色/
background-color:#FFFFFF;}
QTabBar::tab:!selected{
color:#B2B2B2;
border-color:#FFFFFF;}
QTabBar::scroller{width: 0px;}”;
QString qss1 = "QTabBar::tab{ \
font: 75 12pt Arial; \
text-align:left; \
width:184px; \
height:32; \
background:#FFFFFF; \
border:2px solid #FFFFFF; \
border-bottom-color:#FFFFFF; \
border-top-left-radius:4px; \
border-top-right-radius:4px; \
padding:2px; \
margin-top:0px; \
margin-right:1px; \
margin-left:1px; \
margin-bottom:0px;} \
QTabBar::tab:selected{ \color:#333333; /*文字颜色*/ \background-color:#FFFFFF;} \
QTabBar::tab:!selected{ \color:#B2B2B2; \border-color:#FFFFFF;} \
QTabBar::scroller{width: 36px;}";
- tabbrowser::tabbrowser(QWidget *parent)
- QTabWidget{parent}
{
this->addTab(new QWidget,u8"稻壳");
this->setUsesScrollButtons(true);//滚动鼠标可切换tab
this->setTabsClosable(true); //显示tab右侧的关闭按钮
this->setMovable(true);//设置可移动位置
initTabWidget();
setTabBarFlag(NORMAL);this->setStyleSheet(qss0);connect(this, &QTabWidget::tabCloseRequested,this, &tabbrowser::on_closeTab);
}
void tabbrowser::resizeEvent(QResizeEvent *ev)
{
setTabBarFlag(NORMAL);
QTabWidget::resizeEvent(ev);
}
void tabbrowser::initTabWidget()
{
this->setContextMenuPolicy(Qt::CustomContextMenu);
connect(this,&QTabWidget::customContextMenuRequested,this,&tabbrowser::onMenuShow);
createTabMenu();
m_pRightWidget = new CTabTitleWidget(this);this->setCornerWidget(m_pRightWidget, Qt::TopRightCorner);
connect(m_pRightWidget, &CTabTitleWidget::sig_addtab, this, &tabbrowser::on_newTab);
connect(m_pRightWidget, &CTabTitleWidget::sig_close, this, &tabbrowser::sig_close);
}
void tabbrowser::setTabBarFlag(TAB_FLAG flag)
{
int w = this->width();
int tabsWidth = 0; //所有tab的总宽度
int tabsHeight = tabBar()->height();
int tabs = this->count();if (flag == NEW || flag == NORMAL)
{for (int i = 0; i < tabs; ++i){tabsWidth += tabBar()->tabRect(i).width();}
}
else
{for (int i = 0;i < tabs - 1;++i){tabsWidth += tabBar()->tabRect(i).width();}
}if (w > tabsWidth)
{m_pRightWidget->setEmptyWidgetWidth(w - tabsWidth - 32 * 5 - 15);this->setStyleSheet(qss0);
}
else
{//当所有tab的宽度大于整个tabWidget的宽时m_pRightWidget->setEmptyWidgetWidth(150);this->setStyleSheet(qss1);
}
}
void tabbrowser::createTabMenu()
{
m_pTabMenu = new QMenu(this);
QAction* pAcSave = new QAction(QIcon(":/resources/save.png"), u8"保存", m_pTabMenu);
m_pTabMenu->addAction(pAcSave);connect(pAcSave, &QAction::triggered, [=] {QMessageBox::information(this, u8"提示", u8"你点击了 保存");});QAction* pAcSaveAs = new QAction(QString(u8"另存为"), m_pTabMenu);
m_pTabMenu->addAction(pAcSaveAs);m_pTabMenu->addSeparator();QAction* pAcShareDoc = new QAction(QIcon(":/resources/share.png"), QString(u8"分享文档"), m_pTabMenu);
m_pTabMenu->addAction(pAcShareDoc);QAction* pAcSendToDevice = new QAction(QString(u8"发送到设备"), m_pTabMenu);
m_pTabMenu->addAction(pAcSendToDevice);m_pTabMenu->addSeparator();QAction* pAcNewName = new QAction(QString(u8"重命名"), m_pTabMenu);
m_pTabMenu->addAction(pAcNewName);QAction* pAcSaveToWPSCloud = new QAction(QString(u8"保存到WPS云文档"), m_pTabMenu);
m_pTabMenu->addAction(pAcSaveToWPSCloud);QAction* pAcCloseAll = new QAction(QString(u8"关闭所有文件"), m_pTabMenu);
m_pTabMenu->addAction(pAcCloseAll);
connect(pAcCloseAll, &QAction::triggered, this, &tabbrowser::on_closeAllTab);
}
void tabbrowser::on_newTab()
{
int nCount = count();
QString title = QString::number(nCount);
title = “Page” + title;
// 这里写的有问题,应该是 insertTab
this->addTab(new QWidget, title);if (!tabsClosable())
{setTabsClosable(true);
}setTabBarFlag(NEW);
}
void tabbrowser::on_closeTab(int index)
{
widget(index)->deleteLater();
setTabBarFlag(CLOSE);
//当只剩下1个tab时
if (count() == 1)
{setTabsClosable(false);setTabBarFlag(SPECIAL);
}
}
void tabbrowser::onMenuShow(const QPoint &pos)
{
int index = this->tabBar()->tabAt(pos);
#ifdef _DEBUG
qDebug() << u8"当前tab为:" << QString::number(index);
this->setCurrentIndex(index);
#endif
if (index != -1)
{m_pTabMenu->exec(QCursor::pos());
}
}
void tabbrowser::on_closeAllTab()
{
}
相关文章:

Qt自定义标题栏
效果如下: 代码如下: // widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget>QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass Widget : public QWidget {Q_OBJECTpublic:Widget(QWidget *parent nullptr…...
java如何向数组中插入元素
java的数组是不可改变的,因此如果要向数组中插入新的元素,需要新建一个数组,新的数组元素个数减去老数组元素个数的差大于等于要插入新的元素数量。 假如说要插入一个数组元素,需要把新元素插入到中间,把新的数组分为…...

4、PHP的xml注入漏洞(xxe)
青少年ctf:PHP的XXE 1、打开网页是一个PHP版本页面 2、CTRLf搜索xml,发现2.8.0版本,含有xml漏洞 3、bp抓包 4、使用代码出发bug GET /simplexml_load_string.php HTTP/1.1 补充: <?xml version"1.0" encoding&quo…...

设计模式-解释器模式
作者持续关注 WPS二次开发专题系列,持续为大家带来更多有价值的WPS开发技术细节,如果能够帮助到您,请帮忙来个一键三连,更多问题请联系我(QQ:250325397) 定义 解释器模式(Interpreter Pattern&…...

NDIS驱动程序堆栈
NDIS 6.0 引入了暂停和重启驱动程序堆栈的功能。 若要支持 NDIS 6.0 提供的堆栈管理功能,必须重写旧版驱动程序。 NDIS 6.0 还引入了 NDIS Filter驱动程序。 Filter驱动程序可以监视和修改协议驱动程序与微型端口驱动程序之间的交互。 与 NDIS 5 相比,F…...
大数据开发面试题【数仓篇】
197、数据仓库和传统数据库区别 由于历史数据使用频率过低,导致数据堆积,查询性能下降;用于查询分析,涉及大量的历史数据,数据仓库中的数据一般来日志文件和事务 数据库是跟业务挂钩的,数据库不可能装下一…...

Leetcode刷题笔记5
76. 最小覆盖子串 76. 最小覆盖子串 - 力扣(LeetCode) 解法一: 暴力枚举 哈希表 先定义left和right,可以在随机位置 枚举一个位置向后找,找到一个位置之后,发现这段区间是一个最小的区间之后,…...
【Qt】Qt中的信号槽
一、信号和槽概述 信号槽是Qt矿建引以为豪的机制之一。 所谓信号槽,实际上就是观察者模式(发布——订阅模式)。当某个事件发生之后,比如,按钮检测到自己被点击了一下,它就会发出一个信号。这种发出的信号是…...
VsCode个人插件
Auto Rename Tag > 同时修改标签 Rainbow Brackets > 不同层级不同括号颜色 Dracula Official > 个人比较喜欢的一款主题 Error Lens > 错误信息显示 ES7REACT/Redux/React-Native>react开发插件 ESLINT Indenticator>方便看结构 Prettier Formatter …...

Docker环境安装并使用Elasticsearch
1、拉取es docker pull elasticsearch:7.10.12、查看镜像 docker images3、启动es docker run -d --name esearch -p 9200:9200 -p 9300:9300 elasticsearch:7.10.14、如果启动ES时出现一下问题 Unable to find image docker.elastic.co/elasticsearch/elasticsearch:7.10.…...

中心渗透Ⅱ
cs与msf权限传递以及mimikatz抓取win2012明文密码 使用Cobalt Strike抓取win2012明文密码,将会话传递到Metasploit Framework上 1.cs生成木马并使目标服务器中马 建立监听生成木马 2.抓取目标主机的明文密码 通过修改注册表来让Wdigest Auth保存明文口令 shell …...

【webrtc】RtpToNtpEstimator:最小二乘法、ntp估计及c++实例
上一篇: 【webrtc】RtpToNtpEstimator:将 RTP 时间戳映射到 NTP 时间 分析了最小二乘法的实现及对rtp到ntp的映射计算的调用流程 基于最小二乘法进行估计 RtpToNtpEstimator::Estimate G:\CDN\rtcCli\m98\src\system_wrappers\source\rtp_to_ntp_estimator.cc RtpToNtpEstima…...

【DevOps】Elasticsearch在Ubuntu 20.04上的安装与配置:详细指南
目录 一、ES 简介 1、核心概念 2、工作原理 3、 优势 二、ES 在 Ubuntu 20.04 上的安装 1、安装 Java 2、下载 ES 安装包 3、创建 ES 用户 4 、解压安装包 5、 配置 ES 6、 启动 ES 7、验证安装 三、ES 常用命令 1、创建索引 2、 插入文档 3、查询文档 四、ES…...

windows内存管理
一 windows系统的内存管理涉及哪些 1.1 虚拟内存管理机制 windows操作系统使用虚拟内存技术,将磁盘文件,通过映射对象(存储在物理内存)关联,映射到虚拟内存作为文件试图。即用户操作"虚拟内存中File View Objec…...

c++ 将指针转换为 void* 后,转换为怎么判断原指针类型?
当将指针转换为void后,擦除了指针所指向对象的类型信息,因此无法通过void指针来判断原始指针的类型。我这里有一套编程入门教程,不仅包含了详细的视频讲解,项目实战。如果你渴望学习编程,不妨点个关注,给个…...

Swift 属性
属性 一、存储属性1、常量结构体实例的存储属性2、延时加载存储属性3、存储属性和实例变量 二、计算属性1、简化 Setter 声明2、简化 Getter 声明3、只读计算属性 三、属性观察器四、属性包装器1、设置被包装属性的初始值2、从属性包装器中呈现一个值 五、全局变量和局部变量六…...

基于maxkey接入jeecgboot并实现账户同步
1. 注册应用 1.1 在统一认证中心注册第三方应用 1.1.1 填写应用名和登录地址 1.1.2 填写认证地址授权方式和作用域 1.1.3 选择权限范围并提交 1.2 配置访问权限 1.2.1 指定用户组 1.1.2 选择注册的应用 1.1.3 在单点登录认证页面查看添加的应用 1.3 同步一个第三方应用的账号…...

kafka Kerberos集群环境部署验证
背景 公司需要对kafka环境进行安全验证,目前考虑到的方案有Kerberos和SSL和SASL_SSL,最终考虑到安全和功能的丰富度,我们最终选择了SASL_SSL方案。处于知识积累的角度,记录一下kafka keberos安装部署的步骤。 机器规划 目前测试环境公搭建了三台kafka主机服务,现在将详细…...

[C++]debug介绍+debug时如何查看指针指向内存处的值
一、简介 预备工具和知识:使用使用VSCode使用Debug。 本文简介:本文将简要介绍debug中Continue,Step Over,Step Into和Restart的功能。并介绍如何在debug时查看动态内存地址(指针)的值; 二、D…...
AI学习指南数学工具篇-凸优化在支持逻辑回归中的应用
AI学习指南数学工具篇-凸优化在支持逻辑回归中的应用 一、引言 在人工智能领域,逻辑回归是一种常见的分类算法,它通过学习样本数据的特征和标签之间的关系,来进行分类预测。而在逻辑回归算法中,凸优化是一种重要的数学工具&…...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战
前言 现在我们有个如下的需求,设计一个邮件发奖的小系统, 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其…...
R语言AI模型部署方案:精准离线运行详解
R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...

涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战
“🤖手搓TuyaAI语音指令 😍秒变表情包大师,让萌系Otto机器人🔥玩出智能新花样!开整!” 🤖 Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制(TuyaAI…...
大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计
随着大语言模型(LLM)参数规模的增长,推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长,而KV缓存的内存消耗可能高达数十GB(例如Llama2-7B处理100K token时需50GB内存&a…...
解决:Android studio 编译后报错\app\src\main\cpp\CMakeLists.txt‘ to exist
现象: android studio报错: [CXX1409] D:\GitLab\xxxxx\app.cxx\Debug\3f3w4y1i\arm64-v8a\android_gradle_build.json : expected buildFiles file ‘D:\GitLab\xxxxx\app\src\main\cpp\CMakeLists.txt’ to exist 解决: 不要动CMakeLists.…...
提升移动端网页调试效率:WebDebugX 与常见工具组合实践
在日常移动端开发中,网页调试始终是一个高频但又极具挑战的环节。尤其在面对 iOS 与 Android 的混合技术栈、各种设备差异化行为时,开发者迫切需要一套高效、可靠且跨平台的调试方案。过去,我们或多或少使用过 Chrome DevTools、Remote Debug…...

Linux部署私有文件管理系统MinIO
最近需要用到一个文件管理服务,但是又不想花钱,所以就想着自己搭建一个,刚好我们用的一个开源框架已经集成了MinIO,所以就选了这个 我这边对文件服务性能要求不是太高,单机版就可以 安装非常简单,几个命令就…...

Linux中《基础IO》详细介绍
目录 理解"文件"狭义理解广义理解文件操作的归类认知系统角度文件类别 回顾C文件接口打开文件写文件读文件稍作修改,实现简单cat命令 输出信息到显示器,你有哪些方法stdin & stdout & stderr打开文件的方式 系统⽂件I/O⼀种传递标志位…...
上位机开发过程中的设计模式体会(1):工厂方法模式、单例模式和生成器模式
简介 在我的 QT/C 开发工作中,合理运用设计模式极大地提高了代码的可维护性和可扩展性。本文将分享我在实际项目中应用的三种创造型模式:工厂方法模式、单例模式和生成器模式。 1. 工厂模式 (Factory Pattern) 应用场景 在我的 QT 项目中曾经有一个需…...
鸿蒙(HarmonyOS5)实现跳一跳小游戏
下面我将介绍如何使用鸿蒙的ArkUI框架,实现一个简单的跳一跳小游戏。 1. 项目结构 src/main/ets/ ├── MainAbility │ ├── pages │ │ ├── Index.ets // 主页面 │ │ └── GamePage.ets // 游戏页面 │ └── model │ …...