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

PyQt5桌面应用开发(16):定制化控件-QPainter绘图

本文目录

  • PyQt5桌面应用系列
  • 画画图,喝喝茶
  • QPainter和QPixmap
    • QPixmap
    • QPainter
    • 绘制事件
  • 一个魔改的QLabel
    • Canvas类
    • 主窗口
    • 主程序:
  • 总结

PyQt5桌面应用系列

  • PyQt5桌面应用开发(1):需求分析
  • PyQt5桌面应用开发(2):事件循环
  • PyQt5桌面应用开发(3):并行设计
  • PyQt5桌面应用开发(4):界面设计
  • PyQt5桌面应用开发(5):对话框
  • PyQt5桌面应用开发(6):文件对话框
  • PyQt5桌面应用开发(7):文本编辑+语法高亮与行号
  • PyQt5桌面应用开发(8):从QInputDialog转进到函数参数传递
  • PyQt5桌面应用开发(9):经典布局QMainWindow
  • PyQt5桌面应用开发(10):界面布局基本支持
  • PyQt5桌面应用开发(11):摸鱼也要讲基本法,两个字,16
  • PyQt5桌面应用开发(12):QFile与线程安全
  • PyQt5桌面应用开发(13):QGraphicsView框架
  • PyQt5桌面应用开发(14):数据库+ModelView+QCharts
  • PyQt5桌面应用开发(15):界面动画
  • PyQt5桌面应用开发(16):定制化控件-QPainter绘图

本文完整源代码@gitcode.net

画画图,喝喝茶

程序员的日子,还是挺悠闲。只要快捷键设置得好,摸鱼不要太简单。话说这天,本人文青病又犯了,就想着整点艺术。虽然艺术细胞不多……

先上艺术。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

不过跟我儿子比,还是差点:

在这里插入图片描述
在这里插入图片描述

QPainter和QPixmap

前面都是胡扯,这里其是想写的是PyQt5中自定义控件的技术。对于PyQt5而言,所有的控件,都把自己作为一种bitmap来绘制,只有理解了这一点,才能说掌握了自定义控件。

QPixmap

计算机图像学里所有的图形都是像素点阵列,每个像素点都有自己的颜色,这种点阵列就是bitmap。bitmap也可以序列化成图像文件,不同的编码格式对应不同格式的文件,常见的有bmp、jpg、png等。

PyQt5中,所有的控件都是继承自QWidget,而QWidget继承自QPaintDevice,QPaintDevice是一个抽象类,它定义了一些绘制的接口。QPixmap和QImage都继承自QPaintDevice,所以QPixmap和QImage都可以作为绘制的目标。在Device之上,又有QPainter,QPainter是一个绘制的工具,它可以把图形绘制到QPaintDevice上。

控件的pixmap()函数都返回一个QPixmap对象,这个对象可以用来绘制控件的内容。

QPainter

QPainter是一个绘制工具,它可以把图形绘制到QPaintDevice上。QPainter的绘制函数有很多,这里只介绍几个常用的:

  • drawPoint(x, y):绘制一个点
  • drawLine(x1, y1, x2, y2):绘制一条直线
  • drawRect(x, y, width, height):绘制一个矩形
  • drawEllipse(x, y, width, height):绘制一个椭圆
  • drawArc(x, y, width, height, startAngle, spanAngle):绘制一个圆弧
  • drawPie(x, y, width, height, startAngle, spanAngle):绘制一个扇形
  • drawPolygon(points):绘制一个多边形
  • drawText(x, y, text):绘制一段文本
  • drawPixmap(x, y, pixmap):绘制一个图像
  • drawImage(x, y, image):绘制一个图像
  • fillRect(x, y, width, height, color):用color颜色填充一个矩形

此外,QPainter还提供了函数设置画图的笔触。

  • pen():获取当前的画笔
  • setPen(pen):设置画笔

这些函数,提供了多种不同的重载形式,具体查看文档就行。

绘制事件

QWidget的paintEvent()函数是绘制事件,当控件需要绘制的时候,就会调用这个函数。paintEvent()
函数的参数是QPaintEvent,它包含了绘制的区域,可以通过rect()函数获取。

paintEvent()函数的实现,一般是先创建一个QPainter对象,然后调用QPainter的绘制函数,最后销毁QPainter对象。

def paintEvent(self, event):painter = QPainter(self)painter.drawPixmap(self.rect(), self.pixmap)painter.end()

QPainter提供了一对函数begin()和end()来管理绘制的生命周期,这两个函数是成对出现的,一般都是在begin()
函数中创建QPainter对象,然后在end()
函数中销毁QPainter对象。但是,QPainter的构造函数也可以直接传入一个QPaintDevice对象,这样就不需要调用begin()。但是end()
函数一般是需要自行调用的。

基本的内容就是这些,比较简单,接下来增加一点点细节。

一个魔改的QLabel

我们选择一个QLabel控件作为父类,定义一个Canvas类。在Canvas中,提供鼠标绘图的功能,所有的图形都是花在QLabel的pixmap()上。

希望提供的功能如下:

  • 鼠标绘制图形
  • 设置绘制的颜色
  • 设置线条粗细
  • 鼠标喷涂
  • 喷涂的过程增加一个框(框有不同的形状)
  • 保存绘制的图形
  • 清楚绘图区

界面的设计如下:

在这里插入图片描述

  • 下方工具栏:颜色选择,包括增加自定义颜色
  • 上方工具栏:颜色、保存之外其它所有交互功能

Canvas类

Canvas类继承自QLabel,它的构造函数中,设置了一些属性,包括:

  • setMouseTracking(False):设置鼠标跟踪,如果设置为True,那么鼠标移动事件就会被触发,否则只有鼠标按下和释放事件才会被触发。
  • last_x, last_y:记录鼠标的上一个位置,用于绘制直线。
  • pen_color:记录当前的画笔颜色。
  • is_spray:记录是否是喷涂模式。
  • gauss_size:喷涂的大小。
  • shape_type:记录当前的绘制形状。
  • is_rotate:形状是否旋转
  • is_gauss_sum_up:是否用高斯叠加函数形成一个特殊笔刷

类中间定义了一个enum,用于记录绘制的形状,包括:

  • NONE:无
  • RECT:矩形
  • CIRC:圆形
  • TRI:三角形
  • HEX:六角形

相应地还定义了一系列槽函数。重要的功能在重载的几个函数中实现。

  • def resizeEvent(self, a0: QResizeEvent) -> None:
  • def mouseReleaseEvent(self, ev: QMouseEvent) -> None:
  • def mousePressEvent(self, ev: QMouseEvent) -> None:
  • def mouseMoveEvent(self, e: QMouseEvent):

resizeEvent()
函数在控件大小改变的时候被调用,这里我们在这个函数中重新设置pixmap的大小,保证pixmap的大小和控件大小一致。mousePressEvent和mouseReleaseEvent处理鼠标按下和释放事件,mouseMoveEvent处理鼠标移动事件。

最后是一个功能函数把QPixamp保存为图片和内部函数绘制喷涂。

class Canvas(QLabel):class ShapeType:NONE = 0RECT = 1CIRC = 2TRI = 3HEX = 4def __init__(self, parent=None):super(Canvas, self).__init__(parent)self.last_x, self.last_y = None, Noneself.pen_color = QColor(Qt.black)self.setMouseTracking(False)self.is_spray = Falseself.gauss_size = 10self.gauss_density = 100self.shape_type = self.ShapeType.NONEself.is_rotate = Falseself.angle = Noneself.line_width = 4self.gauss_sum_up = False@pyqtSlot(bool)def set_gauss_sum_up(self, b: bool):self.gauss_sum_up = b@pyqtSlot(int)def set_line_width(self, w):self.line_width = w@pyqtSlot(int)def set_gauss_size(self, s):self.gauss_size = s@pyqtSlot(int)def set_gauss_density(self, d):self.gauss_density = d@pyqtSlot(bool)def set_rotate(self, b: bool):self.is_rotate = b@pyqtSlot(int)def set_shape_type(self, shape_type: ShapeType):self.shape_type = shape_type@pyqtSlot(QColor)def set_pen_color(self, c):self.pen_color = QColor(c)@pyqtSlot(bool)def toggle_spray(self, b: bool):self.is_spray = b@pyqtSlot()def clear(self) -> None:self.pixmap().fill(Qt.white)self.update()def resizeEvent(self, a0: QResizeEvent) -> None:pixmap = self.pixmap()if pixmap:self.setPixmap(pixmap.scaled(a0.size()))else:pixmap = QPixmap(a0.size())pixmap.fill(Qt.white)self.setPixmap(pixmap)def mouseReleaseEvent(self, ev: QMouseEvent) -> None:self.last_x, self.last_y = None, Nonedef mousePressEvent(self, ev: QMouseEvent) -> None:self.last_x, self.last_y = ev.x(), ev.y()if self.is_spray:self._spray(ev.x(), ev.y(), QPainter(self.pixmap()))self.update()def mouseMoveEvent(self, e: QMouseEvent):painter = QPainter(self.pixmap())p = painter.pen()p.setColor(self.pen_color)p.setWidth(self.line_width)painter.setPen(p)if self.is_spray:self._spray(e.x(), e.y(), painter)else:painter.drawLine(self.last_x, self.last_y, e.x(), e.y())painter.end()self.update()self.last_x, self.last_y = e.x(), e.y()def save_png(self):fid, _ = QFileDialog.getSaveFileName(self, 'Save PNG', 'canvas.png', 'PNG (*.png)')if fid:self.pixmap().save(fid, 'PNG', 100)def _spray(self, x, y, painter):p = painter.pen()p.setWidth(1)p.setColor(self.pen_color)painter.setPen(p)painter.translate(x, y)# draw shape in local coordinatesif self.is_rotate:self.angle = random.randrange(0, 360)painter.rotate(self.angle)if self.shape_type == self.ShapeType.RECT:angle = random.randrange(0, 360)painter.drawRect(QRectF(- self.gauss_size, - self.gauss_size, 2 * self.gauss_size, 2 * self.gauss_size))if self.shape_type == self.ShapeType.CIRC:painter.drawEllipse(QPointF(0, 0), self.gauss_size, self.gauss_size)if self.shape_type == self.ShapeType.TRI or self.shape_type == self.ShapeType.HEX:painter.drawPolygon(QPolygonF([QPointF(- math.sqrt(3) * self.gauss_size, self.gauss_size),QPointF(+ math.sqrt(3) * self.gauss_size, self.gauss_size),QPointF(0, - self.gauss_size * 2.0)]))if self.shape_type == self.ShapeType.HEX:painter.drawPolygon(QPolygonF([QPointF(- math.sqrt(3) * self.gauss_size, - self.gauss_size),QPointF(+ math.sqrt(3) * self.gauss_size, - self.gauss_size),QPointF(0, self.gauss_size * 2.0)]))if self.is_rotate:painter.rotate(-self.angle)xi, yi = 0, 0for i in range(self.gauss_density):if self.gauss_sum_up:xi += random.gauss(0, self.gauss_size / 3.0)yi += random.gauss(0, self.gauss_size / 3.0)else:xi, yi = random.gauss(0, self.gauss_size / 3.0), random.gauss(0, self.gauss_size / 3.0)painter.drawPoint(QPointF(xi, yi))# back to global coordinatespainter.translate(-x, -y)

主窗口

主窗口要构造所有的界面元素,并提供保存按键组合的响应。

class MainWindow(QMainWindow):def __init__(self):super(MainWindow, self).__init__()self.toolbar_button_width = 30self.canvas = Canvas()self.setCentralWidget(self.canvas)self.palette_widget = QToolBar(self)self.palette_widget.setWindowTitle('Palette')self.current_color = QLabel()self.current_color.setFixedWidth(self.toolbar_button_width)self.current_color.setStyleSheet('background-color: #000000')self.palette_widget.addWidget(self.current_color)add_color = QPushButton("新")add_color.setFixedWidth(self.toolbar_button_width)add_color.clicked.connect(self.pick_color)self.palette_widget.addWidget(add_color)self.palette_widget.addSeparator()for color in COLORS:button = QPaletteButton(color, self.palette_widget, self.toolbar_button_width)self.palette_widget.addWidget(button)button.clicked.connect(partial(self.canvas.set_pen_color, QColor(color)))button.clicked.connect(partial(self.current_color.setStyleSheet, f'background-color: {color}'))self.addToolBar(Qt.BottomToolBarArea, self.palette_widget)self.palette_widget.setMovable(False)self.pen_style = QToolBar(self)self.pen_style.setWindowTitle('Pen Style')checkbox = QCheckBox('喷涂', self.pen_style)checkbox.clicked.connect(self.canvas.toggle_spray)sumup = QCheckBox('高斯叠加', self.pen_style)sumup.clicked.connect(self.canvas.set_gauss_sum_up)size_tunner = QSpinBox(self.pen_style)size_tunner.setMinimum(1)size_tunner.setMaximum(200)size_tunner.setValue(50)size_tunner.valueChanged.connect(self.canvas.set_gauss_size)size_tunner.setSingleStep(1)size_tunner.setFixedWidth(100)density_tunner = QSpinBox(self.pen_style)density_tunner.setMinimum(0)density_tunner.setMaximum(5000)density_tunner.setValue(500)density_tunner.valueChanged.connect(self.canvas.set_gauss_density)density_tunner.setSingleStep(10)density_tunner.setFixedWidth(100)clear_button = QPushButton('Clear', self.pen_style)clear_button.clicked.connect(self.canvas.clear)clear_button.setStyleSheet('background-color: #ff0000; color: #ffffff;')self.pen_style.addWidget(clear_button)self.pen_style.addSeparator()self.pen_style.addWidget(checkbox)self.pen_style.addWidget(sumup)self.pen_style.addSeparator()self.pen_style.addWidget(QLabel('喷涂大小:'))self.pen_style.addWidget(size_tunner)self.pen_style.addSeparator()self.pen_style.addWidget(QLabel('喷涂数目:'))self.pen_style.addWidget(density_tunner)self.outline = QComboBox(self.pen_style)self.outline.addItem("无")self.outline.addItem("方形")self.outline.addItem("圆形")self.outline.addItem("三角形")self.outline.addItem("六角形")self.outline.currentIndexChanged.connect(self.canvas.set_shape_type)self.pen_style.addSeparator()self.pen_style.addWidget(QLabel('边框:'))self.pen_style.addWidget(self.outline)is_rotate = QCheckBox('旋转', self.pen_style)is_rotate.clicked.connect(self.canvas.set_rotate)is_rotate.setChecked(False)self.pen_style.addWidget(is_rotate)self.pen_style.addSeparator()self.pen_style.addWidget(QLabel('线条宽度:'))self.pen_style.addSeparator()line_width = QSpinBox(self.pen_style)line_width.setMinimum(1)line_width.setMaximum(10)line_width.setValue(4)line_width.valueChanged.connect(self.canvas.set_line_width)line_width.setSingleStep(1)self.pen_style.addWidget(line_width)self.pen_style.setMovable(False)self.addToolBar(Qt.TopToolBarArea, self.pen_style)@pyqtSlot()def pick_color(self):color = QColorDialog.getColor()if color.isValid():button = QPaletteButton(color.name(), self.palette_widget, self.toolbar_button_width)self.palette_widget.addWidget(button)button.clicked.connect(partial(self.canvas.set_pen_color, color))button.clicked.connect(partial(self.current_color.setStyleSheet, f'background-color: {color.name()}'))button.clicked.emit()# resize the palette widget to fit all the buttonsself.palette_widget.resize(self.palette_widget.sizeHint())def keyPressEvent(self, ev: QKeyEvent) -> None:if ev.matches(QKeySequence.Save):self.canvas.save_png()

这里的代码乏善可陈,唯一好玩的是那个颜色选择界面。

COLORS = sorted({'#000000', '#808080', '#800000', '#808000', '#008000', '#008080', '#000080', '#800080', '#808040', '#004040','#004080', '#0000ff', '#004080', '#0080ff', '#0040ff', '#0080c0', '#00ffff', '#00ff00', '#00ff80', '#00ffbf','#00ffff', '#00bfff', '#00bfbf', '#00b080', '#00bf80', '#00b040', '#00bf40', '#00bf00', '#00ff40', '#00ffbf','#00ffff', '#80ff00', '#80ff80', '#80ffbf', '#80ffff', '#80bfff', '#80bfbf', '#80b080', '#80bf80', '#80b040','#80bf40', '#80bf00', '#80ff40', '#80ffbf', '#80ffff', '#bf0000', '#bf0080', '#bf0080', '#bf8000', '#bf8040','#bf8080', '#bf80c0', '#bf80ff', '#bf40ff', '#bf00ff', '#bf00bf', '#bf0080', '#bf0040', '#bf0000', '#bf4000','#bf4040', '#bf4080', '#bf40c0', '#bf40ff', '#bf00ff', '#bf00bf', '#bf0080', '#bf0040', '#bf0000', '#bf4000','#bf4040', '#bf4080', '#bf40c0', '#bf40ff', '#bf00ff', '#bf00bf', '#bf0080', '#bf0040', '#bf0000', '#bf4000','#bf4040', '#bf4080', '#bf40c0', '#bf40ff', '#bf00ff', '#bf00bf', '#bf0080', '#bf0040', '#bf0000', '#bf4000','#bf4040', '#bf4080', '#bf40c0', '#bf40ff', '#bf00ff', '#bf00bf', '#bf0080', '#bf0040', '#bf0000', '#bf4000','#bf4040', '#bf4080', '#bf40c0', '#bf40ff', '#bf00ff', '#bf00bf', '#bf0080', '#bf0040', '#bf0000', '#bf4000','#bf4040', '#bf4080', '#00ff00', '#00ff80', '#00ffbf', '#00ffff', '#00bfff', '#00bfbf', '#00b080', '#00bf80','#00b040', '#00bf40', '#00bf00', '#00ff40', '#00ffbf', '#00ffff', '#80ff00', '#80ff80', '#80ffbf', '#80ffff','#80bfff', '#80bfbf', '#80b080', '#80bf80', '#80b040', '#80bf40', '#80bf00', '#80ff40', '#80ffbf', '#80ffff','#bf0000', '#bf0080', '#bf0080', '#bf8000', '#bf8040', '#bf8080', '#bf80c0', '#bf80ff', '#bf40ff', '#bf00ff','#bf00bf', '#bf0080', '#ffff00', '#ffff80', '#ffffbf', '#ffffff', '#bfffff', '#bfbfbf', '#bf8080', '#bfbf80','#bf4040', '#bfbf40', '#bf0000', '#bfbf00', '#bf00bf', '#bfbfbf', '#bf8080', '#bfbf80'})class QPaletteButton(QPushButton):def __init__(self, color, parent=None, size=24):super(QPaletteButton, self).__init__(parent)self.setFixedSize(size, size)self.setStyleSheet(f'background-color: {color}')

这里就是随便写了一堆颜色,然后用一个按钮的子类来实现,这样就可以直接用按钮的clicked信号来实现颜色的选择了。

主程序:

if __name__ == '__main__':app = QApplication(sys.argv)window = MainWindow()window.setWindowTitle("Painter")window.resize(1400, 800)window.show()sys.exit(app.exec_())

总结

这里面需要注意的技术要素包括:

  1. 信号与槽的使用
  2. 事件处理,特别是鼠标事件,按下、释放、移动等
  3. 画图的基本原理,包括画笔、画刷、画布等
  4. 画图中,我们用了一个移动的技术,把画布移动到一个位置,以那个位置为0点画图,可以转动,然后移动回去。

Canvas的resizeEvent实际上承担了两个功能:初始创建的时候,会调用resizeEvent,然后在resize的时候也会调用resizeEvent,所以我们需要在resizeEvent里面做一些初始化的工作,比如创建画布,然后在resize的时候,我们需要重新创建画布,然后把画布的内容复制到新的画布上面,然后删除旧的画布。

相关文章:

PyQt5桌面应用开发(16):定制化控件-QPainter绘图

本文目录 PyQt5桌面应用系列画画图,喝喝茶QPainter和QPixmapQPixmapQPainter绘制事件 一个魔改的QLabelCanvas类主窗口主程序: 总结 PyQt5桌面应用系列 PyQt5桌面应用开发(1):需求分析 PyQt5桌面应用开发(2…...

spring5源码篇(9)——mybatis-spring整合原理

spring-framework 版本:v5.3.19 spring和mybatis的整合无非主要就是以下几个方面: 1、SqlSessionFactory怎么注入? 2、Mapper代理怎么注入? 3、为什么要接管mybatis事务? 文章目录 一、SqlSessionFactory怎么注入SqlSe…...

为什么需要防雷接地,防雷接地的作用是什么

为什么需要电气接地? 您是否曾经在工作条件下使用任何电器时接触过电击?几乎每个人的答案都是肯定的,有时这些电击是轻微的,但有时会对电气和电子设备造成损坏,并可能危及生命。为防止对人的生命和电器造成任何损害&a…...

如何应用金字塔模型提高结构化表达能力

看一下结构化表达的定义: 结构化表达:是基于结构化思维,理清事物整理与部分之间关系、换位思考后,进行简洁、清晰和有信服力的表达,是一种让受众听得明白、记得清楚、产生认同的精益沟通方式。 结构化表达的基本原则是…...

2023年系统分析师考前几页纸

企业战略规划是用机会和威胁评价现在和未来的环境,用优势和劣势评价企业现状,进而选择和确定企业的总体和长远目标,制定和抉择实现目标的行动方案。信息系统战略规划关注的是如何通过该信息系统来支撑业务流程的运作,进而实现企业的关键业务目标,其重点在于对信息系统远景…...

openwrt-安装NGINX

openwrt-安装NGINX 介绍 OpenWrt 是一个用于嵌入式设备的开源操作系统。它基于 Linux 内核,并且主要被设计用于路由器和网络设备。 OpenWrt 的主要特点包括: 完全可定制:OpenWrt 提供了一个完全可写的文件系统,用户可以自定义设…...

Linux安装MongoDB数据库并内网穿透在外远程访问

文章目录 前言1.配置Mongodb源2.安装MongoDB数据库3.局域网连接测试4.安装cpolar内网穿透5.配置公网访问地址6.公网远程连接7.固定连接公网地址8.使用固定公网地址连接 转发自CSDN cpolarlisa的文章:Linux服务器安装部署MongoDB数据库 - 无公网IP远程连接「内网穿透…...

flutter系列之:使用AnimationController来控制动画效果

文章目录 简介构建一个要动画的widget让图像动起来总结 简介 之前我们提到了flutter提供了比较简单好用的AnimatedContainer和SlideTransition来进行一些简单的动画效果,但是要完全实现自定义的复杂的动画效果,还是要使用AnimationController。 今天我…...

golang 函数调用栈笔记

一个被函数在栈上的情况:(栈从高地址向低地址延伸) 返回地址(函数执行结束后,会跳转到这个地址执行) BP(函数的栈基)局部变量返回值(指的是函数返回值,eg&am…...

云端一体助力体验升级和业务创新

随着音视频和AI技术的发展,在满足用户基础体验和需求情况下,更极致的用户体验和更丰富的互动玩法,成为各个平台打造核心竞争力的关键。LiveVideoStackCon 2022 北京站邀请到火山引擎视频云华南区业务负责人——张培垒,基于节跳动音…...

【Linux Network】高级IO

目录 前言 五种IO模型 阻塞IO 非阻塞IO 信号驱动IO IO多路转接 异步IO 小结 同步通信 vs 异步通信 阻塞 vs 非阻塞 其他高级IO 非阻塞IO fcntl函数 代码测试 高级IO🌷 前言 IO:所谓的I便是 input,所谓的O便是 output,简单点来说&a…...

Python语言基本控制结构

Python语言基本控制结构包括:条件语句:if、elif、else 循环语句:for、while 跳转语句:break、continue、return 下面是它们的基本用法: 条件语句 if condition1: statement1 elif condition2: statement2 else: stat…...

旅游网站版面设计方案

门户网站的页面设计:采用天蓝色为主色调、以红色、绿色为基调,突出网站的青春活波性。 网站风格尽量简单统一、容易让大多数上网者接受,个性化的网站,再者,网站有主体信息结构及布 word . . . . 局,它是总体…...

sudo unable to open read-only file system”的原因

此错误是由多种原因引起的,包括: 文件系统不一致。文件系统配置错误(/etc/fstab 文件中的错误条目)。由于各种原因(包括突然断电或电缆损坏)导致系统意外或突然关闭。在某些情况下,Windows 的双…...

Dynamics 365 DevOps CI/CD之WebResource

对于D365自身的发布,简单点来说就是Solution的发布,复杂一些会涉及周边集成接口等一系列的发布。如果是单纯的Solution的发布的Azure DevOps商店里有很多工具,比如Power DevOps Tools,这个我之前也有博文转载过相关文章&#xff0…...

Linux常用指令及基础配置

Linux常用指令及基础配置 Linux系统操作指令文件管理指令系统设置相关指令addr2line的运用 vim相关vim配置操作Vim功能操作分屏擦操作删除操作换行符转换操作:文件比较合并操作折叠指令 Linux系统操作指令 文件管理指令 find ./ -iname filename find ./ -name “…...

Linux 服务器上Nvidia相关指令

1、GPU驱动的内存常驻模式 1)操作命令: 确保你具有root或sudo权限,以执行下面的命令。打开终端或命令行界面。运行以下命令来设置GPU驱动的内存常驻模式: nvidia-smi -pm 1这会将GPU驱动程序设置为内存常驻模式。 4. 验证设置是否成功。运…...

ChatGPT的工作原理是什么?

ChatGPT是美国OpenAI研发的聊天机器人程序,2022年11月30日发布。ChatGPT是人工智能技术驱动的自然语言处理工具,它能够通过理解和学习人类的语言来进行对话。 ChatGPT的原理 ChatGPT是一种基于人工智能技术的自然语言生成模型,它能够从大量…...

C++进阶——红黑树

C进阶——红黑树 概念 红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black。 通过 对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出俩 倍&…...

什么是NTFS for Mac?2023新版本如何下载

在NTFS for Mac中包含了多种功能操作,促进软件更好地使用,可以进行全局设置,也可以针对某一各挂载的磁盘进行针对性设置。 本集小编主要向大家介绍它包含的一些基本功能,看看这款mac读写工具能够实现那些功能,全面了解…...

华为云AI开发平台ModelArts

华为云ModelArts:重塑AI开发流程的“智能引擎”与“创新加速器”! 在人工智能浪潮席卷全球的2025年,企业拥抱AI的意愿空前高涨,但技术门槛高、流程复杂、资源投入巨大的现实,却让许多创新构想止步于实验室。数据科学家…...

linux之kylin系统nginx的安装

一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源(HTML/CSS/图片等),响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址,提高安全性 3.负载均衡服务器 支持多种策略分发流量…...

【OSG学习笔记】Day 18: 碰撞检测与物理交互

物理引擎(Physics Engine) 物理引擎 是一种通过计算机模拟物理规律(如力学、碰撞、重力、流体动力学等)的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互,广泛应用于 游戏开发、动画制作、虚…...

VB.net复制Ntag213卡写入UID

本示例使用的发卡器:https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...

【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例

文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...

【2025年】解决Burpsuite抓不到https包的问题

环境:windows11 burpsuite:2025.5 在抓取https网站时,burpsuite抓取不到https数据包,只显示: 解决该问题只需如下三个步骤: 1、浏览器中访问 http://burp 2、下载 CA certificate 证书 3、在设置--隐私与安全--…...

现代密码学 | 椭圆曲线密码学—附py代码

Elliptic Curve Cryptography 椭圆曲线密码学(ECC)是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础,例如椭圆曲线数字签…...

EtherNet/IP转DeviceNet协议网关详解

一,设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络,本网关连接到EtherNet/IP总线中做为从站使用,连接到DeviceNet总线中做为从站使用。 在自动…...

是否存在路径(FIFOBB算法)

题目描述 一个具有 n 个顶点e条边的无向图,该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序,确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数,分别表示n 和 e 的值(1…...

基于 TAPD 进行项目管理

起因 自己写了个小工具,仓库用的Github。之前在用markdown进行需求管理,现在随着功能的增加,感觉有点难以管理了,所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD,需要提供一个企业名新建一个项目&#…...