Qt多线程编程学习

1. 项目概述

本项目展示了Qt中多线程编程的基本用法,通过继承QThread类创建自定义线程,并演示了线程的启动、执行和销毁过程。项目包含一个简单的用户界面,用户可以通过按钮控制线程的启动和结束。

1.1 项目结构

项目包含以下文件:

  • 51.pro:项目配置文件
  • main.cpp:程序入口
  • widget.h:主窗口类定义,包含自定义线程类定义
  • widget.cpp:主窗口类实现
  • widget.ui:主窗口界面设计文件

1.2 功能特点

  • 继承QThread类创建自定义线程
  • 重写run()方法定义线程执行逻辑
  • 使用deleteLater()实现线程的自动销毁
  • 通过按钮控制线程的启动和结束
  • 使用qDebug()输出线程状态信息

2. 代码实现

2.2 主函数(main.cpp)

#include "widget.h"#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);  // 创建应用程序对象Widget w;                    // 创建主窗口对象w.show();                    // 显示主窗口return a.exec();             // 进入应用程序事件循环
}

2.3 Widget类定义(widget.h)

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QThread>
#include <QDebug>class MyThread;  // 前向声明QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE// 主窗口类
class Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);  // 构造函数~Widget();                          // 析构函数private slots:void on_pushButton_clicked();       // 开启线程按钮槽函数void on_pushButton_2_clicked();     // 结束线程按钮槽函数private:Ui::Widget *ui;                     // UI对象指针MyThread *myThread;                 // 线程对象指针
};// 自定义线程类
class MyThread : public QThread
{Q_OBJECTpublic:// 构造函数MyThread(QWidget *parent = nullptr) {Q_UNUSED(parent)  // 标记参数未使用,避免编译器警告}// 析构函数~MyThread() {qDebug() << "线程销毁" << endl;}// 重写run()方法,定义线程执行逻辑// 注意:只有这个run()方法在新的线程里面执行void run() override {qDebug() << "线程开启" << endl;sleep(5);  // 模拟耗时操作,睡眠5秒qDebug() << "线程结束" << endl;deleteLater();  // 线程执行完毕后自动销毁对象}
};#endif // WIDGET_H

2.4 Widget类实现(widget.cpp)

#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);  // 设置UI// 一个应用程序至少要一个进程,QProcess// 一个进程至少会有一个线程,QThread// 注释掉的代码:在构造函数中创建线程对象// myThread = new MyThread(this);
}Widget::~Widget()
{delete ui;  // 释放UI资源
}// 开启线程按钮点击事件处理函数
void Widget::on_pushButton_clicked()
{// system("sleep 5");           // 系统调用,会阻塞主线程// system("ping 192.168.1.1");  // 系统调用,会阻塞主线程// 启动线程的两种方式:// 方式1:使用成员变量(注释掉的代码)// myThread->start();// 方式2:动态创建线程对象(推荐)MyThread *testThread = new MyThread(this);testThread->start();  // 启动线程,会调用run()方法
}// 结束线程按钮点击事件处理函数
void Widget::on_pushButton_2_clicked()
{// 终止线程(注释掉的代码)// 注意:terminate()方法强制终止线程,可能导致资源泄漏// 不推荐使用,应该让线程自然结束// if (!myThread->isFinished())//     myThread->terminate();
}

2.5 主窗口界面(widget.ui)

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0"><class>Widget</class><widget class="QWidget" name="Widget"><property name="geometry"><rect><x>0</x><y>0</y><width>800</width><height>480</height></rect></property><property name="windowTitle"><string>Widget</string></property><!-- 开启线程按钮 --><widget class="QPushButton" name="pushButton"><property name="geometry"><rect><x>70</x><y>160</y><width>171</width><height>121</height></rect></property><property name="styleSheet"><string notr="true">QPushButton { background-color: rgb(239, 41, 41); border: none}QPushButton:hover { background-color: rgb(114, 159, 207);}</string></property><property name="text"><string>开启线程</string></property></widget><!-- 结束线程按钮 --><widget class="QPushButton" name="pushButton_2"><property name="geometry"><rect><x>420</x><y>160</y><width>171</width><height>121</height></rect></property><property name="styleSheet"><string notr="true">QPushButton { background-color: rgb(239, 41, 41); border: none}QPushButton:hover { background-color: rgb(114, 159, 207);}</string></property><property name="text"><string>结束线程</string></property></widget></widget><resources/><connections/>
</ui>

3. Qt多线程编程详解

3.1 多线程基础概念

在Qt中,多线程编程主要涉及以下概念:

  • 进程(Process):一个应用程序至少有一个进程
  • 线程(Thread):一个进程至少有一个线程(主线程)
  • 主线程:负责UI更新和事件处理的线程
  • 工作线程:执行耗时操作的后台线程

3.2 QThread类详解

QThread是Qt中用于创建和管理线程的核心类。主要特点包括:

  • 继承自QObject,支持信号槽机制
  • 提供了线程的生命周期管理
  • 通过重写run()方法定义线程执行逻辑
  • 支持线程间通信
3.2.1 QThread的主要方法
class QThread : public QObject
{
public:// 启动线程void start(Priority priority = InheritPriority);// 等待线程结束bool wait(unsigned long time = ULONG_MAX);// 强制终止线程(不推荐)void terminate();// 退出线程void quit();// 检查线程是否正在运行bool isRunning() const;// 检查线程是否已完成bool isFinished() const;// 获取线程IDQt::HANDLE currentThreadId();// 线程睡眠(静态方法)static void sleep(unsigned long secs);static void msleep(unsigned long msecs);static void usleep(unsigned long usecs);protected:// 线程执行函数,需要重写virtual void run();signals:// 线程开始信号void started();// 线程完成信号void finished();
};
3.2.2 线程优先级

QThread支持设置线程优先级:

enum Priority {IdlePriority,         // 空闲优先级LowestPriority,       // 最低优先级LowPriority,          // 低优先级NormalPriority,       // 正常优先级(默认)HighPriority,         // 高优先级HighestPriority,      // 最高优先级TimeCriticalPriority, // 时间关键优先级InheritPriority       // 继承优先级
};// 使用示例
thread->start(QThread::HighPriority);

3.3 线程创建方式

3.3.1 继承QThread类(本项目使用的方式)
class MyThread : public QThread
{Q_OBJECTprotected:void run() override {// 线程执行逻辑// 这里的代码在新线程中执行}
};// 使用
MyThread *thread = new MyThread;
thread->start();
3.3.2 使用QObject + moveToThread(推荐方式)
class Worker : public QObject
{Q_OBJECTpublic slots:void doWork() {// 工作逻辑emit resultReady(result);}signals:void resultReady(const QString &result);
};// 使用
QThread *thread = new QThread;
Worker *worker = new Worker;worker->moveToThread(thread);connect(thread, &QThread::started, worker, &Worker::doWork);
connect(worker, &Worker::resultReady, this, &MainWindow::handleResults);
connect(worker, &Worker::resultReady, worker, &QObject::deleteLater);
connect(worker, &Worker::resultReady, thread, &QThread::quit);
connect(thread, &QThread::finished, thread, &QObject::deleteLater);thread->start();
3.3.3 使用QtConcurrent(简单任务)
#include <QtConcurrent>
#include <QFuture>// 执行简单函数
QFuture<void> future = QtConcurrent::run([](){// 后台执行的代码
});// 执行有返回值的函数
QFuture<int> future = QtConcurrent::run([](){ return 42; 
});
int result = future.result();

3.4 线程同步与通信

3.4.1 信号槽机制
class WorkerThread : public QThread
{Q_OBJECTprotected:void run() override {for (int i = 0; i < 100; ++i) {emit progressChanged(i);msleep(100);}emit workFinished();}signals:void progressChanged(int value);void workFinished();
};// 在主线程中连接信号槽
connect(workerThread, &WorkerThread::progressChanged, progressBar, &QProgressBar::setValue);
connect(workerThread, &WorkerThread::workFinished, this, &MainWindow::onWorkFinished);
3.4.2 互斥锁(QMutex)
#include <QMutex>
#include <QMutexLocker>class ThreadSafeCounter
{
public:void increment() {QMutexLocker locker(&mutex);  // 自动加锁和解锁++count;}int value() const {QMutexLocker locker(&mutex);return count;}private:mutable QMutex mutex;int count = 0;
};
3.4.3 等待条件(QWaitCondition)
#include <QWaitCondition>
#include <QMutex>QMutex mutex;
QWaitCondition condition;
bool dataReady = false;// 生产者线程
void producer() {QMutexLocker locker(&mutex);// 生产数据dataReady = true;condition.wakeOne();  // 唤醒等待的线程
}// 消费者线程
void consumer() {QMutexLocker locker(&mutex);while (!dataReady) {condition.wait(&mutex);  // 等待条件满足}// 消费数据
}
3.4.4 读写锁(QReadWriteLock)
#include <QReadWriteLock>
#include <QReadLocker>
#include <QWriteLocker>class ThreadSafeMap
{
public:QString value(const QString &key) const {QReadLocker locker(&lock);  // 读锁return map.value(key);}void setValue(const QString &key, const QString &value) {QWriteLocker locker(&lock);  // 写锁map[key] = value;}private:mutable QReadWriteLock lock;QMap<QString, QString> map;
};

4. 实现步骤详解

4.1 创建自定义线程类

  1. 继承QThread类:
class MyThread : public QThread
{Q_OBJECT  // 必须包含,支持信号槽public:MyThread(QObject *parent = nullptr) : QThread(parent) {}protected:void run() override {// 线程执行逻辑}
};
  1. 重写run()方法:
void MyThread::run()
{// 这里的代码在新线程中执行// 可以执行耗时操作,不会阻塞主线程qDebug() << "线程开始执行";// 模拟耗时操作for (int i = 0; i < 10; ++i) {sleep(1);  // 睡眠1秒qDebug() << "执行进度:" << (i + 1) * 10 << "%";}qDebug() << "线程执行完毕";
}

4.2 启动和管理线程

  1. 创建线程对象:
MyThread *thread = new MyThread(this);
  1. 启动线程:
thread->start();  // 调用start()会自动调用run()方法
  1. 等待线程结束:
thread->wait();  // 阻塞等待线程结束
  1. 检查线程状态:
if (thread->isRunning()) {qDebug() << "线程正在运行";
}if (thread->isFinished()) {qDebug() << "线程已完成";
}

4.3 线程生命周期管理

  1. 自动销毁:
void MyThread::run()
{// 执行逻辑deleteLater();  // 线程结束后自动销毁
}
  1. 手动销毁:
connect(thread, &QThread::finished, thread, &QObject::deleteLater);
  1. 优雅退出:
class MyThread : public QThread
{
private:bool m_stop = false;public:void stop() { m_stop = true; }protected:void run() override {while (!m_stop) {// 执行工作if (m_stop) break;msleep(100);}}
};

5. 常用功能示例

5.1 带进度更新的线程

class ProgressThread : public QThread
{Q_OBJECTprotected:void run() override {for (int i = 0; i <= 100; ++i) {emit progressChanged(i);msleep(50);  // 模拟工作}emit workCompleted();}signals:void progressChanged(int value);void workCompleted();
};// 使用
ProgressThread *thread = new ProgressThread;
connect(thread, &ProgressThread::progressChanged, progressBar, &QProgressBar::setValue);
connect(thread, &ProgressThread::workCompleted, this, &MainWindow::onWorkCompleted);
thread->start();

5.2 文件处理线程

class FileProcessThread : public QThread
{Q_OBJECTpublic:FileProcessThread(const QString &filePath) : m_filePath(filePath) {}protected:void run() override {QFile file(m_filePath);if (!file.open(QIODevice::ReadOnly)) {emit error("无法打开文件");return;}QTextStream stream(&file);QString content = stream.readAll();// 处理文件内容QString processedContent = processContent(content);emit contentProcessed(processedContent);}private:QString m_filePath;QString processContent(const QString &content) {// 模拟内容处理return content.toUpper();}signals:void contentProcessed(const QString &content);void error(const QString &message);
};

5.3 网络请求线程

class NetworkThread : public QThread
{Q_OBJECTpublic:NetworkThread(const QString &url) : m_url(url) {}protected:void run() override {QNetworkAccessManager manager;QNetworkRequest request(m_url);QNetworkReply *reply = manager.get(request);QEventLoop loop;connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);loop.exec();if (reply->error() == QNetworkReply::NoError) {QByteArray data = reply->readAll();emit dataReceived(data);} else {emit error(reply->errorString());}reply->deleteLater();}private:QString m_url;signals:void dataReceived(const QByteArray &data);void error(const QString &message);
};

5.4 定时器线程

class TimerThread : public QThread
{Q_OBJECTpublic:TimerThread(int interval) : m_interval(interval), m_stop(false) {}void stop() { m_stop = true; }protected:void run() override {while (!m_stop) {emit timeout();msleep(m_interval);}}private:int m_interval;bool m_stop;signals:void timeout();
};

6. 常见问题与解决方案

6.1 UI更新问题

问题:在工作线程中直接更新UI控件导致程序崩溃。

原因:Qt的UI控件只能在主线程中更新。

解决方案:使用信号槽机制在主线程中更新UI。

// 错误做法(在工作线程中)
void WorkerThread::run()
{label->setText("更新文本");  // 错误!会导致崩溃
}// 正确做法
void WorkerThread::run()
{emit textChanged("更新文本");  // 发送信号
}// 在主线程中连接信号槽
connect(workerThread, &WorkerThread::textChanged, label, &QLabel::setText);

6.2 内存泄漏问题

问题:线程对象没有正确释放导致内存泄漏。

解决方案

// 方案1:使用deleteLater()
connect(thread, &QThread::finished, thread, &QObject::deleteLater);// 方案2:在run()方法中调用deleteLater()
void MyThread::run()
{// 执行逻辑deleteLater();
}// 方案3:手动管理
if (thread->isFinished()) {delete thread;thread = nullptr;
}

6.3 线程阻塞问题

问题:主线程等待工作线程完成导致界面卡死。

解决方案:避免在主线程中使用wait()方法。

// 错误做法
void MainWindow::startWork()
{thread->start();thread->wait();  // 阻塞主线程,界面卡死
}// 正确做法
void MainWindow::startWork()
{connect(thread, &QThread::finished, this, &MainWindow::onWorkFinished);thread->start();
}void MainWindow::onWorkFinished()
{// 处理工作完成后的逻辑
}

6.4 线程安全问题

问题:多个线程同时访问共享数据导致数据竞争。

解决方案:使用互斥锁保护共享数据。

class ThreadSafeClass
{
public:void setValue(int value) {QMutexLocker locker(&mutex);m_value = value;}int getValue() const {QMutexLocker locker(&mutex);return m_value;}private:mutable QMutex mutex;int m_value = 0;
};

6.5 线程终止问题

问题:使用terminate()强制终止线程可能导致资源泄漏。

解决方案:使用标志位实现优雅退出。

class GracefulThread : public QThread
{
public:void requestStop() { m_stopRequested = true; }protected:void run() override {while (!m_stopRequested) {// 执行工作if (m_stopRequested) break;msleep(100);}}private:volatile bool m_stopRequested = false;
};

7. 高级应用

7.1 线程池

#include <QThreadPool>
#include <QRunnable>class Task : public QRunnable
{
public:void run() override {// 执行任务qDebug() << "任务执行中...";}
};// 使用线程池
QThreadPool *pool = QThreadPool::globalInstance();
pool->start(new Task);

7.2 生产者-消费者模式

#include <QQueue>
#include <QMutex>
#include <QWaitCondition>template<typename T>
class ThreadSafeQueue
{
public:void enqueue(const T &item) {QMutexLocker locker(&mutex);queue.enqueue(item);condition.wakeOne();}T dequeue() {QMutexLocker locker(&mutex);while (queue.isEmpty()) {condition.wait(&mutex);}return queue.dequeue();}private:QQueue<T> queue;QMutex mutex;QWaitCondition condition;
};class Producer : public QThread
{
protected:void run() override {for (int i = 0; i < 100; ++i) {queue.enqueue(i);msleep(10);}}private:ThreadSafeQueue<int> &queue;
};class Consumer : public QThread
{
protected:void run() override {while (true) {int item = queue.dequeue();qDebug() << "消费:" << item;}}private:ThreadSafeQueue<int> &queue;
};

7.3 异步任务管理器

class TaskManager : public QObject
{Q_OBJECTpublic:void addTask(QRunnable *task) {QThreadPool::globalInstance()->start(task);}void waitForAllTasks() {QThreadPool::globalInstance()->waitForDone();}int activeThreadCount() const {return QThreadPool::globalInstance()->activeThreadCount();}void setMaxThreadCount(int count) {QThreadPool::globalInstance()->setMaxThreadCount(count);}
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/95657.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/95657.shtml
英文地址,请注明出处:http://en.pswp.cn/pingmian/95657.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

加密货币武器化:恶意npm包利用以太坊智能合约实现隐蔽通信

ReversingLabs研究人员发现两个恶意npm包利用以太坊&#xff08;Ethereum&#xff09;智能合约隐藏并传播恶意软件。这两个名为colortoolsv2和mimelib2的软件包于2025年7月被识别&#xff0c;展现了开源安全攻防战中的新战术。恶意软件包伪装成实用工具攻击活动始于7月7日发布的…

Spring Boot 全局字段处理最佳实践

在日常开发中&#xff0c;我们总会遇到一些琐碎但又无处不在的字段处理需求&#xff1a;• 请求处理: 用户提交的表单&#xff0c;字符串前后带了多余的空格&#xff0c;需要手动 trim()。• 响应处理: 返回给前端的 BigDecimal 金额&#xff0c;因为精度问题导致JS处理出错&am…

三坐标测量机在汽车制造行业中的应用

在汽车制造业中&#xff0c;零部件精度决定着整车性能。从发动机活塞的微米级公差&#xff0c;到车身焊接的毫米级间隙&#xff0c;汽车制造“差之毫厘&#xff0c;谬以千里” &#xff0c;任何细微偏差都可能引发连锁反应&#xff1a;发动机抖动、异响、油耗飙升&#xff0c;车…

机床夹具设计 +选型

机床夹具设计—第2组&#xff08;钻床夹具&#xff09;仿真组装视频_哔哩哔哩_bilibili 夹具-商品搜索-怡合达一站式采购平台 米思米FA标准品电子目录new 可能要吧这些定位块单独用yolo训练一边才能搞识别分析 3长条一短销定位&#xff0c;黄色的用来夹紧 一个面加一短轴一棱…

表格识别技术:通过计算机视觉和OCR,实现非结构化表格向结构化数据的转换,推动数字化转型。

在日常工作和生活中&#xff0c;我们无处不在与表格打交道。从财务报表、发票收据&#xff0c;到科研论文中的数据表、医疗报告&#xff0c;表格以其清晰、结构化的方式&#xff0c;承载着大量关键信息。然而&#xff0c;当这些表格以纸质或图片等非结构化形式存在时&#xff0…

Go基础(②Viper)

Viper 读取配置创建一个配置文件 config.yamlserver:port: 8080timeout: 30 # 超时时间&#xff08;秒&#xff09; database:host: "localhost"user: "root"password: "123456"name: "mydb"然后用 Viper 读取这个配置&#xff0c;代…

kafka Partition(分区)详解

一、什么是 PartitionPartition&#xff08;分区&#xff09; 是 Kafka Topic&#xff08;主题&#xff09; 的最小并行单位。一个 Topic 可以包含多个 Partition&#xff0c;每个 Partition 底层对应一个有序、不可变的消息队列&#xff0c;消息只会顺序追加。Partition 内部消…

中创中间件适配HGDB

文章目录环境文档用途详细信息环境 系统平台&#xff1a;Microsoft Windows (64-bit) 10 版本&#xff1a;5.6.5 文档用途 本文章主要介绍中创中间件简单适配HGDB。 详细信息 一、数据源配置 1.数据库准备 &#xff08;1&#xff09;安装HGDB并创建一个名为myhgdb的数据…

服务器内存和普通计算机内存在技术方面有什么区别?

服务器内存和普通计算机内存在技术上的区别&#xff0c;主要体现在为满足不同工作场景和要求而采用的设计和特性上。下面这个表格汇总了它们的主要技术差异&#xff0c;方便你快速了解&#xff1a; ​技术特性​​服务器内存​​普通计算机内存​​错误校验 (ECC)​​支持ECC(…

哪款AI生成PPT工具对职场新人最友好?操作门槛最低的是哪个?

一句话生成专业PPT&#xff0c;职场新人也能轻松做出高质量演示文稿现代职场节奏快&#xff0c;PPT制作已成为必备技能。然而&#xff0c;职场新人常面临两大挑战&#xff1a;缺乏设计经验&#xff0c;以及需要在有限时间内完成高质量演示。传统PPT制作耗时费力&#xff0c;需梳…

1.注解的力量:Spring Boot如何用注解重构IoC容器

文章目录1.1 IoC容器&#xff1a;Spring的智能管家1.2 注解驱动&#xff1a;给管家下指令1.2.1 SpringBootApplication&#xff1a;总管家的聘书1.2.2 组件注解&#xff1a;员工的身份标识1.2.3 Autowired&#xff1a;依赖注入的三种方式1.2.4 Bean注解&#xff1a;手动招聘特殊…

【算法】92.翻转链表Ⅱ--通俗讲解

一、题目是啥?一句话说清 给你一个链表和两个整数 left 和 right,反转从第 left 个节点到第 right 个节点的子链表,并返回反转后的链表。其他部分保持不变。 示例: 输入:head = [1,2,3,4,5], left = 2, right = 4 输出:[1,4,3,2,5](反转了从第2到第4个节点) 二、解题…

Nature子刊:新发现!深层脑网络中发现强迫症症状的神经生物标志物

强迫症&#xff08;OCD&#xff09;是一种令人困扰的精神疾病&#xff0c;患者常常被强迫思维和强迫行为所困扰。例如&#xff0c;有些人会反复洗手&#xff0c;无法控制自己的清洁冲动&#xff1b;还有些人会不断检查门窗是否关好&#xff0c;即便他们已经确认过无数次。这些行…

Onlyoffice集成与AI交互操作指引(Iframe版)

Onlyoffice集成与AI交互操作指引&#xff08;Iframe版&#xff09; 本文档系统介绍了软件系统集成OnlyOffice实现在线编辑与AI辅助功能的方案。主要内容包括&#xff1a;后端需提供文档配置信息并实现Callback接口以处理文档保存&#xff1b;前端通过Vue集成编辑器&#xff0c…

TypeScript 中 keyof、typeof 和 instanceof

在 TypeScript 开发中&#xff0c;keyof、typeof 和 instanceof 是核心的类型操作符和操作符&#xff0c;专门用于提升类型安全、代码可读性和维护性。1. keyof 操作符定义和用途&#xff1a;keyof 是一个类型操作符&#xff0c;用于获取对象类型的所有键&#xff08;属性名&am…

分布式专题——1.1 Redis单机、主从、哨兵、集群部署

1 Redis 部署 下面演示在 Linux 环境下部署 Redis7。 1.1 单机部署 1.1.1 检查安装 gcc 环境Redis 是由 C 语言编写的&#xff0c;它的运行需要 C 环境&#xff0c;因此我们需要先安装 gcc&#xff1b; # 关闭防⽕墙 systemctl stop firewalld.service # 查看防火墙状态 firewa…

2025年渗透测试面试题总结-54(题目+回答)

安全领域各种资源&#xff0c;学习文档&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具&#xff0c;欢迎关注。1、SQL注入的防护方法有哪些&#xff1f; 2、永恒之蓝的漏洞原理是什么&#xff1f;怎么做到的&#xff1f; 3、命令…

安卓学习 之 按钮点击事件

今天学习安卓应用中的按钮点击事件&#xff1a;总结下来在安卓应用中的Button注册点击事件的方法主要是以下4种方法&#xff0c;稍后会逐个介绍&#xff1a; 第一种方法&#xff1a;自定义内部类的方法 第二种方法&#xff1a;匿名内部类的方法 第三种方法&#xff1a;当前Acti…

鸿蒙NEXT主题设置指南:应用级与页面级主题定制详解

在鸿蒙应用开发中&#xff0c;灵活的主题设置能力是实现个性化用户体验的关键技术&#xff0c;HarmonyOS NEXT提供了强大而灵活的主题设置功能&#xff0c;让开发者能够轻松实现应用级和页面级的主题定制。在当今追求个性化的时代&#xff0c;用户希望应用能够根据自己的喜好呈…

全球汽车氮化镓技术市场规模将于2031年增长至180.5亿美元,2025-2031年复合增长率达94.3%,由Infineon和Navitas驱动

全球汽车氮化镓技术市场规模将于2031年增长至180.5亿美元&#xff0c;2025-2031年复合增长率达94.3%&#xff0c;由Infineon和Navitas驱动汽车氮化镓技术正从一个有前景的细分市场加速进入主流电力电子领域。根据QYResearch&#xff08;恒州博智&#xff09;的《全球汽车GaN技术…