vault backup: 2022-09-26 18:49:43

Affected files:
.obsidian/daily-notes.json
.obsidian/plugins/periodic-notes/data.json
.obsidian/templates.json
.obsidian/workspace
01. 個人/02. 專注Study/Android/ADB 取得 APK 的 icon.md
01. 個人/02. 專注Study/Android/ADB.md
01. 個人/02. 專注Study/Android/AOSP.md
01. 個人/02. 專注Study/Android/Android programming.md
01. 個人/02. 專注Study/Android/Ktor.md
01. 個人/02. 專注Study/Android/Service.md
01. 個人/02. 專注Study/Android/Tools.md
01. 個人/02. 專注Study/Android/UI.md
01. 個人/02. 專注Study/C++/C++17.md
01. 個人/02. 專注Study/C++/Class template.md
01. 個人/02. 專注Study/C++/Structured binding declaration.md
01. 個人/02. 專注Study/C++/for_each.md
01. 個人/02. 專注Study/C++/lambda.md
01. 個人/02. 專注Study/C++/lvalue.md
01. 個人/02. 專注Study/C++/move operator.md
01. 個人/02. 專注Study/C++/rvalue.md
01. 個人/02. 專注Study/C++/智慧指標.md
01. 個人/02. 專注Study/RxKotlin/20200207 - Study RxKotlin.md
03. 資料收集/01. Programming/COM/20210726 - COM Interface.md
03. 資料收集/01. Programming/DB/MySQL.md
03. 資料收集/01. Programming/DB/sqlite.md
03. 資料收集/01. Programming/Design Pattern.md
03. 資料收集/01. Programming/FFMPEG/00. Introduction.md
03. 資料收集/01. Programming/FFMPEG/01. Setup.md
03. 資料收集/01. Programming/FFMPEG/FFMpeg.md
03. 資料收集/01. Programming/Flask.md
03. 資料收集/01. Programming/Media Foundation/20210604 - Windows media foundation.md
03. 資料收集/01. Programming/OpenCV.md
03. 資料收集/01. Programming/OpenGL.md
03. 資料收集/01. Programming/Python/argparse.ArgumentParser.md
03. 資料收集/01. Programming/Python/decorator.md
03. 資料收集/01. Programming/Python/logging.md
03. 資料收集/01. Programming/Python/opencv.md
03. 資料收集/01. Programming/Python/subprocess.md
03. 資料收集/01. Programming/Python/threading.md
03. 資料收集/01. Programming/Python/tkinter.md
03. 資料收集/01. Programming/Python/檢測工具.md
03. 資料收集/01. Programming/QT/Dropdown button.md
03. 資料收集/01. Programming/QT/QVariant.md
03. 資料收集/01. Programming/QT/Qt.md
03. 資料收集/01. Programming/UML.md
03. 資料收集/01. Programming/演算法.md
03. 資料收集/99. templates/blogHeader.md
03. 資料收集/99. templates/date.md
03. 資料收集/99. templates/front matter.md
03. 資料收集/99. templates/note.md
03. 資料收集/99. templates/table.md
03. 資料收集/99. templates/thisWeek.md
03. 資料收集/99. templates/日記.md
03. 資料收集/99. templates/讀書筆記.md
03. 資料收集/Hobby/RC.md
03. 資料收集/Hobby/RC/Traxxas Sledge.md
03. 資料收集/Hobby/RC/好盈電變調整中立點.md
03. 資料收集/Hobby/RC/差速器調教教學.md
03. 資料收集/Linux/CLI/cut.md
03. 資料收集/Linux/CLI/scp.md
03. 資料收集/Linux/CLI/timedatectl.md
03. 資料收集/Programming/Qt.md
03. 資料收集/Tool Setup/Hardware/RaspberryPi.md
03. 資料收集/Tool Setup/Software/Chrome.md
03. 資料收集/Tool Setup/Software/Obisidian.md
03. 資料收集/Tool Setup/Software/SublimeText.md
03. 資料收集/Tool Setup/Software/VirtualBox.md
03. 資料收集/Tool Setup/Software/Visual Studio Code.md
03. 資料收集/Tool Setup/Software/Windows Setup.md
03. 資料收集/Tool Setup/Software/Windows Terminal.md
03. 資料收集/Tool Setup/Software/freefilesync.md
03. 資料收集/Tool Setup/Software/vim.md
03. 資料收集/翻牆/V2Ray.md
03. 資料收集/翻牆/Wireguard.md
03. 資料收集/軟體工具/youtube-dl.md
This commit is contained in:
2022-09-26 18:49:43 +08:00
parent 2f312a4575
commit 0a8e11189d
75 changed files with 20 additions and 874 deletions

View File

@@ -1,5 +1,5 @@
{
"folder": "01. Daily",
"folder": "01. 個人/01. Daily",
"format": "YYYY-MM-DD(ddd)",
"template": "02. PARA/03. Resources資源/99. templates/日記"
"template": "03. 資料收集/99. templates/日記"
}

View File

@@ -4,8 +4,8 @@
"hasMigratedWeeklyNoteSettings": false,
"daily": {
"format": "",
"template": "02. PARA/03. Resources資源/99. templates/日記.md",
"folder": "01. Daily",
"template": "03. 資料收集/99. templates/日記.md",
"folder": "01. 個人/01. Daily",
"enabled": true
},
"weekly": {

View File

@@ -1,5 +1,5 @@
{
"folder": "02. PARA/03. Resources資源/99. templates",
"folder": "03. 資料收集/99. templates",
"dateFormat": "YYYY-MM-DD",
"timeFormat": "HH:mm:ss"
}

33
.obsidian/workspace vendored
View File

@@ -7,12 +7,8 @@
"id": "828beb43bb437dd1",
"type": "leaf",
"state": {
"type": "markdown",
"state": {
"file": "03. 資料收集/RaspberryPi.md",
"mode": "source",
"source": true
}
"type": "empty",
"state": {}
}
}
],
@@ -69,7 +65,6 @@
"state": {
"type": "backlink",
"state": {
"file": "03. 資料收集/RaspberryPi.md",
"collapseAll": false,
"extraContext": false,
"sortOrder": "alphabetical",
@@ -85,9 +80,7 @@
"type": "leaf",
"state": {
"type": "outline",
"state": {
"file": "03. 資料收集/RaspberryPi.md"
}
"state": {}
}
}
],
@@ -116,15 +109,15 @@
},
"active": "f69acad103e7f817",
"lastOpenFiles": [
"03. 資料收集/科技/HDR Sensor.md",
"03. 資料收集/軟體工具/IPFS.md",
"03. 資料收集/軟體工具/docker.md",
"03. 資料收集/架站/HTTP Server/Nginx/Reverse Proxy(Layer4).md",
"03. 資料收集/架站/HTTP Server/Nginx.md",
"03. 資料收集/架站/SWAG Reverse proxy.md",
"03. 資料收集/架站/Gitea.md",
"03. 資料收集/架站/Trojan.md",
"03. 資料收集/架站/Storj.md",
"03. 資料收集/架站/03. Trojan.md"
"03. 資料收集/翻牆/V2Ray.md",
"02. 工作/01. Logitech/20210412 - TestCam.md",
"02. 工作/01. Logitech/20210428 - Sega.md",
"02. 工作/01. Logitech/20210512 - Kong.md",
"02. 工作/01. Logitech/20210716 - AutoStation.md",
"02. 工作/01. Logitech/20220601 - Sentinel.md",
"02. 工作/01. Logitech/Logitech.md",
"03. 資料收集/名言佳句.md",
"03. 資料收集/每週外食.md",
"00. Inbox/00. TODO.md"
]
}

View File

@@ -1,2 +0,0 @@
* 好盈電變調整中立點:[【RC】FLYSKY 富斯NB4 遥控器基本功能使用教程_哔哩哔哩_bilibili](https://www.bilibili.com/video/BV1pJ411y7yB/)
* [(28) 陳春期--HB D812 差速器調教教學 - YouTube](https://www.youtube.com/watch?v=dSYQBz3T6gU)

View File

@@ -0,0 +1 @@
[【RC】FLYSKY 富斯NB4 遥控器基本功能使用教程_哔哩哔哩_bilibili](https://www.bilibili.com/video/BV1pJ411y7yB/)

View File

@@ -0,0 +1 @@
[(28) 陳春期--HB D812 差速器調教教學 - YouTube](https://www.youtube.com/watch?v=dSYQBz3T6gU)

View File

@@ -1,734 +0,0 @@
## Prepare
### Windows 10 SDK
下載並安裝[Windows 10 SDK](https://developer.microsoft.com/zh-tw/windows/downloads/windows-10-sdk/),安裝
**Debugging Tools for Windows**就可以了。
![[chrome_20210309_110223_934x685.png]]
然後在QtCreator裡面設置Debugger。
![[NVIDIA_Share_20210309_110738_1920x1080.png]]
### Visual Studio 2017
- ![[Pasted image 20210312144218.png]]
- ![[Pasted image 20210312144242.png]]
- ![[Pasted image 20210312144405.png]]
- ![[Pasted image 20210312144523.png]]
## PRO file 語法
### 導入lib
```
QT += <lib> <lib2>
```
### 導入include path
```
INCLUDEPATH += <INCLUDE_PATH>
```
若使用相對路徑必須相對於makefile生成的路徑。
也可以使用`$$PWD`來生成絕對路徑,例:
```
INCLUDEPATH += $$PWD/../../include
```
> 可以用`message()`來印出變數:`message($$PWD)`
### 導入lib
`-L`指定library path`-l`指定libraray name。例
```
LIBS += -L"../../lib" -lopencv_world320
```
### 指定執行目錄
```
DESTDIR += ../../bin
```
### 指定執行檔檔名
```
TARGET = <NEW_FILENAME>
```
- Import QT pro file into Visual Studio.
- `qmake -tp vc <QT_PROJECT_FILE>`
- 使用VS工具import。
## 基本類別class
### QIODevice
An abstract class that wraps input and output for most devices
### QDataStream
依序寫入的資料也可以依序被讀出來。資料會被編碼過所以用Text editor會看到亂碼。
### QTextStream
可以依序寫入字串也可以依序被讀出來因為寫入的是字串所以用Text editor就可以看到資料。
### QLockFile
創造一個在操作時可以獨佔的檔案。避免race condition的情形。
```cpp
QLockFile lock(fileName() +".lock");
lock.setStaleLockTime(30000);
if(lock.tryLock()) {
...
lock.unlock();
} else {
qInfo() << "Could not lock the file!";
qint64 pid;
QString host;
QString application;
if(lock.getLockInfo(&pid,&host,&application)) {
qInfo() << "The file is locked by:";
qInfo() << "Pid: " << pid;
qInfo() << "Host: " << host;
qInfo() << "Application: " << application;
} else {
qInfo() << "File is locked, but we can't get the info!";
}
}
```
### QtMessageHandler
可以用來重新導向或攔截`qInfo()``qDebug()``qWarning()``qCritical()``qFatal()`這些function
```cpp
const QtMessageHandler QT_DEFAULT_MESSAGE_HANDLER = qInstallMessageHandler(nullptr);
void lhandler(QtMsgType type, const QMessageLogContext &context, const QString &msg) {
QString txt;
switch (type) {
case QtInfoMsg:
txt = QString("Info: %1 in %2").arg(msg);
break;
case QtDebugMsg:
txt = QString("Debug: %1").arg(msg);
break;
case QtWarningMsg:
txt = QString("Warning: %1").arg(msg);
break;
case QtCriticalMsg:
txt = QString("Critical: %1").arg(msg);
break;
case QtFatalMsg:
txt = QString("Fatal: %1").arg(msg);
break;
}
...
(*QT_DEFAULT_MESSAGE_HANDLER)(type, context, msg);
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
qInstallMessageHandler(lhandler);
qInfo() << "This is a info message";
qDebug() << "This is a debug message";
qWarning() << "This is a warning message";
qCritical() << "This is a critical message";
qFatal("THIS IS SPARTA!!!");
return a.exec();
}
```
也可以把這機制封裝在class裡面
```cpp
// logger.h
#ifndef LOGGER_H
#define LOGGER_H
#include <QObject>
#include <QDebug>
#include <QFile>
#include <QDateTime>
#include <QDir>
#include <iostream>
#include <QTextStream>
class logger : public QObject
{
Q_OBJECT
public:
explicit logger(QObject *parent = nullptr);
static bool logging;
static QString filename;
static void attach();
static void handler(QtMsgType type, const QMessageLogContext &context, const QString & msg);
signals:
public slots:
};
#endif // LOGGER_H
```
```cpp
// logger.cpp
#include "logger.h"
QString logger::filename = QDir::currentPath() + QDir::separator() + "log.txt";
bool logger::logging = false;
static const QtMessageHandler QT_DEFAULT_MESSAGE_HANDLER = qInstallMessageHandler(nullptr);
logger::logger(QObject *parent) : QObject(parent)
{
}
void logger::attach()
{
logger::logging = true;
qInstallMessageHandler(logger::handler);
}
void logger::handler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
// Here, write log message to file
(*QT_DEFAULT_MESSAGE_HANDLER)(type, context, msg);
}
```
### Logging category
Logging category可以用來把輸出的log前面加上一個字串以便分類。
```cpp
#include <QCoreApplication>
#include <QDebug>
#include <QLoggingCategory>
//Declare a logging category
Q_DECLARE_LOGGING_CATEGORY(network);
Q_LOGGING_CATEGORY(network, "network");
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
qInfo() << "test"; // stdout: "test"
qInfo(network) << "test"; // stdout: "network: test"
//turn it off
QLoggingCategory::setFilterRules("network.debug=false");
//Will not log
qDebug(network) << This message will not shown;
if(!network().isDebugEnabled()) {
QLoggingCategory::setFilterRules("network.debug=true");
qDebug(network) << "We turned it back on";
}
qDebug(network) << "You see this because you turn the message on";
return a.exec();
}
```
## QThread
1. 繼承自QThread。
2. 重載`run()`
3. 呼叫`start()`來開始thread。
## QWidget
### 設定signal與對應的slot
1. 在class header裡面加入`Q_OBJECT`
2. 在constructor裡呼叫`connect()`來建立對應關係:`connect(SOURCE_OBJECT, SIGNAL(clicked()), DEST_OBJECT, SLOT(close()))`
### Postion
1. `QRect geometry();` 取得x, y, width, height
2. `setGeometry();` 設定x, y, width, height
3. `x()`, `y()`, `width()`, `height()` 單獨取得x, y, width, height
4. `move(x, y);` 只設定x, y
5. `resize(width, height);` 只設定width, height
### Window state
1. `setWindowState(Qt::WindowMaximized);`
1. `Qt::WindowMaximized` -> `showMaximized()`
2. `Qt::WindowMinimized` -> `showMinimized()`
3. `Qt::WindowNoState` -> `showNormal()`
4. `Qt::WindowFullScreen` -> `showFullScreen()`
### Window Style
1. `CustomizeWindowHint()`
2. `setWindowFlags(Qt::WindowCloseButtonHint | Qt::WindowMinimizeButtonHint)`
1. Qt::WindowCloseButtonHint
2. Qt::WindowMinimizeButtonHint
3. `setWindowFlag(Qt::WindowCloseButtonHint, false)` // 取消close按鈕
1. Qt::WindowCloseButtonHint
2. Qt::WindowMinimizeButtonHint
4. 沒有邊框的視窗:`setWindowFlags(Qt::FramelessWindowHint)`
5. 透明背景: `setAttribute(Qt::WA_TranslucentBackground, true)`
6. Style sheet: https://doc.qt.io/qt-5/stylesheet-syntax.html#style-rules
### Layout
- QVBoxLayout
```cpp
QVBoxLayout* pVlayout = new QVBoxLayout();
widget->setLayout(pVlayout);
// Add button to layout
QPushButton* button = new QPushButton("My Button");
pVlayout->addWidget(button);
```
- `setContentsMargin()`設定元與layout的距離
- `setSpacing()`:設定元件與元件之間的距離
- QFormLayout
- Iterate all items
```cpp
QFormLayout* layout = (QFormLayout*)this->layout();
for (int i = 0; i < layout->rowCount(); i++) {
QLayoutItem* item = layout->itemAt(i, QFormLayout::FieldRole);
QWidget* widget = (QWidget*)item->widget();
if (widget) {
QString className = widget->metaObject()->className();
if (className == "QLineEdit") {
QLineEdit* edit = (QLineEdit*)widget;
edit->setText("Text changed");
}
} else {
continue;
}
}
```
#### QSizePolicly
- QSizePolicly::GrowFlag必要時可以超過
- QSizePolicly::ExpandFlag放到最大
- QSizePolicly::ShrinkFlag必要時可以小於建議尺寸
- QSizePolicly::IgnoreFlag忽略
## QLabel
- `QLabel.setTextIneractionFlags()`
## QSlider
### Style
#### groove
```
QSlider::groove {
border: 1px solid #999999;
height: 28px;
background: rgba(155, 155, 155, 200);
border-radius: 10px;
}
```
#### handle
```
QSlider::handle {
border: 1px solid #FF0000;
width: 20px;
margin: -10px 0;
background: rgba(255, 0, 0, 200);
border-radius: 10px;
}
```
#### add-page
```
QSlider::add-page {
background: rgba(255, 0, 0, 200);
}
```
#### sub-page
```
QSlider::add-page {
background: rgba(0, 255, 0, 200);
}
```
![[Pasted image 20210318115725.png]]
## QListWidget
- Insert a QLineEdit
```cpp
QLineEdit* lineEdit = new QLineEdit("A line edit here");
ui->listWidget->setItemWidget(new QListWidgetItem("", ui->listWidget), lineEdit);
```
- Insert a QSpinBox
```
QSpinBox* spinBox = new QSpinBox();
ui->listWidget->setItemWidget(new QListWidgetItem("Test item 5", ui->listWidget), spinBox);
```
### Stylesheet example
```
QTableView {
selection-background-color: qlineargradient(x1: 0, y1: 0, x2: 0.5, y2: 0.5, stop: 0 #FF92BB, stop: 1 white);
}
```
```
QTableView QTableCornerButton::section {
background: red;
border: 2px outset red;
}
```
```
QTableView::indicator:unchecked {
background-color: #d7d6d5
}
```
## QTableWidget
- setColumnCount()
- https://doc.qt.io/qt-5/qtablewidget.html#setColumnCount
- setHorizontalHeaderItem(column_index, new QTableWidgetItem("Header1"))
- https://doc.qt.io/qt-5/qtablewidget.html#setHorizontalHeaderItem
- setColumnWidth(column_index, column_width)
- https://doc.qt.io/qt-5/qtableview.html#setColumnWidth
- Bind Header's event
- `connect(ui.tableWidget->horizontalHeader(), SIGNAL(sectionClicked(int)), this, SLOT(SectionClicked(int)));`
- Style
```
QHeaderView::section:checked{ /* Focus */
background-color: rgba(55, 55, 55,255 );
}
QHeaderView::section:hover{ /* 滑鼠懸停 */
background-color: rgba(85, 10, 10,255 );
}
QTableWidget{
background-color: rgb(27, 122, 239);
alternate-background-color: rgb(26, 81, 232);
color:white;
}
```
## QTreeWidget
- Data create & insert
- `insertTopLevelItem(int index, QTreeWidgetItem*)`
- `addTopLevelItem(QTreeWidgetItem*)`
- `new QTreeWidgetItem(QTreeWidget*)`
- Insert widget
- `void setItemWidget(QTreeWidgetItem* item, int column, QWidget* widget)`
- Iterate items
- `QTreeWidgetItem* topLevelItem(int index) const`
- `int topLevelItemCount() const`
- Get item
- `QList<QTreeItemWidget*> selectedItems() const`
- Style
```
/* 有旁節點,沒有與其他元素相鄰 */
QTreeView::branch:has-siblings:!adjoins-item {
border-image: url(vline.png) 0;
}
/* 有旁節點,與其他元素相鄰 */
QTreeView::branch:has-siblings:adjoins-item {
border-image: url(branch-more.png) 0;
}
/* 沒有子節點,沒有旁節點,與其他元素相鄰 */
QTreeView::branch:!has-children:!has-siblings:adjoins-item {
border-image: url(branch-end.png) 0;
}
/* 收合狀態,有子節點,沒有旁節點 */
QTreeView::branch:closed:has-children:!has-siblings,
/* 收合狀態,有子節點,有旁節點 */
QTreeView::branch:closed:has-children:has-siblings {
border-image: none; image: url(branch-closed.png);
}
/* 打開狀態,有子節點,沒有旁節點 */
QTreeView::branch:open:has-children:!has-siblings,
/* 打開狀態,有子節點,有旁節點 */
QTreeView::branch:open:has-children:has-siblings {
border-image: none;
image: url(branch-open.png);
}
```
## QStatusBar
- `showMessage(QString, int miniSeconds)`: 顯示文字,一段時間後消失
## QToolBar
- `addAction(QIcon, QString)`
- `addAction(QString)`
- `setToolButtonStyle(int)`
## QDockWidget
- https://blog.csdn.net/czyt1988/article/details/51209619
## QJson
- [C++(Qt5)入門範例各種Json範例](https://lolikitty.pixnet.net/blog/post/206254516)
## QFile
Read UTF-8 content from file.
```cpp
QString filename = QString::fromLocal8Bit("testplan中文檔名也可以.json");
QFile file(filename);
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
QTextStream fileRead(&file);
fileRead.setCodec("UTF-8");
QString fileContent = fileRead.readAll();
printf("fileContent = %s\n", fileContent.toLocal8Bit().toStdString().c_str());
file.close();
parseJson(fileContent);
}
else {
printf("Open failed. %s\n", filename.toLocal8Bit().toStdString().c_str());
}
```
## String
### UTF-8
1. 對於n bytes的字元第一個byte的前n個bits是1第n+1個bit是0第2個byte以後都以`10`開頭。
1. 例:
2. 1 byte character: 0x0XXXXXXX。
3. 2 bytes character: 0x110XXXXXX 0x10XXXXXX。
4. 3 bytes character: 0x1110XXXXX 0x10XXXXXX 0x10XXXXXX。
5. 4 bytes character: 0x11110XXXX 0x10XXXXXX 0x10XXXXXX 0x10XXXXXX。
2. 例:
1. 「A」是一個1 byte字元編碼為`0x01000001`。
2. 「Á」是一個2 bytes字元編碼為`0x11000011 0x10000001`。
3. 「好」是一個3 bytes字元編碼為`0x11100101 0x10100101 0x10111101`。
3. [UTF-8 to binary轉換網站](https://onlineutf8tools.com/convert-utf8-to-binary)
2. BOM
1. Big endian: `FE FF`
2. Little endian: `FF FE`
### QString
- 16 bits QChar(unsigned short), UNIDODE 4.0
- `==`: compare string
- `isNull()`: If has a value
- `isEmpty()`: If contained value == ""
- `QString::number()`: 接收一個數字,把數字轉為字串。
- `QString::toInt()`、`QString::toDouble()`把字串轉為Int或Double。
- 讀取UTF-8的字串
```
codec = QTextCodec::codecFromName("UTF-8");
QTextCodec::setCodecForLocale(codec);
```
然後用`QString::fromLocal8Bit()`來讀取字串該字串就會被當作UTF-8來處理。
- `QTextCodec::availableCodecs()`可以列出QT所支援的格式。
- 在Visual Studio中強制文件用UTF-8來存檔`#pragma execution_character_set("UTF-8")`
- 在Visual Studio中預設是以CP950存檔所以字串**都不是**unicode而是**multi-character**所以要從Windows讀進來的字串一律需要使用`QString::fromLocal8Bit("")`而一旦轉為QString之後就是UTF-8了若需要再輸出回Windows則需要`QString.toLocal8Bit().toStdString()`。
- 例:
```cpp
QString filename = QString::fromLocal8Bit("testplan中文檔名也可以.json");
QFile file(filename);
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
QTextStream fileRead(&file);
fileRead.setCodec("UTF-8");
QString fileContent = fileRead.readAll();
printf("fileContent = %s\n", fileContent.toLocal8Bit().toStdString().c_str());
file.close();
parseJson(fileContent);
}
else {
printf("Open failed. %s\n", filename.toLocal8Bit().toStdString().c_str());
}
```
- Visual Studio 2017 debug QString: [调试时直接显示QString的字符值包含windows和linux](https://blog.csdn.net/iamdbl/article/details/78343642)
#### Search
- `QString.indexOf()`
- `QString.lastIndexOf()`
#### Trim
- `QString.chop(5)`去掉結尾的5個字元inplace轉換沒有回傳新字串。
- `QString.left(5)`取最左邊5個字元
- `QString.right(5)`取最右邊5個字元
#### Replace
- `QString.replace("original", "new")`:將"original"替換為"new"。
- 也支援regular expression
#### Split
- `QString.split(",")`:用","把字串分割,並回傳一個`QStringList`。
#### Regular Expression
- `.`匹配任意1個字元
- `+`此類型的匹配字元可以1個以上
- `*`:匹配任意多個字元
- `^`:表示開始位置
- `$`:表示結束位置
- `?`:表示前一個匹配條件不一定要成立
- `[]`:用括號來限制要匹配的字元
## Event
- 如果有特殊需求,可以重載`QWidget::event(QEvent*)`來達成。
### MouseEvent
- Get coordinate of component: `QMouseEvent::x()` & `QMouseEvent::y()`
- Get coordinate of window: `QMouseEvent::windowPos().x()` & `QMouseEvent::windowPos().y()`
- Get coordinate of screen: `QMouseEvent::screenPos().x()` & `QMouseEvent::screenPos().y()`
- `QPoint mapToGlobal(QPoint)`: Translates the widget coordinate pos to global screen coordinates.
- `QCursor::pos().x()` & `QCursor::pos().x()`: 也可以獲得screen coordinate。
- Get click
```
if (mouseEvent->buttons() & Qt::LeftButton) // or Qt::RightButton, Qt::MiddleButton
{
}
```
### MouseCursor
- 設定cursor click的位置`QCursor cursor = QCursor(pixmap, -1, -1)`
- (-1, -1) 表示用cursor中心點為click點
- ( 0, 0) 表示用cursor左上角為click點
- 更換cursor`setCursor(Qt::ArrowCursor)`
### ResizeEvent
- `void resizeEvent(QResizeEvent*)`
## QOpenGLWidget
- `void paintGL()`
- `void initialGL()`
- `void resizeGL(int w, int h)`
## QGLShaderProgram
- `addShaderFromSourceCode`
- `bindAttributeLocation`:設定傳入的變數
- `uniformLocation`:取得變數
## GL概念
### Vertex
#### Coordinate
```
float *vertexData = new float[12] {
1.0f, -1.0f, 0.0f,
-1.0f, -1.0f, 0.0f,
1.0f, 1.0f, 0.0f,
-1.0f, 1.0f, 0.0f,
};
```
### Texture
#### Coordinate
材質座標永遠都在第一象限
```
float* textureVertexData = new float[8] {
1.0f, 0.0f,
0.0f, 0.0f,
1.0f, 1.0f,
0.0f, 1.0f,
};
```
#### 建立材質
- `glGenTextures(1, t);`
- `glBindTexture(GL_TEXTURE_2D, *t);`
- `glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);`
- `glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);`
#### 寫入材質
- `glActiveTexture(GL_TEXTURE0);`
- `glBindTexture(GL_TEXTURE_2D, idY);`
- `glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, pixelW, pixelH, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, plane[0]);`
```
glTexImage2D(
GL_TEXTURE_2D,
0, // 細節預設0
GL_LUMINANCE, // GPU內部格式
pixelW,
pixelH,
0,
GL_LUMINANCE, // Pixel format
GL_UNSIGNED_BYTE, // Data format
plane[0]);
```
- `glTexSubImage2D()`修改texture
- `glUniform1i(textureUniformY, 0);`
- `glDrawArray(GL_TRIANGLE_STRIP, 0, 4);`
## GLSL
### 內建變數
- `gl_FragColor`
### 3種變數類型
- `varying`vertex與shader共用vertex運算完之後傳給shader使用。
- `attribute`vertex使用由`bindAttributeLocation`傳入
- `uniform`由user傳入的資料由`uniformLocation`得到pointer address再由`glUniform1i(textureUniformY, 0)`來設定。
### Vertex Shader
```
attribute vec4 vertexIn;
attribute vec2 textureIn;
varying vec2 textureOut;
void main() {
gl_position = vertexIn;
textureOut = textureIn;
}
```
### Fragment Shader
```
varying vec2 textureOut;
uniform sampler2D texY;
uniform sampler2D texU;
uniform sampler2D texV;
void main() {
vec3 yuv;
vec3 rgb;
yuv.x = textue2D(texY, textureOut).r;
yuv.y = textue2D(texU, textureOut).r - 0.5;
yuv.z = textue2D(texV, textureOut).r - 0.5;
rgb = mat3(
1, 1, 1,
0, -0.39465, 2.03211,
1.13983, -0.5806, 0) * yuv;
gl_FragColor = vec4(rgb, 1);
}
```
### APIs
畫出矩形與材質
- `glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, 0, 0, vertexVertices);`
- `glEnableVertexAttribArray(ATTRIB_VERTEX);`
- `glVertexAttribPointer(ATTRIB_TEXTURE, 2, GL_FLOAT, 0, 0, textureVertices);`
- `glEnableVertexAttribArray(ATTRIB_TEXTURE);`
# 檔案操作
## 開啟檔案對話框
```c++
QString selectedFilepath = QFileDialog::getOpenFileName(
this,
tr("Select test plan file"), // 檔案選擇對話框左上角的提示
tr("."), // 檔案選擇對話框一開始的路徑
"(*.json);;All files(*.*)"); // 可選擇的副檔名
```
使用者所選擇的檔名會放在`selectedFilepath`,可以用`selectedFilepath.isEmpty()`來判斷使用者是不是真的有選擇檔案或是按了取消鍵。
## 存檔對話框
```c++
QString fileName = QFileDialog::getSaveFileName(
this,
tr("Save Address Book"), "", // 檔案選擇對話框左上角的提示
tr("Address Book (*.abk);;All Files (*)")); // 存檔的副檔名
```
# MISC
## 教學文
- [Qt教程Qt5编程入门教程非常详细](http://c.biancheng.net/qt/)

View File

@@ -1,2 +0,0 @@
- [GitHub - Qv2ray/Qv2ray: Linux / Windows / macOS 跨平台 V2Ray 客户端 | 支持 VMess / VLESS / SSR / Trojan / Trojan-Go / NaiveProxy / HTTP / HTTPS / SOCKS5 | 使用 C++ / Qt 开发 | 可拓展插件式设计](https://github.com/Qv2ray/Qv2ray)
- [Project V · Project V 官方网站](https://www.v2ray.com/)

View File

@@ -1,111 +0,0 @@
## Installation
### Install on Synology NAS
1. 從[synology-wireguard release](https://github.com/runfalk/synology-wireguard/releases)下載對應的SPKDS1513+是WireGuard-cedarview-1.0.20200729.spk。若不知道該下載哪一個版本可以查看[這個對照表](https://www.synology.com/en-global/knowledgebase/DSM/tutorial/Compatibility_Peripherals/What_kind_of_CPU_does_my_NAS_have)。
2. 在套件中心裡面手動安裝
3. 用SSH登入
### Install on Ubuntu 20.04
安裝: `sudo apt install wireguard resolvconf`
1. 打開firewall port
```
sudo ufw allow 50100/udp
```
2. 打開port forwarding
`sudo vim /etc/sysctl.conf`
然後加入這一行,存檔離開
`net.ipv4.ip_forward=1`
套用
`sudo sysctl -p`
## Setup Wireguard
1. Make a folder to store key and config
```
mkdir ~/wireguard ; cd ~/wireguard
```
2. 生成server的private/public key: `wg genkey | tee server_privateKey | wg pubkey > server_publicKey`
3. 在`/etc/wireguard`裡面,建立`wg0.conf`,如下:
```
[Interface]
Address = 10.0.0.1/24
ListenPort = 50100
PrivateKey = 8EELc7SWYbZswluhP0ZEzSkTAINXLlXqdE8J34eak3g=
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o enp0s3 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o enp0s3 -j MASQUERADE
SaveConfig = true
DNS = 8.8.8.8
# Awin
[Peer]
PublicKey = dB9l0rROSHyp3C6Odykdu69sU1k7XrOEa33ibx10I00=
AllowedIPs = 10.0.0.2/32
# Dean
[Peer]
PublicKey = N8kOoy3x4rsM1XDekrzLVQJ7Eo9Cb/vcQ07btzEK41Q=
AllowedIPs = 10.0.0.3/32
```
注意文中的`[Interface]`中的`PrivateKey`要替換成你自己生成的key可以用`cat server_privateKey`與`cat server_publicKey`來取得。
4. 生成user private/public key: `wg genkey | tee <user_name>_privateKey | wg pubkey > <user_name>_publicKey`
1. 例如要給awin的key: `wg genkey | tee awin_privateKey | wg pubkey > awin_publicKey`
5. 建立user的config例如給awin的config:
建立`awin.conf`,內容如下:
```
[Interface]
PrivateKey = OBN3ORMdpaz7pHTSlkyCXHvgLTbXnmB2kxJTCyrr3F4=
Address = 10.0.0.2/24
DNS = 8.8.8.8
[Peer]
PublicKey = 15Sy2MRW1yKWLzA03MciOkR7qvpxSXfmQtkMj9xOzj0=
AllowedIPs = 0.0.0.0/0, ::0/0
Endpoint = vpn.awin.one:50100
```
6. 把user config生成QR code方便掃描:
- `sudo grep -v '^#' /etc/wireguard/<user_name>.conf | qrencode -t ansiutf8`
- `qrencode -t ansiutf8 < <user_name>.conf`
- 兩個都可以
7. 重啟Wireguard
```
sudo wg-quick up wg0; \
sleep 5; \
sudo wg-quick down wg0; \
sleep 5; \
sudo wg-quick up wg0
```
另一個:
`sudo wg-quick down wg0 ; sudo cp ./wg0.conf /etc/wireguard/wg0.conf ; sudo wg-quick up wg0 ; sudo wg show wg0`
8. 查看Wireguard狀態: `sudo wg`
## Troubleshooting
That will tell you whether your packets are reaching the remote server, or if they're not getting through the tunnel.
- On the remote server: `sudo tcpdump -i wg0`
- On local machine: `ping -c1 <server_ip>`
## Helper
寫了一個script來copy config這樣就可以在Windows直接編輯。
```
#!/bin/env bash
sudo cp /volume1/homes/awin/Temp/wg0.conf .
sudo cp /volume1/homes/awin/Temp/awin.conf .
sudo cp /volume1/homes/awin/Temp/dean.conf .
sudo wg-quick down wg0
sleep 5
sudo wg-quick up wg0
sleep 5
sudo wg-quick down wg0
sleep 5
sudo wg-quick up wg0
```
----------
參考資料:
- https://github.com/runfalk/synology-wireguard
- https://notes.wadeism.net/linux/680/
- [『Atrandys』wireguard配置文件讲解 | 配置多用户 - YouTube](https://www.youtube.com/watch?v=X4doKJmjE4o&feature=youtu.be)