pyqt5制作音乐播放器(第三版)

这次接入了数据库,增加了翻页模式,更新了功能跳转之间的细节

数据设计:

收藏 like=1时表示被收藏,展示show=0的时候表示表数据被搜索

from peewee import Model, PrimaryKeyField, CharField, BooleanField, MySQLDatabase,IntegerFielddatabase = MySQLDatabase("czh", host="localhost", port=3306,user="root", password="123456")class BaseModel(Model):class Meta:database = databaseclass Music(BaseModel):id = PrimaryKeyField()singer = CharField(max_length=264, help_text='歌手')song = CharField(max_length=264, help_text='歌曲')path = CharField(max_length=264, help_text='路径')like = BooleanField(default=False, help_text='收藏')show = BooleanField(default=True, help_text='展示')row = IntegerField(help_text='行数')

在load_music中想到了lambda来传条件参数,分别给三个字段设计了对应的条件con1,con2,con3,只有在使用相应功能时修改条件即可实现函数复用了

records = Music.select().where(self.con1(Music.id) & self.con2(Music.show) & self.con3(Music.like)).offset(start_index).limit(self.page_size)

代码:

注:

7.25:修改了上下切换音乐的BUG,翻页后上下切换已经翻页自动播放等问题

import fnmatch
import os
import random
import sys
import loggingfrom PyQt5.QtGui import QPalette, QBrush, QPixmap, QLinearGradient, QColor, QIntValidator
from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton, QSlider, QLabel, \QTableWidget, QLineEdit, QTableWidgetItem
from PyQt5.QtMultimedia import QMediaPlayer, QMediaContent
from PyQt5.QtCore import QUrl, Qt, QTimerfrom database import Musiclogging.basicConfig(filename="music.log", filemode="w", format="%(asctime)s %(name)s:%(levelname)s:%(message)s",datefmt="%Y-%m-%d %H:%M:%S", level=logging.INFO)
logger = logging.getLogger("music")
KZT = logging.StreamHandler()
KZT.setLevel(logging.INFO)
logger.addHandler(KZT)class MusicPlayer(QMainWindow):def __init__(self):super().__init__()self.music_path = "F://wyy"  # 音乐文件夹,可以有子文件夹self.start_x = 10self.x_step = 100self.start_y = 10self.y_step = 40self.window_w, self.window_h = 500, 800self.duration = 1self.position = 0self.text = "歌曲未加载"self.random_play_list= []self.total_pages = 0self.page_size = 20self.current_page = 1  # 翻页时所在页面self.play_page = 1  # 正在播放音乐的所在页self.current_index = 1  # 数据库idself.current_music_info = Music.select().where(Music.id == self.current_index)[0]self.current_music = self.current_music_info.songself.current_singer = self.current_music_info.singerself.current_path = self.current_music_info.pathself.status = True  # 音乐是否在播放self.update_label = True  # 音乐是否在播放-》是否更新进度条self.random_play_status = False  # 是否处于随机播放状态self.show_favorite_status = False  # 是否展示收藏self.search_status = False  # 查询状态self.con1 = lambda x: x >= 0  # 普通查询条件self.con2 = lambda x: x >= 0  # 搜索查询条件self.con3 = lambda x: x >= 0  # 收藏查询条件self.load_local_music(False)  # 加载本地音乐文件self.init_ui()logger.info("配置加载完成")def init_ui(self):self.setWindowTitle("音乐播放器")self.resize(self.window_w, self.window_h)self.setMinimumSize(self.window_w, self.window_h)self.setMaximumSize(self.window_w, self.window_h)palette = QPalette()  # 主界面背景palette.setBrush(QPalette.Background, QBrush(QPixmap("imgs/21.jpg")))self.setPalette(palette)self.player = QMediaPlayer()self.play_button = QPushButton("播放", self)self.play_button.clicked.connect(self.play_music)self.play_button.move(self.start_x, self.start_y)self.change_button = QPushButton("暂停", self)self.change_button.clicked.connect(self.change_music_status)self.change_button.move(self.start_x + self.x_step, self.start_y)self.play_pre_button = QPushButton("上一首", self)self.play_pre_button.clicked.connect(self.play_pre)self.play_pre_button.move(self.start_x, self.start_y + self.y_step)self.play_next_button = QPushButton("下一首", self)self.play_next_button.clicked.connect(self.play_next)self.play_next_button.move(self.start_x + self.x_step, self.start_y + self.y_step)self.play_random_btn = QPushButton("随机播放", self)self.play_random_btn.clicked.connect(self.change_random_status)self.play_random_btn.move(self.start_x + 2 * self.x_step, self.start_y + self.y_step)self.favorite_btn = QPushButton("我的收藏", self)self.favorite_btn.clicked.connect(self.show_favorite)self.favorite_btn.move(self.start_x + 3 * self.x_step, self.start_y + self.y_step)self.volume_slider = QSlider(Qt.Horizontal, self)self.volume_slider.setRange(0, 100)self.volume_slider.setValue(50)self.volume_slider.setTickPosition(QSlider.TicksBelow)self.volume_slider.setTickInterval(10)self.volume_slider.resize(200, 30)self.volume_slider.sliderReleased.connect(self.change_volume)# self.volume_slider.sliderPressed.connect(self.volume_pressed)self.volume_slider.move(self.start_x, self.start_y + 2 * self.y_step)self.music_pro_bar = QLabel(self)self.music_pro_width = self.window_w - self.start_x - 210self.music_pro_bar.resize(self.music_pro_width, 10)self.music_pro_bar.move(self.start_x + 210, self.start_y + 2 * self.y_step + 10)gradient = QLinearGradient(0, 0, self.music_pro_width, 0)gradient.setColorAt(0, QColor(0, 0, 0))gradient.setColorAt(1, QColor(255, 255, 255))music_pro_bar_palette = QPalette()music_pro_bar_palette.setBrush(QPalette.Background, gradient)self.music_pro_bar.setAutoFillBackground(True)self.music_pro_bar.setPalette(music_pro_bar_palette)self.table_widget = QTableWidget(0, 3, parent=self)  # 检测结果列表self.table_widget.verticalHeader().hide()  # 隐藏行索引self.table_widget.move(self.start_x, self.start_y + 4 * self.y_step)self.table_widget.resize(self.window_w - self.start_x, self.window_h - self.start_y - 5 * self.y_step)self.table_widget.cellClicked.connect(self.cell_clicked)self.table_widget.cellDoubleClicked.connect(self.play_cell)self.table_widget.setColumnWidth(0, 150)self.table_widget.setColumnWidth(1, 250)self.table_widget.setColumnWidth(2, 70)self.table_widget.setEditTriggers(QTableWidget.NoEditTriggers)self.table_widget.setStyleSheet("QTableWidget {background-image: url('imgs/11.jpg');}")self.load_music()self.prev_button = QPushButton("上一页", self)self.next_button = QPushButton("下一页", self)self.prev_button.clicked.connect(self.click_prev_page)self.next_button.clicked.connect(self.click_next_page)self.prev_button.move(100, self.window_h - self.y_step)self.next_button.move(200, self.window_h - self.y_step)self.int_validator = QIntValidator(0, self.total_pages)self.jump_page_btn = QPushButton("跳转", self)self.jump_page_btn.clicked.connect(self.jump_page)self.jump_page_btn.move(300, self.window_h - self.y_step)self.jump_page_text = QLineEdit(self)self.jump_page_text.setValidator(self.int_validator)self.jump_page_text.move(400, self.window_h - self.y_step)self.search_btn = QPushButton("搜索", self)self.search_btn.move(self.start_x + 2 * self.x_step, self.start_y)self.search_btn.clicked.connect(self.change_search_status)self.search_text = QLineEdit(self)self.search_text.resize(self.window_w - self.start_x - 3 * self.x_step - 10, 30)self.search_text.move(self.start_x + 3 * self.x_step, self.start_y)self.search_text.setStyleSheet("QLineEdit {border-radius: 5px;}")self.search_text.returnPressed.connect(self.search_music)self.music_label = QLabel(self.text, self)self.music_label.resize(self.window_w - self.start_x, 30)self.music_label.move(self.start_x, self.start_y + 3 * self.y_step)self.music_label.setAlignment(Qt.AlignCenter)self.timer = QTimer()self.timer.timeout.connect(self.scroll_text)self.timer.start(500)self.player.stateChanged.connect(self.handle_player_status_changed)self.player.mediaStatusChanged.connect(self.handle_media_status_changed)self.player.durationChanged.connect(self.update_duration)self.player.positionChanged.connect(self.update_position)def play_music(self):self.player.setMedia(QMediaContent(QUrl.fromLocalFile(self.current_path)))self.player.play()self.text = f"当前播放:{self.current_music} —— {self.current_singer} "self.music_label.setText(self.text)logger.info("正在播放:%s - %s", self.current_music, self.current_singer)def change_music_status(self):if self.status:self.player.pause()self.status = Falseself.change_button.setText('继续')logger.info("已暂停当前音乐:%s", self.current_music)else:self.status = Trueself.player.play()self.change_button.setText('暂停')logger.info("已继续当前音乐:%s", self.current_music)def handle_media_status_changed(self, status):if status == QMediaPlayer.EndOfMedia:logger.info("播放完毕: %s - %s", self.current_music, self.current_singer)if self.random_play_status:  # 再判断是否随机播放self.play_random()else:self.play_next()def handle_player_status_changed(self, state):if state == QMediaPlayer.PlayingState:self.update_label = Trueelif state == QMediaPlayer.StoppedState:self.update_label = Falsedef clear_table(self):self.table_widget.clearContents()self.table_widget.setHorizontalHeaderLabels(['歌手', '歌曲'])  # 设置列表头self.table_widget.setRowCount(0)logger.info("已更新列表")def cell_clicked(self, row, column):if column != 2:text = self.table_widget.item(row, column).text()logger.info("点击了:%s", text)if column == 2:song = self.table_widget.item(row, column - 1).text()singer = self.table_widget.item(row, column - 2).text()query = Music.select().where((Music.song == song) & (Music.singer == singer))[0]like = query.likeif like == 1:query.like = 0logger.info("取消收藏:%s %s", query.singer, query.song)self.table_widget.setItem(row, column, QTableWidgetItem('收藏'))else:query.like = 1logger.info("收藏音乐:%s %s", query.singer, query.song)self.table_widget.setItem(row, column, QTableWidgetItem('已收藏'))query.save()def play_cell(self, row, column):if column == 1:self.status = Trueself.change_button.setText('暂停')song = self.table_widget.item(row, column).text()singer = self.table_widget.item(row, column - 1).text()query = Music.select().where((Music.song == song) & (Music.singer == singer))if query:self.current_index = query[0].idself.play_page = self.current_pageself.update_current_music()logger.info("双击播放:%s - %s", self.current_music, self.current_singer)self.play_music()def change_search_status(self):self.current_page = 1if not self.search_status:self.search_status = Trueself.search_btn.setText("返回列表")logger.info("点击搜索")self.con2 = lambda x: x == 0self.search_music()else:self.search_status = Falseself.search_btn.setText("搜索")query = Music.select().where(Music.show == 0)for q in query:q.show = 1q.save()self.con2 = lambda x: x >= 0self.load_music()self.search_text.setText('')logger.info("取消查询")def search_music(self):text = self.search_text.text()logger.info("点击查询:%s", text)if text:query = Music.select().where((Music.singer.contains(text)) | (Music.song.contains(text)))for q in query:q.show = Falseq.save()logger.info("查询到 %d条 相关内容", len(query))self.load_music()else:logger.info('未查询到相关音乐')def change_random_status(self):if not self.random_play_status:self.random_play_status = Trueself.play_random_btn.setText("取消随机")logger.info("切换为随机播放")query = Music.select().where(self.con1(Music.id) & self.con2(Music.show) & self.con3(Music.like))self.random_play_list= [q.id for q in query]logger.info("已加载随机列表")self.play_random()  # 切换时启动一次else:self.random_play_status = Falseself.play_random_btn.setText("随机播放")logger.info("取消随机播放")def play_random(self):if not self.random_play_list:self.change_random_status()  # 取消随机self.change_random_status()  # 重新随机self.current_index = random.choice(self.random_play_list)self.random_play_list.remove(self.current_index)logger.info("已获取随机音乐,剩余 %d 首", len(self.random_play_list))self.update_current_music()self.play_music()def load_music(self):total_records = Music.select().where(self.con1(Music.id) & self.con2(Music.show) & self.con3(Music.like)).count()self.total_pages = (total_records + self.page_size - 1) // self.page_sizeself.int_validator = QIntValidator(0, self.total_pages)records = Music.select().where(self.con1(Music.id) & self.con2(Music.show) & self.con3(Music.like)).offset((self.current_page - 1) * self.page_size).limit(self.page_size)self.table_widget.setRowCount(len(records))self.table_widget.setColumnCount(3)for i, record in enumerate(records):record.row = irecord.save()like = "收藏" if record.like == 0 else "已收藏"self.table_widget.setItem(i, 0, QTableWidgetItem(record.singer))self.table_widget.setItem(i, 1, QTableWidgetItem(record.song))self.table_widget.setItem(i, 2, QTableWidgetItem(like))self.table_widget.setHorizontalHeaderLabels(['歌手', '歌曲', '♥'])self.statusBar().showMessage(f'{self.current_page}/{self.total_pages}')logger.info('已加载音乐列表')def load_local_music(self, ensure):logger.info('重新加载列表')self.find_mp3_files() if ensure else None  # 从本地重新加载def show_favorite(self):self.current_page = 1if not self.show_favorite_status:logger.info('已进入我的收藏列表')self.show_favorite_status = Trueself.favorite_btn.setText('返回列表')self.con3 = lambda x: x == 1self.change_search_status() if self.search_status else Noneself.load_music()else:logger.info('已返回所有列表')self.show_favorite_status = Falseself.favorite_btn.setText('我的收藏')self.con3 = lambda x: x >= 0self.load_music()def update_current_music(self):self.current_music_info = Music.select().where(Music.id == self.current_index)[0]self.current_music = self.current_music_info.songself.current_singer = self.current_music_info.singerself.current_path = self.current_music_info.pathdef play_pre(self):logger.info("播放上一首")row = self.current_music_info.rowquery = Music.select().where(self.con1(Music.id) & self.con2(Music.show) & self.con3(Music.like)).offset((self.play_page - 1) * self.page_size).limit(self.page_size)if row == 0:self.play_page = self.total_pages if self.play_page == 1 else self.play_page - 1query = Music.select().where(self.con1(Music.id) & self.con2(Music.show) & self.con3(Music.like)).offset((self.play_page - 1) * self.page_size).limit(self.page_size)row = len(query) - 1logger.info(f"已播放至第一首,切换至最后一首")else:row -= 1self.current_index = query[row].idself.update_current_music()self.status = Trueself.change_button.setText('暂停')logger.info("切换音乐为:%s - %s", self.current_music, self.current_singer)self.play_music()def play_next(self):logger.info("播放下一首")row = self.current_music_info.rowquery = Music.select().where(self.con1(Music.id) & self.con2(Music.show) & self.con3(Music.like)).offset((self.play_page - 1) * self.page_size).limit(self.page_size)if row == len(query) - 1:  # 该页最后一条数据row = 0  # 切换至首条数据self.play_page = 1 if self.play_page == self.total_pages else self.play_page + 1  # 若为最后一页切换至首页query = Music.select().where(self.con1(Music.id) & self.con2(Music.show) & self.con3(Music.like)).offset((self.play_page - 1) * self.page_size).limit(self.page_size)  # 重新查询logger.info(f"已播放至最后一首,切换至第一首")else:row += 1self.current_index = query[row].idself.update_current_music()self.status = Trueself.change_button.setText('暂停')logger.info("切换音乐为:%s - %s", self.current_music, self.current_singer)self.play_music()def change_volume(self):value = self.volume_slider.value()self.player.setVolume(value)logger.info("滑动设置音量为%s", value)def set_position(self):self.music_pro_bar.resize(int(self.position / self.duration * self.music_pro_width), 10)def update_duration(self, duration):if not self.update_label:returnself.duration = durationdef update_position(self, position):if not self.update_label:returnself.position = positionself.set_position()def scroll_text(self):current_text = self.music_label.text()scroll_text = current_text[1:] + current_text[0]self.music_label.setText(scroll_text)self.music_label.setStyleSheet(f"color:{self.rgb2hex(*self.random_color())}")def click_prev_page(self):if self.current_page > 1:logger.info('跳转上一页')self.current_page -= 1self.load_music()def click_next_page(self):if self.current_page < self.total_pages:logger.info('跳转点击下一页')self.current_page += 1self.load_music()def jump_page(self):self.current_page = int(self.jump_page_text.text())logger.info('输入跳转 %d 页', self.current_page)self.load_music()def rgb2hex(self, r, g, b):return "#{:02x}{:02x}{:02x}".format(r, g, b)def find_mp3_files(self):  # 生成音乐文件列表,根据需求自定义for root, dirs, files in os.walk(self.music_path):for file in files:if fnmatch.fnmatch(file, '*.mp3'):if '_' in file:path = os.path.join(root, file)s = Music.select().where(Music.path == path)if s:continueelse:tp = Music(singer=file.split('_')[1].split('.')[0], song=file.split('_')[0],path=path, like=False, show=True)tp.save()def random_color(self):  # 随机颜色r, g, b = random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)return r, g, bif __name__ == "__main__":app = QApplication(sys.argv)player = MusicPlayer()player.show()sys.exit(app.exec_())

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

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

相关文章

【区块链+绿色低碳】基于区块链的碳排放管理系统 | FISCO BCOS应用案例

目前业内的碳排放核查方式主要依靠于第三方人工核查、手动填报数据&#xff0c;然后由具备有认证资质的机构进行核验 盖章。但在此过程中存在数据造假的情况&#xff0c;给碳排放量核算的准确性、可靠性带来挑战。 中科易云采用国产开源联盟链 FISCO BCOS&#xff0c;推出基于…

搭建博客系统#Golang

WANLI 博客系统 项目介绍 基于vue3和gin框架开发的前后端分离个人博客系统&#xff0c;包含md格式的文本编辑展示&#xff0c;点赞评论收藏&#xff0c;新闻热点&#xff0c;匿名聊天室&#xff0c;文章搜索等功能。 项目已经部署并运行&#xff0c;快速开发可以查看博客&am…

GitHub每日最火火火项目(7.25)

1. 项目名称&#xff1a;public - apis / public - apis 项目介绍&#xff1a;这是一个集体列表&#xff0c;收集了各种免费的 APIs。在当今的软件开发中&#xff0c;API&#xff08;应用程序编程接口&#xff09;扮演着至关重要的角色&#xff0c;它们允许不同的应用程序和服…

基于Go语言开发调用高德API地址逆编码

最近公司有一个需求&#xff0c;有一批数据只有经纬度没有确定地址&#xff0c;现在需要根据经纬度补全地址&#xff0c;刚好高德提供这么一个API&#xff0c;可以拿来使用。 不过因为提供的数据的经纬度是大地2000坐标系&#xff0c;跟高德坐标系还不一样&#xff0c;需要进行…

培训第十一天(nfs与samba共享文件)

上午 1、环境准备 &#xff08;1&#xff09;yum源 &#xff08;一个云仓库pepl仓库&#xff09; [rootweb ~]# vim /etc/yum.repos.d/hh.repo [a]nameabaseurlfile:///mntgpgcheck0[rootweb ~]# vim /etc/fstab /dev/cdrom /mnt iso9660 defaults 0 0[rootweb ~]# mount -a[…

WebKit与PWA:打造无缝的渐进式Web应用体验

WebKit与PWA&#xff1a;打造无缝的渐进式Web应用体验 随着移动互联网的快速发展&#xff0c;用户对于Web应用的体验要求越来越高。Progressive Web Apps&#xff08;PWA&#xff09;&#xff0c;即渐进式Web应用&#xff0c;以其无需安装、易于更新、跨平台等特性&#xff0c…

JavaSE--基础语法--继承和多态(第三期)

一.继承 1.1我们为什么需要继承? 首先&#xff0c;Java中使用类对现实世界中实体来进行描述&#xff0c;类经过实例化之后的产物对象&#xff0c;则可以用来表示现实中的实体&#xff0c;但是 现实世界错综复杂&#xff0c;事物之间可能会存在一些关联&#xff0c;那在设计程…

Spring-一个接口拥有多实现类-企业应用场景

前言: 由于java的多态特性,往往一个接口有多种具体的实现,传统的做法是在一个实现类中新建不同方法。但这种做法既不符合OOP的思想,而且当每种实现逻辑都相对复杂的时候,会让我们的代码显得臃肿和凌乱,当我们只需要使用其中一种实现的时候,没有必要去关心其他实现,所以…

Java读取文件中多个JSON对象,并且16进制字符串和byte相互转换,将byte转为16进制字符串并写入json文件

Java读取文件中多个JSON对象 File file new File("/home/renjx/testcases.json");//将json转为mapsObjectMapper objectMapper new ObjectMapper();List<Map<String, String>> maps objectMapper.readValue(file, new TypeReference<List<Map&…

Apache虚拟主机VirtualHost配置项详解

在Apache中,VirtualHost容器用于定义一个虚拟主机的配置,它允许在单一的物理服务器上托管多个不同的网站,每个网站可以有自己的域名、文档根目录、错误日志等。VirtualHost内的配置项非常灵活,可以包含从基本的网站信息到高级的URL重写和安全设置。 以下是一些常见的Virtu…

Java之数组应用-冒泡排序-二分查找

冒泡排序 冒泡(Bubble Sort)排序是一种简单排序算法&#xff0c;它通过依次比较交换两个相邻元素实现功能。每一次冒泡会让至少一个元素移动到它应该在的位置上&#xff0c;这样 n 次冒泡就完成了 n 个数据的排序工作。 这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”…

实在智能RPA助力三大运营商用“AI+RPA”打造新质生产力!

近年来&#xff0c;人工智能及自动化技术的突破性进展&#xff0c;正深刻地影响和重塑全球的生活生产模式。 作为我国现代化和数字化进程中的先行军的运营商行业&#xff0c;以中国电信、中国联通和中国移动等为代表的运营商企业&#xff0c;正致力于把握这一历史机遇&#xff…

SpringBoot项目配置多环境env

javaSpringBoot项目多环境配置 为什么maven Profiles 救命项目的pom文件管理 为什么 项目里面需要集成测试环境、开发、生产、多云环境&#xff0c;不仅需要application.yml,还需要加载别的config配置文件 故&#xff0c;我需要便捷多环境配置管理 maven Profiles 救命 项目的…

MySQL练手 --- 1934. 确认率

题目链接&#xff1a;1934. 确认率 思路 由题可知&#xff0c;两个表&#xff0c;一个表为Signups注册表&#xff0c;另一个表为Confirmations信息确认表&#xff0c;表的关联关系为 一对一&#xff0c;且user_id作为两个表的连接条件&#xff08;匹配字段&#xff09;&#…

【C# WInForm】将TextBox从输入框设置为文本框

1.需求情形&#xff1a; textbox作为最常用的控件之一&#xff0c;通常是用来输入文本信息或者显示文字&#xff0c;但是如果要在界面中显示大段文本&#xff0c;一个带有边框、可选中的文本样式似乎不合适。像这样&#xff1a; 我需要的是这段文字不仅能跨行&#xff0c;而且…

Atlassian Intelligence工具集解析:从自然语言到JQL处理,从虚拟代理到AI摘要、编辑器中的生成式AI等,全方位提升团队协作效率

2023年&#xff0c;Atlassian推出了Atlassian Intelligence——这是一款功能强大的团队协作增强工具&#xff0c;托管在其高级和企业级云平台上。Atlassian遵循 “释放团队潜力”的使命&#xff0c;利用合乎道德的AI模型来加速组织的现有能力。通过人机协作&#xff0c;用户可以…

判断文件格式

判断文件格式 判断文件格式,以便处理: if UpperCase(ExtractFileExt(sFileName)) <> .PDF thenbeginimgCapture.Picture.Graphic := nil;imgCapture.Picture.LoadFromFile(sFileName);end;unit SysUtils; function ExtractFileName(const FileName: string): string;/…

Unity3D 水面Mesh生成详解

在Unity3D中&#xff0c;创建逼真的水面效果是许多游戏和仿真项目中的重要部分。水面的动态效果通常通过Mesh&#xff08;网格&#xff09;的顶点动画来实现。本文将详细介绍如何在Unity3D中生成动态的水面Mesh&#xff0c;并给出具体的代码实现。. 对惹&#xff0c;这里有一个…

Vite+Vue 3 环境变量配置

在开发 Web 应用时&#xff0c;我们常常需要根据不同的环境&#xff08;如开发、测试、生产&#xff09;进行不同的配置。 Vite 提供了灵活的环境变量配置机制在一个特殊的 import.meta.env 对象上暴露环境变量&#xff0c;这些变量在构建时会被静态地替换掉。让我们可以轻松管…

c++笔记2

目录 2.2 栈底&#xff08;bottom&#xff09; } 大数乘大数 节点&#xff1a;包含一个数据元素及若干指向子树分支的信息 。 节点的度&#xff1a;一个节点拥有子树的数目称为节点的度 。 叶子节点&#xff1a;也称为终端节点&#xff0c;没有子树的节点或者度为零的节点…