2024-1-14
Python
datetime(所有平台/所有语言/所有领域)
from datetime import datetime, timedelta, timezone
datetime
可以从很多格式转换为标准的时间格式。时区是独立设置的,这样转换为时间戳就很方便。
def name_to_datetime(name: str) -> datetime:
dt = datetime.strptime(name, "%Y-%m-%d-%H-%M-%S")
tz = timezone(timedelta(hours=8))
dt = dt.replace(tzinfo=tz)
return dt
arg(所有平台/所有语言/所有领域)
import sys
Python 中的参数可以用 sys
模块获取。
if len(sys.argv) > 1:
working_dir = Path(sys.argv[1])
PySide(所有平台/Python+CPP)
from PySide6.QtCore import Qt, QUrl, Slot
from PySide6.QtGui import QFont
from PySide6.QtMultimedia import QMediaPlayer
from PySide6.QtMultimediaWidgets import QVideoWidget
from PySide6.QtWidgets import (
QApplication,
QFrame,
QHBoxLayout,
QLabel,
QMainWindow,
QPushButton,
QSizePolicy,
QSlider,
QSpacerItem,
QVBoxLayout,
QWidget,
)
VSCode 的 Python 插件可以整理 import。
布局、控件、项目(Qt)
一般用的是控件(widget),控件用布局(layout)联系起来,自动调整大小。项目(item)还没怎么用过,但 spacer 是项目而不是控件。
布局的动态修改(Qt)
可以作为最外层的控件可以设置一个布局(setLayout
)。在新建布局时,构造函数直接传入最外层控件,就不用手动调用 setLayout
设置。
布局中可以添加控件(addWidget
)、布局(addLayout
)、项目(addSpacerItem
)。
stretch(Qt)
参见 stackoverflow.com/a/31328541。… stretch 参数均为 0
(默认),则等分。否则非 0 的按比例,0 的按内容。
self.hboxLayout1.addLayout(self.vboxLayout1, stretch=1) # 其他都是 0,vboxLayout1 把剩余空间用完。
QFrame(Qt)
QFrame
可以在内部关联布局。外面就是个框。
QFrame 设置边框颜色(CSS)
参见 www.qtcentre.org/threads/444…
self.frame.setObjectName("frame")
self.frame.setStyleSheet(f"#frame {{ border: 10px solid {color}; }}")
Qt 播放视频(Qt)
from PySide6.QtMultimedia import QMediaPlayer
from PySide6.QtMultimediaWidgets import QVideoWidget
显示、多媒体是分开的模块。
self.videoWidget = QVideoWidget(self)
self.vboxLayout1.addWidget(self.videoWidget, 1)
self.mediaPlayer = QMediaPlayer(self)
self.mediaPlayer.setVideoOutput(self.videoWidget)
self.mediaPlayer.setSource(QUrl.fromLocalFile(self._video_file_path))
2024-1-15
Python
bisect(所有平台/Python)
from bisect import bisect
二分查找。
timedelta(所有平台/Python)
from datetime import timedelta
用 timedelta
表示两个 datetime
的差。
if et is None or t < et:
self._set_frame_color("red")
elif t - et < timedelta(seconds=3):
self._set_frame_color("green")
如果一个时间有时区,一个没有,就不能比较或者相减,转换成时间戳后再操作。
if et is None or t.timestamp() < et.timestamp():
self._set_frame_color("red")
elif t.timestamp() - et.timestamp() < 3.0:
self._set_frame_color("green")
PySide(所有平台/Python+CPP)
AudioOutput(Qt)
from PySide6.QtMultimedia import QAudioOutput, QMediaPlayer
from PySide6.QtMultimediaWidgets import QVideoWidget
要播放声音,必须使用 QAudioOutput
。必须指定父结点,不能是临时的。
self.mediaPlayer = QMediaPlayer(self)
self.mediaPlayer.setVideoOutput(self.videoWidget)
self.mediaPlayer.setAudioOutput(QAudioOutput(self))
2024-1-16
Python
PySide(所有平台/Python+CPP)
blockSignals(Qt)
使用 blockSignals
方法,可以阻止发出信号。可以用在强制 set value 而不触发信号的场景。
pre = self.slider.blockSignals(True)
self.slider.setValue(position)
self.slider.blockSignals(pre)
2024-1-17
Kotlin
Bitmap, Canvas, Matrix(Android/Kotlin+Java)
Android 中,Bitmap
创建后需要用 Canvas
进行绘图,与 Windows 类似。利用 Matrix
可以进行仿射变换。
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Matrix
directBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
rotatedBitmap = Bitmap.createBitmap(height, width, Bitmap.Config.ARGB_8888)
val canvas = Canvas(rb)
val matrix = Matrix().apply {
postRotate(270f)
postTranslate(0f, rb.height.toFloat())
canvas.drawBitmap(db, matrix, null)
Bitmap
可以从 Buffer
中拷贝图像,也可以把图像拷贝到 Buffer
中。
val byteBuffer = ByteBuffer.wrap(data)
byteBuffer.int // Skip the first 4 bytes.
db.copyPixelsFromBuffer(byteBuffer)
rb.copyPixelsToBuffer(ByteBuffer.wrap(frd))
2024-1-18
Python
Matplotlib(所有平台/Python)
Matplotlib 可以使用 Qt 作为后端。如果项目中已经存在 Qt,要先导入 Qt,再导入 Matplotlib。
from PySide6.QtCore import QPoint, QRect, Qt, QUrl, Slot
from PySide6.QtGui import QFont, QPainter, QPen
from PySide6.QtMultimedia import QAudioOutput, QMediaPlayer
from PySide6.QtMultimediaWidgets import QVideoWidget
from PySide6.QtWidgets import (
QApplication,
QFrame,
QHBoxLayout,
QLabel,
QMainWindow,
QPushButton,
QSizePolicy,
QSlider,
QSpacerItem,
QVBoxLayout,
QWidget,
)
if True:
from matplotlib.backends.backend_qtagg import FigureCanvasQTAgg
from matplotlib.figure import Figure
使用 Qt 作为后端时,Matplotlib 有一个显示控件,名为 FigureCanvasQTAgg
,它是一个 Matplotlib 的 Canvas,也是一个 Qt 的 QWidget
。初始化时,需要将它要绘制的 Figure
作为参数传入。Figure
和 Canvas
的关系基本上类似于昨天写的 Bitmap
和 Canvas
的关系。
self.figure = Figure()
self.ax = self.figure.add_subplot(111)
self.canvas = FigureCanvasQTAgg(self.figure)
layout.addWidget(self.canvas)
如果修改 Figure
后没有窗口大小改变这样的事件提醒 FigureCanvasQTAgg
重绘,则需要手动调用 Canvas
的 draw
方法。
self.ax.clear()
self.ax.plot(self._x[left_idx:right_idx], self._y[left_idx:right_idx])
self.canvas.draw()
2024-1-19
Kotlin
Context(Android/Kotlin+Java)
参见 www.jianshu.com/p/fb0681f5f…
Context 提供了关于环境全局信息的接口,Application、Activity、Service 均是 Context。
Context
有 applicationContext
属性,可以获取当前进程的全局单例 Application Context。如果某个东西的生命周期与进程相关,就用它。
不同的 Context 能力不同,例如 Application 就不允许弹窗。
Swift
简介(Apple/Swift)
用 import
语句导入。用 var
关键字定义变量。注释类似于 C++,但多行注释可嵌套。
import Cocoa
var myString = "Hello, World!"
print(myString)
let
是常量,等效于 Rust 的 let
,Kotlin 的 val
,Go 的 const
。
var
是变量,等效于 Rust 的 let mut
,Kotlin 的 var
,Go 的 var
。
声明语法和 Rust、Kotlin 一样。
可选类型的原理是枚举,和 Rust 一样(None
和 Some(T)
)。写法和 Kotlin 一样,空值的名字和 Go 一样(nil
)。
var myString: String? = nil
断言有值时,和 Kotlin 一样,但是只使用一个 !
。
和 Rust 一样,可以作模式匹配。
if let constantName = someOptional {
statements
}
和 C++ 一样,用 Exp1 ? Exp2 : Exp3
表示三目运算符。
范围循环和 Rust 一样,但是省略号多一个点。
import Cocoa
for index in 1...5 {
print("\(index) 乘于 5 为:\(index * 5)")
}
Swift 的内存模型应该类似于 Rust,因为还有 Arc 啥的。
和 Go 一样,用 func
定义函数。
和大家都不一样,类里面,在 func
前加 mutating
表示可以修改成员。类方法隐含 self
这个名字。
2024-1-20
硬件
I2C
I2C 的地址位的最低位表示读(1)写(0)。当别人明确告诉你一个地址是 7-bit 时,你需要左移一位使用,库的 read
、write
方法可能会自动帮你修改读写位。
参见 www.i2c-bus.org/repeated-st… 的时序中有一个 start 条件和 stop 条件。在 stop 前,允许有多个 start,使得多个批次的操作不会被打断。这在多个主机的系统中有用。Mbed Studio 中的 I2C
类的 repeat
参数可以实现不发送 stop 条件。