基于PyQt5的UI界面开发——图像与视频的加载与显示

article/2025/7/19 5:02:58

介绍

这里我们的主要目标是实现一个基于PyQt5和OpenCV的图像浏览和视频播放应用。用户可以选择本地的图像或视频文件夹,进行图像自动播放和图像切换以及视频播放和调用摄像头等操作,并且支持图像保存功能。项目的核心设计包括文件路径选择、图像或视频的显示、自动播放、图像保存等功能。

录得教程视频:专为深度学习开发者设计的PyQt5快速上手教程_哔哩哔哩_bilibili

感兴趣的可以看看。 

UI的初步设计

整体的设计如图所示,主体的窗口名我命名为ImageLoadWindow,其他控件的标记我已经写在了上方图片中,大家可以和下面的代码进行对比。

视频的加载

文件路径的读取

当我们在开发视频处理或视频播放应用时,经常需要让用户选择视频文件以及指定保存路径。

SetPFilePath 方法用于选择视频文件。它使用 QFileDialog.getOpenFileName 弹出一个文件选择对话框,允许用户从文件系统中选择一个视频文件。如果用户选择了文件,该方法将更新界面上的文本和内部变量。

    def SetPFilePath(self):filename, _ = QFileDialog.getOpenFileName(self, "选择视频文件", '.', "Video Files (*.mp4 *.avi *.mkv)")if filename:self.PFilePathLiEd.setText(filename)self.PFilePath = filename

SetSFilePath 方法用于设置保存路径。它使用 QFileDialog.getExistingDirectory 弹出一个目录选择对话框,允许用户选择一个目录作为保存路径。如果用户选择了目录,该方法将更新界面上的文本和内部变量。

    def SetSFilePath(self):dirname = QFileDialog.getExistingDirectory(self, "选择保存目录", '.')if dirname:self.SFilePathLiEd.setText(dirname)self.SFilePath = dirname + '/'

这是一个很好用的框架,以后的ui设计可以直接对着我这里命名,这样在创建新的时候,可以实现代码的移植。

视频文件的读取和显示

这里,我们想让用户选择本地的视频文件或者通过摄像头实时获取视频流,并将视频帧显示在 PyQt5 的窗口中。

SetPFilePath,用于选择视频文件,并将文件路径显示在输入框中。此处的SetSFilePath,用于选择保存目录路径,但实际在下面的代码中并没有添加相关的逻辑。

当我们选择了视频文件,并点击运行按钮后,在左侧的OutputLab(QLable控件)显示了视频的播放。当不没有选择视频文件,就会根据LoadWayCBox(Combo Box控件)的索引去选择我们的摄像头,请注意此处是下拉框选项,索引是从0开始,符合摄像头的读取顺序,如果要用在其他项目时,要注意是否正确。

from PyQt5.QtWidgets import QApplication, QMainWindow, QFileDialog, QMessageBox
from PyQt5.QtGui import QPixmap
from PyQt5.QtCore import QTimer
import qimage2ndarray
import cv2
from load_image import Ui_ImageLoadWindowclass ImageLoadWindow(QMainWindow, Ui_ImageLoadWindow):def __init__(self):super().__init__()self.setupUi(self)self.PrepParameters()self.CallBackFunctions()self.timer = QTimer(self)self.timer.timeout.connect(self.update_frame)self.capture = None  # 用于存储视频捕获对象self.frame = None  # 用于存储当前帧def PrepParameters(self):# 选择文件路径self.PFilePath = ""# 保存文件路径self.SFilePath = ""self.PFilePathLiEd.setText(self.PFilePath)self.SFilePathLiEd.setText(self.SFilePath)def CallBackFunctions(self):self.PFilePathBt.clicked.connect(self.SetPFilePath)self.SFilePathBt.clicked.connect(self.SetSFilePath)self.RunBt.clicked.connect(self.start_video_playback)self.ExitBt.clicked.connect(self.close_application)def SetPFilePath(self):filename, _ = QFileDialog.getOpenFileName(self, "选择视频文件", '.', "Video Files (*.mp4 *.avi *.mkv)")if filename:self.PFilePathLiEd.setText(filename)self.PFilePath = filenamedef SetSFilePath(self):dirname = QFileDialog.getExistingDirectory(self, "选择保存目录", '.')if dirname:self.SFilePathLiEd.setText(dirname)self.SFilePath = dirname + '/'def start_video_playback(self):# 选择视频文件后,启动视频播放if self.PFilePath:self.capture = cv2.VideoCapture(self.PFilePath)else:load_way = self.LoadWayCBox.currentIndex()self.capture = cv2.VideoCapture(load_way)if self.capture.isOpened():self.timer.start(30)  # 每30毫秒更新一次帧else:print("无法打开视频文件或摄像头!")def update_frame(self):ret, self.frame = self.capture.read()if ret:rgb_image = cv2.cvtColor(self.frame, cv2.COLOR_BGR2RGB)# 使用 qimage2ndarray 将 NumPy 数组转换为 QImageqimg = qimage2ndarray.array2qimage(rgb_image)pixmap = QPixmap.fromImage(qimg)self.OutputLab.setPixmap(pixmap)else:self.timer.stop()  # 停止定时器,当视频播放完时def close_application(self):"""关闭应用程序"""reply = QMessageBox.question(self, '退出', '您确定要退出程序吗?', QMessageBox.Yes | QMessageBox.No, QMessageBox.No)if reply == QMessageBox.Yes:if self.capture:self.capture.release()QApplication.quit()if __name__ == "__main__":import sysapp = QApplication(sys.argv)window = ImageLoadWindow()window.show()sys.exit(app.exec_())

视频文件的处理 

如下所示,即为选择了视频文件后运行的情况。如果不选就会调用本地的摄像头。

 关于对视频处理的一块,你可以在下面注释的地方完成逻辑的实现。

    def update_frame(self):ret, self.frame = self.capture.read()if ret:# self.frame = ... 此处实现rgb_image = cv2.cvtColor(self.frame, cv2.COLOR_BGR2RGB)qimg = qimage2ndarray.array2qimage(rgb_image)pixmap = QPixmap.fromImage(qimg)self.OutputLab.setPixmap(pixmap)else:self.timer.stop()

图像的加载

文件路径的读取

SetPFilePath方法允许用户选择一个目录,目录中的所有文件都会被读取并存储在 self.pimage_list 中。为了仅获取图片文件,我过滤了所有非图片文件,确保 self.pimage_list 只包含有,比如.jpg、.png、.jpeg、.bmp 和 .gif 等图片格式。

    def SetPFilePath(self):dirname = QFileDialog.getExistingDirectory(self, "浏览", '.')if dirname:self.PFilePathLiEd.setText(dirname)self.PFilePath=dirname+'/'self.pimage_list = [f for f in os.listdir(self.PFilePath) iff.lower().endswith(('.png', '.jpg', '.jpeg', '.bmp', '.gif'))]

SetSFilePath方法选择一个保存目录。选择完成后,保存路径会被显示在 SFilePathLiEd 文本框中,并将 SFilePath 变量更新为所选目录的路径。

    def SetSFilePath(self):dirname = QFileDialog.getExistingDirectory(self, "浏览", '.')if dirname:self.SFilePathLiEd.setText(dirname)self.SFilePath=dirname+'/'

图像的切换

为了进一步丰富我们ui的功能,这里我们提供了两个方式去显示图像,第一种是通过控件显示图片,另外一种可以实现自动播放的功能。

下面为更新设计后的UI:

这里我们先要理清楚我们接下来要做什么,首先选择处理文件的路径,以及保存的路径,并点击运行按钮,显示第一张图像,如果没有选择保存路径,则只显示图像而不进行保存。

通过Last和Next键去控制图像的显示,并且第一张图像Last键被禁用,最后一张图像Next键被禁用。图像的显示和保存都通过opencv实现。

from PyQt5.QtWidgets import QApplication, QMainWindow, QFileDialog, QMessageBox
from PyQt5.QtGui import QPixmap
import qimage2ndarray
import cv2
import os
from load_image import Ui_ImageLoadWindowclass ImageLoadWindow2(QMainWindow, Ui_ImageLoadWindow):def __init__(self):super().__init__()self.setupUi(self)self.PrepParameters()self.CallBackFunctions()def PrepParameters(self):self.PFilePath = r''  # 初始化路径为空self.SFilePath = r''  # 初始化保存路径为空self.PFilePathLiEd.setText(self.PFilePath)self.SFilePathLiEd.setText(self.SFilePath)self.pimage_list = []  # 存储图像文件列表self.current_image_idx = -1  # 用于追踪当前显示的图像索引self.current_image = None  # 用于存储当前显示的图像数据def CallBackFunctions(self):self.PFilePathBt.clicked.connect(self.SetPFilePath)self.SFilePathBt.clicked.connect(self.SetSFilePath)self.RunBt.clicked.connect(self.start_image_show)  # 运行按钮,开始显示图像self.LastBt.clicked.connect(self.show_last_image)  # 上一张按钮self.NextBt.clicked.connect(self.show_next_image)  # 下一张按钮self.ExitBt.clicked.connect(self.close_application)  # 退出按钮def SetPFilePath(self):dirname = QFileDialog.getExistingDirectory(self, "浏览", '.')if dirname:self.PFilePathLiEd.setText(dirname)self.PFilePath = dirname + '/'self.pimage_list = [f for f in os.listdir(self.PFilePath)if f.lower().endswith(('.png', '.jpg', '.jpeg', '.bmp', '.gif'))]self.current_image_idx = -1  # 重置图像索引def SetSFilePath(self):dirname = QFileDialog.getExistingDirectory(self, "浏览", '.')if dirname:self.SFilePathLiEd.setText(dirname)self.SFilePath = dirname + '/'def start_image_show(self):if not self.pimage_list:QMessageBox.warning(self, '警告', '没有找到图像文件!', QMessageBox.Ok)return# 如果保存路径为空,弹出警告窗口询问是否继续if not self.SFilePath:reply = QMessageBox.question(self, '保存路径未选择', '保存路径未选择,是否继续显示图像?',QMessageBox.Yes | QMessageBox.No, QMessageBox.No)if reply == QMessageBox.No:return  # 如果用户选择 No,返回不继续self.current_image_idx = 0  # 从第一张图像开始显示self.show_image(self.current_image_idx)# 启用和禁用按钮self.update_navigation_buttons()def show_image(self, idx):if 0 <= idx < len(self.pimage_list):# 获取图像文件路径img_path = os.path.join(self.PFilePath, self.pimage_list[idx])image = cv2.imread(img_path)if image is not None:# 转换为RGB模式rgb_image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)self.current_image = imageqimg = qimage2ndarray.array2qimage(rgb_image)pixmap = QPixmap.fromImage(qimg)self.OutputLab.setPixmap(pixmap)# 如果有保存路径,才进行自动保存if self.SFilePath:self.auto_save_image(self.pimage_list[idx])else:print(f"无法读取图像: {img_path}")def auto_save_image(self, image_filename):if self.current_image is None:returnsave_path = os.path.join(self.SFilePath, image_filename)os.makedirs(self.SFilePath, exist_ok=True)cv2.imwrite(save_path, self.current_image)print(f"图像已自动保存到: {save_path}")def show_last_image(self):if self.current_image_idx > 0:self.current_image_idx -= 1self.show_image(self.current_image_idx)self.update_navigation_buttons()def show_next_image(self):if self.current_image_idx < len(self.pimage_list) - 1:self.current_image_idx += 1self.show_image(self.current_image_idx)self.update_navigation_buttons()def update_navigation_buttons(self):if self.current_image_idx == 0:self.LastBt.setEnabled(False)  # 禁用上一张按钮else:self.LastBt.setEnabled(True)  # 启用上一张按钮if self.current_image_idx == len(self.pimage_list) - 1:self.NextBt.setEnabled(False)  # 禁用下一张按钮else:self.NextBt.setEnabled(True)  # 启用下一张按钮def close_application(self):"""关闭应用程序"""reply = QMessageBox.question(self, '退出', '您确定要退出程序吗?', QMessageBox.Yes | QMessageBox.No, QMessageBox.No)if reply == QMessageBox.Yes:QApplication.quit()if __name__ == "__main__":import sysapp = QApplication(sys.argv)window = ImageLoadWindow2()window.show()sys.exit(app.exec_())

逻辑流程概述:

  1. 用户选择图像文件夹和保存路径(可选)。
  2. 点击运行按钮开始显示第一张图像。
  3. 如果保存路径未选择,程序会弹出提示,询问用户是否继续显示图像。
  4. 用户可以通过上一张(LastBt)和下一张(NextBt)按钮切换图像。
  5. 当图像显示时,若保存路径已选择,程序会自动保存当前显示的图像。
  6. 如果用户关闭程序,会弹出确认退出的对话框。

实现自动播放功能

下面就是完整的设计了,由于考虑到自动播放,所以我在这里添加了暂停恢复键,用于播放过程中的暂停。

好的,这里我们还是需要理清楚我们需要做什么。首先在选择好图像文件夹路径和保存路径后,如果勾选了自动播放就会禁用掉Last和Next键,点击运行会弹出窗口是否进行循环播放,如果选择进行循环播放,则图像会显示在OutputLab上,如果选择了否也会进行自动播放,只是在播放完成之后,可以切换到Last和Next键进行图片的切换。

在自动播放过程中,如果点击了暂停键,文字变为恢复,再点击文字变为暂停,在点击了暂停后,再点击运行可以重新进行选择。

from PyQt5.QtWidgets import QApplication, QMainWindow, QFileDialog, QMessageBox
from PyQt5.QtGui import QPixmap
from PyQt5.QtCore import QTimer
import qimage2ndarray
import cv2
import os
from load_image import Ui_ImageLoadWindowclass ImageLoadWindow2(QMainWindow, Ui_ImageLoadWindow):def __init__(self):super().__init__()self.setupUi(self)self.PrepParameters()self.CallBackFunctions()def PrepParameters(self):self.PFilePath = r''  # 初始化路径为空self.SFilePath = r''  # 初始化保存路径为空self.PFilePathLiEd.setText(self.PFilePath)self.SFilePathLiEd.setText(self.SFilePath)self.pimage_list = []  # 存储图像文件列表self.current_image_idx = -1  # 用于追踪当前显示的图像索引self.current_image = None  # 用于存储当前显示的图像数据self.is_autoplay = False  # 是否启用自动播放标志self.is_loop = False  # 是否循环播放标志self.is_paused = False  # 是否暂停自动播放标志def CallBackFunctions(self):self.PFilePathBt.clicked.connect(self.SetPFilePath)self.SFilePathBt.clicked.connect(self.SetSFilePath)self.RunBt.clicked.connect(self.start_image_show)  # 运行按钮,开始显示图像self.LastBt.clicked.connect(self.show_last_image)  # 上一张按钮self.NextBt.clicked.connect(self.show_next_image)  # 下一张按钮self.ExitBt.clicked.connect(self.close_application)  # 退出按钮self.AutoplaycheckBox.stateChanged.connect(self.toggle_autoplay)  # 连接自动播放勾选框self.StopRecoverBt.clicked.connect(self.pause_or_resume_autoplay)  # 连接暂停/恢复按钮def SetPFilePath(self):dirname = QFileDialog.getExistingDirectory(self, "浏览", '.')if dirname:self.PFilePathLiEd.setText(dirname)self.PFilePath = dirname + '/'self.pimage_list = [f for f in os.listdir(self.PFilePath)if f.lower().endswith(('.png', '.jpg', '.jpeg', '.bmp', '.gif'))]self.current_image_idx = -1  # 重置图像索引def SetSFilePath(self):dirname = QFileDialog.getExistingDirectory(self, "浏览", '.')if dirname:self.SFilePathLiEd.setText(dirname)self.SFilePath = dirname + '/'def toggle_autoplay(self, state):"""根据勾选状态设置是否启用自动播放"""self.is_autoplay = state == 2  # 2表示勾选状态self.StopRecoverBt.setEnabled(self.is_autoplay)  # 只有启用自动播放时才启用暂停/恢复按钮def start_image_show(self):if not self.pimage_list:QMessageBox.warning(self, '警告', '没有找到图像文件!', QMessageBox.Ok)return# 如果保存路径为空,弹出警告窗口询问是否继续if not self.SFilePath:reply = QMessageBox.question(self, '保存路径未选择', '保存路径未选择,是否继续显示图像?',QMessageBox.Yes | QMessageBox.No, QMessageBox.No)if reply == QMessageBox.No:return  # 如果用户选择 No,返回不继续self.current_image_idx = 0  # 从第一张图像开始显示self.show_image(self.current_image_idx)if self.is_autoplay:# 如果是自动播放模式,弹出对话框确认是否循环播放reply = QMessageBox.question(self, '循环播放', '是否循环播放图像?',QMessageBox.Yes | QMessageBox.No, QMessageBox.No)if reply == QMessageBox.Yes:self.is_loop = True  # 启用循环播放else:self.is_loop = False  # 不循环播放# 启动自动播放self.start_autoplay()else:# 启用和禁用按钮self.update_navigation_buttons()# 如果是自动播放并且已经暂停了,点击运行时,确保按钮文本恢复为'暂停'if self.is_paused:self.StopRecoverBt.setText('暂停')  # 恢复为暂停按钮文本def start_autoplay(self):"""启动自动播放模式"""if self.is_paused:# 如果当前是暂停状态,直接恢复定时器self.is_paused = Falseself.StopRecoverBt.setText('暂停')  # 修改按钮文本为 '暂停'self.LastBt.setEnabled(False)  # 禁用上一张按钮self.NextBt.setEnabled(False)  # 禁用下一张按钮# 使用QTimer定时器进行自动播放if not hasattr(self, 'autoplay_timer'):  # 如果定时器不存在,则创建self.autoplay_timer = QTimer(self)self.autoplay_timer.timeout.connect(self.next_image_in_autoplay)self.autoplay_timer.start(1000)  # 每1秒切换一张图像def next_image_in_autoplay(self):"""自动播放下一张图像"""if self.is_paused:return  # 如果已暂停,不进行任何操作if self.current_image_idx < len(self.pimage_list) - 1:self.current_image_idx += 1self.show_image(self.current_image_idx)else:if self.is_loop:self.current_image_idx = 0  # 如果是循环播放,回到第一张self.show_image(self.current_image_idx)else:self.stop_autoplay()  # 自动播放完成后停止并恢复按钮def stop_autoplay(self):"""停止自动播放"""if hasattr(self, 'autoplay_timer'):self.autoplay_timer.stop()self.update_navigation_buttons()  # 恢复按钮状态def pause_or_resume_autoplay(self):"""暂停或恢复自动播放"""if self.is_paused:self.is_paused = Falseself.StopRecoverBt.setText('暂停')  # 修改按钮文本为 '暂停'self.start_autoplay()  # 恢复播放else:self.is_paused = Trueself.StopRecoverBt.setText('恢复')  # 修改按钮文本为 '恢复'self.autoplay_timer.stop()  # 暂停定时器def show_image(self, idx):if 0 <= idx < len(self.pimage_list):# 获取图像文件路径img_path = os.path.join(self.PFilePath, self.pimage_list[idx])image = cv2.imread(img_path)if image is not None:# 转换为RGB模式rgb_image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)self.current_image = imageqimg = qimage2ndarray.array2qimage(rgb_image)pixmap = QPixmap.fromImage(qimg)self.OutputLab.setPixmap(pixmap)# 如果有保存路径,才进行自动保存if self.SFilePath:self.auto_save_image(self.pimage_list[idx])else:print(f"无法读取图像: {img_path}")def auto_save_image(self, image_filename):if self.current_image is None:returnsave_path = os.path.join(self.SFilePath, image_filename)os.makedirs(self.SFilePath, exist_ok=True)cv2.imwrite(save_path, self.current_image)print(f"图像已自动保存到: {save_path}")def show_last_image(self):if self.current_image_idx > 0:self.current_image_idx -= 1self.show_image(self.current_image_idx)self.update_navigation_buttons()def show_next_image(self):if self.current_image_idx < len(self.pimage_list) - 1:self.current_image_idx += 1self.show_image(self.current_image_idx)self.update_navigation_buttons()def update_navigation_buttons(self):"""更新上一张和下一张按钮的状态"""if self.current_image_idx == 0:self.LastBt.setEnabled(False)  # 禁用上一张按钮else:self.LastBt.setEnabled(True)  # 启用上一张按钮if self.current_image_idx == len(self.pimage_list) - 1:self.NextBt.setEnabled(False)  # 禁用下一张按钮else:self.NextBt.setEnabled(True)  # 启用下一张按钮def close_application(self):"""关闭应用程序"""reply = QMessageBox.question(self, '退出', '您确定要退出程序吗?', QMessageBox.Yes | QMessageBox.No, QMessageBox.No)if reply == QMessageBox.Yes:QApplication.quit()if __name__ == "__main__":import sysapp = QApplication(sys.argv)window = ImageLoadWindow2()window.show()sys.exit(app.exec_())

图像文件的处理

可以在注释处进行图像处理。

    def show_image(self, idx):if 0 <= idx < len(self.pimage_list):# 获取图像文件路径img_path = os.path.join(self.PFilePath, self.pimage_list[idx])image = cv2.imread(img_path)# image = ... 图像处理if image is not None:# 转换为RGB模式rgb_image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)self.current_image = imageqimg = qimage2ndarray.array2qimage(rgb_image)pixmap = QPixmap.fromImage(qimg)self.OutputLab.setPixmap(pixmap)# 如果有保存路径,才进行自动保存if self.SFilePath:self.auto_save_image(self.pimage_list[idx])else:print(f"无法读取图像: {img_path}")

其他

这里记录一下使用plainTextEdit显示信息。由于内容有限,所以不另外再写一篇博客了。

名字就叫plainTextEdit,这里我就不修改了。

这里只需要做两个修改就好了。

在初始化的时候PrepParameters,添加一个

self.plainTextEdit.clear()  # 清除文本框内容

你也可以和按钮结合在一起。

还有一个是将内容显示在plainTextEdit上面:

若要给ui添加背景可插入以下代码

    def paintEvent(self, event):painter = QPainter(self)pixmap = QPixmap(r"background.jpg")painter.drawPixmap(self.rect(), pixmap)

 运行效果如下所示:

总结

本篇展示了如何使用PyQt5和OpenCV实现一个图像浏览与视频播放应用,涵盖了文件路径选择、图像/视频显示、自动播放或切换、暂停与恢复、图像保存等多种功能。本篇的代码具有较高的灵活性,你只需要按照相同的命名方式就能够实现代码的移植。希望通过本篇,为其他大家提供有用的参考和实现思路。

另外,需要注意的一点是,在循环播放的时候图像会重复的保存,关于这一部分的相关逻辑,我不想再修改,也不怎么碍事。最后,我这里不提供原来设计ui文件,因为,我写的已经很清楚了,大家能够自己简单的设计,没必要再找我要。


http://www.hkcw.cn/article/ALMIgqTGHp.shtml

相关文章

浙江3名高中生深夜被困深山 成功获救未受伤

5月31日端午节晚上,三名高中生因降雨失温被困在浙江台州的大雷山。救援人员接到通知后迅速展开搜救行动,最终找到三人并提供了保温毯和雨衣等物资。所幸没有人员伤亡。网络视频显示,当晚天空下着大雨,民警、消防人员及救援队在集结搜寻。大雷山位于浙江省台州市中西部,是永…

西藏那曲双湖县发生3.6级地震 震源深度10公里

据中国地震台网正式测定,6月2日12时32分在西藏那曲市双湖县发生3.6级地震,震源深度10公里,震中位于北纬33.63度,东经89.36度。震中5公里范围内平均海拔约5344米。根据中国地震台网速报目录,震中周边200公里内近5年来共发生了70次3级以上地震,其中最大一次是2021年3月30日…

太原一路虎车在酒吧门口横冲直撞 警方已介入调查

6月2日凌晨4时许,有网友发帖称山西省太原市发生了一起越野车冲撞事件。当天上午,太原警方表示已接到报警并正在调查。根据网友发布的视频,这起事件发生在太原市小店区一商家门口。视频中一辆路虎越野车在前进和倒退时有冲撞物品的行为,路人纷纷避让,有人试图拉开路虎车门。…

苏州一医院医生被停工 误操作引发患者投诉

近日,苏州市立医院东区发生了一起B超检查项目的误操作事件。5月30日,患者王女士因身体不适前往医院就诊,医生开具了腹部B超检查单。然而,在实际操作中,超声科医生却误将其操作成阴道B超。这一错误在王女士察觉后才被发现。她询问项目名称时,实习医生仅背对回应“看错了”…

舟山多个海岛游客“被困” 当地回应 天气影响航班调整

6月1日和6月2日,一些在舟山海岛的游客发帖称,由于没有航班离岛,自己被困在海岛上。这些发帖者包括东极岛、枸杞岛等海岛的游客。据网友发布的图片显示,6月1日,东极海运发布提示:因受海面风浪影响,船舶无法航行,当天庙子湖至沈家门9:20、10:00航班停航,已购买该时段船票…

广铁计划加开列车321列 应对返程高峰

6月2日,端午小长假最后一天,广铁迎来返程客流高峰,旅客纷纷踏上归途。当天预计发送旅客237.3万人次,较去年增长9.3%。整个假期期间,旅客运输总体平稳有序。为满足出行需求,广铁集团优化调整运力,通过加开图外列车、动车组重联、增加夜间高铁等方式提升运力。6月2日计划加…

热刺决定解雇波斯特科格鲁,新主帅人选曝光 弗兰克成热门接班人

北京时间6月1日,热刺决定解雇波斯特科格鲁。托马斯-弗兰克成为热刺新教练的接班人选之一,马尔科-席尔瓦也在考虑名单上。此前法国媒体报道称,托特纳姆热刺本周与托马斯-弗兰克进行了直接接触,双方讨论了夏季转会计划和一些转会目标。责任编辑:zhangxiaohua

北京铁路抵京旅客75.8万 端午假期返程高峰

6月2日是端午假期的最后一天,中国铁路北京局预计发送旅客137万人次。其中,北京地区预计发送51.4万人次、到达75.8万人次。中午11点半,北京站迎来了一波出站客流高峰,旅客出站后迅速前往地铁站和出租车调度站。尽管短时间内出现客流高峰,但因地铁进站闸机全面开启,容纳能力…

章子怡晒照祝儿女节日快乐 陪伴是最好的礼物

6月1日,章子怡在社交平台上晒出女儿和儿子的照片,祝他们儿童节快乐。她写道:“陪伴孩子们的每一天都是上天的恩赐……陪伴就是给孩子们最好的礼物。节日快乐我的孩子,愿你们的童年如彩虹般绚烂,健康快乐地成长。”网友们纷纷留言表示,醒醒越来越像妈妈了。2023年10月23日…

郑钦文闯进法网8强 拿下359万奖金 鏖战三盘胜出

北京时间6月1日晚,法国网球公开赛1/8决赛中,郑钦文以7-6(5)、1-6、6-3战胜萨姆索诺娃,首次闯入法网8强,并获得430积分和44万欧元奖金。首盘比赛中,双方表现平稳,比分交替上升。进入中段后,两人互相破发,比赛变得越来越激烈,最终进入抢七局。在抢七局中,郑钦文表现出…

为中国高速列车发展护航 中南大学团队的创新与坚守

高铁已成为许多旅客出行的首选,但鲜为人知的是,高速列车流线型外形及碰撞吸能结构的设计背后,是中南大学轨道交通空气动力与碰撞安全技术创新团队的辛勤付出。我国首个准高速列车项目设立之初,长沙铁道学院(现中南大学)的几名青年教师敏锐地意识到空气动力学在高速列车发…

鸿蒙仓颉语言开发教程:自定义弹窗

假期第一天&#xff0c;祝大家端午节快乐。昨天观看了时代旗舰尊界S800的发布&#xff0c;不得不感慨这车真好啊&#xff5e; 放假闲来无事&#xff0c;继续跟大家分享仓颉语言的开发教程&#xff0c;今天介绍一下自定义弹窗。 仓颉语言中的自定义弹窗和ArkTs类似&#xff0c…

shp转3d tiles在cesium渲染楼宇白膜

shp文件一般做gis的人都知道它是干嘛的&#xff0c;它是一种地理信息系统矢量数据格式&#xff0c;主要用于存储地理空间数据。但是在cesium中&#xff0c;通过Cesium3DTileset渲染白膜只能渲染3d tiles文件格式。所以我们需要工具去将shp文件转换成3d tiles格式。 我是使用的…

郑钦文请球童用帽子将蜜蜂送离场地 法网8强之路

北京时间6月1日晚,法国网球公开赛1/8决赛中,郑钦文以7-6(5)、1-6、6-3战胜萨姆索诺娃,首次闯入法网8强。她还获得了430积分和44万欧元奖金(约合人民币359万元)。首盘比赛中,双方开局平稳,比分交替上升。进入中段后,两人互相破发,比赛变得越来越激烈,最终进入抢七局…

俄版珍珠港?俄军事博主呼吁报复 乌无人机袭击引发紧张局势

就在俄乌定于6月2日举行的第二轮直接谈判前夕,俄罗斯境内发生了一系列袭击事件。当地时间6月1日,俄罗斯境内有五个空军基地遭遇大规模无人机袭击,乌克兰安全局宣称对此负责。这是乌军自俄乌冲突爆发以来对俄领土发动的最具渗透性的袭击之一。俄罗斯国防部认定这是一次“恐怖…

HarmonyOS鸿蒙开发,Text组件作为容器使用(ImageSpan/Span)快速掌握

Text作为容器使用的时候&#xff0c;里面可以使用ImageSpan存放图片&#xff0c;Span用来存放文字 文本显示 (Text/Span)-使用文本-UI开发 (ArkTS声明式开发范式)-ArkUI&#xff08;方舟UI框架&#xff09;-应用框架 - 华为HarmonyOS开发者 例如&#xff1a;&#xff08;提供给…

鸿蒙HarmonyOS 5.0开发实战:长列表滑动到指定列表项动效实现案例

往期鸿蒙5.0全套实战文章必看&#xff1a;&#xff08;文中附带鸿蒙5.0全栈学习资料&#xff09; 鸿蒙开发核心知识点&#xff0c;看这篇文章就够了 最新版&#xff01;鸿蒙HarmonyOS Next应用开发实战学习路线 鸿蒙HarmonyOS NEXT开发技术最全学习路线指南 鸿蒙应用开发实战…

【HarmonyOS 5】App Linking 应用间跳转详解

目录 什么是 App Linking 使用场景 工作原理 如何开发 1.开通 App Linking 2.确定域名 3.服务端部署 applinking.json 文件 4.AGC绑定域名 5.项目配置 6.组装聚合链接 7.解析聚合链接中的参数 其他 如何获取应用ID 如何在应用未安装时点击链接跳转至应用市场 什…

HarmonyOS Next 用户通知服务Notification Kit介绍与实战

1、用户通知服务Notification Kit介绍 Notification Kit&#xff08;用户通知服务&#xff09;为开发者提供本地通知发布通道&#xff0c;开发者可借助Notification Kit将应用产生的通知直接在客户端本地推送给用户&#xff0c;本地通知根据通知类型及发布场景会产生对应的铃声…

HarmonyOS NEXT(九) :图形渲染体系

HarmonyOS NEXT&#xff08;九&#xff09; &#xff1a;图形渲染体系 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;可以分享一下给大家。点击跳转到网站。 https://www.captainbed.cn/ccc 文章目录 HarmonyOS NEXT&#xff0…