vault backup: 2025-03-04 11:17:00
This commit is contained in:
9
20.01. Programming/QT/Application Icon.md
Normal file
9
20.01. Programming/QT/Application Icon.md
Normal file
@@ -0,0 +1,9 @@
|
||||
## Add icon of application
|
||||
1. Create a `*.ico` file of whatever you want to use as a logo. I called mine `favicon.ico`.
|
||||
2. Create a file named `yourapplication.rc`.
|
||||
3. Add the following line to `yourapplication.rc`: `IDI_ICON1 ICON DISCARDABLE "favicon.ico"`.
|
||||
4. Add the `*.rc` file to your buildsystem as a source file.
|
||||
5. Make sure that your `*.exe` ships along side the `favicon.ico` file.
|
||||
|
||||
### Source
|
||||
- [c++ - Set icon for Qt application built in Visual Studio - Stack Overflow](https://stackoverflow.com/questions/65818269/set-icon-for-qt-application-built-in-visual-studio)
|
||||
21
20.01. Programming/QT/Dropdown button.md
Normal file
21
20.01. Programming/QT/Dropdown button.md
Normal file
@@ -0,0 +1,21 @@
|
||||
![[Pasted image 20220519094358.png]]
|
||||
|
||||
1. Button必須是QToolButton.
|
||||
2. 建立menu.
|
||||
3. 建立action.
|
||||
4. 把action加到menu裡面
|
||||
5. 把menu設定給button
|
||||
6. code example:
|
||||
```cpp
|
||||
QMenu* saveFrameMenu = new QMenu;
|
||||
saveRawAction = new QAction(QIcon(QPixmap(":/image/resources/button-raw.png")), "SaveRaw", this);
|
||||
saveJpgAction = new QAction(QIcon(QPixmap(":/image/resources/button-jpg.png")), "SaveJpg", this);
|
||||
saveBmpAction = new QAction(QIcon(QPixmap(":/image/resources/button-bmp.png")), "SaveBmp", this);
|
||||
saveFrameMenu->addAction(saveRawAction);
|
||||
saveFrameMenu->addAction(saveJpgAction);
|
||||
saveFrameMenu->addAction(saveBmpAction);
|
||||
ui.toolButtonSaveFrame->setMenu(saveFrameMenu);
|
||||
ui.toolButtonSaveFrame->setDefaultAction(saveJpgAction);
|
||||
ui.toolButtonSaveFrame->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
|
||||
ui.toolButtonSaveFrame->setPopupMode(QToolButton::MenuButtonPopup);
|
||||
```
|
||||
1
20.01. Programming/QT/QTableWidget.md
Normal file
1
20.01. Programming/QT/QTableWidget.md
Normal file
@@ -0,0 +1 @@
|
||||
- [Qt之QTableWidget详细使用_qt的setitem_m沉默01的博客-CSDN博客](https://blog.csdn.net/u010780613/article/details/50442639)
|
||||
9
20.01. Programming/QT/QVariant.md
Normal file
9
20.01. Programming/QT/QVariant.md
Normal file
@@ -0,0 +1,9 @@
|
||||
Qt有許多UI元件都可以另外設定相依的「資料」,例如`QCombobox`,這樣我們就不必老是依賴選項的文字來做許多麻煩的處理。
|
||||
例如,`QCombobox.addItem()`可以夾帶一個`QVariant`,這個`QVariant`就可以夾帶一個pointer。
|
||||
要讓`QVariant`支援`std::shared_ptr`的方式很簡單,只要在你程式的最上方加入你要使用的type就可以,例如,我要支援我自己的class AwSentinelDevice,就這樣寫:
|
||||
```cpp
|
||||
#include <memory>
|
||||
|
||||
Q_DECLARE_SMART_POINTER_METATYPE(std::shared_ptr);
|
||||
Q_DECLARE_METATYPE(std::shared_ptr<AwSentinelDevice>);
|
||||
```
|
||||
734
20.01. Programming/QT/Qt.md
Normal file
734
20.01. Programming/QT/Qt.md
Normal file
@@ -0,0 +1,734 @@
|
||||
## 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
|
||||
```cpp
|
||||
/* 有旁節點,沒有與其他元素相鄰 */
|
||||
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/)
|
||||
19
20.01. Programming/QT/timer.md
Normal file
19
20.01. Programming/QT/timer.md
Normal file
@@ -0,0 +1,19 @@
|
||||
使用QTimer來反覆執行工作。
|
||||
QTimer可以單次執行,也可以多次執行。
|
||||
|
||||
使用概念如下:
|
||||
1. 建立 QTimer 物件,例如叫做 timer。
|
||||
2. 連接QTimer的timeout signal到你的反應 function
|
||||
3. 呼叫 timer->start()
|
||||
|
||||
Example:
|
||||
```cpp
|
||||
QTimer* timer = new QTimer(this);
|
||||
connect(timer, SIGNAL(timeout()), this, SLOT(update()));
|
||||
timer->start(1000);
|
||||
```
|
||||
|
||||
QTimer可以單次執行:
|
||||
```cpp
|
||||
QTimer::singleShot(200, this, SLOT(update());
|
||||
```
|
||||
9
20.01. Programming/QT/安裝.md
Normal file
9
20.01. Programming/QT/安裝.md
Normal file
@@ -0,0 +1,9 @@
|
||||
`qt-unified-windows-x86-4.0.1-1-online.exe` 預設的 server 真的很慢,甚至會發生校驗錯誤的情況。
|
||||
可以在[Qt Downloads](https://download.qt.io/static/mirrorlist/)選 mirror server,然後在安裝的時候指定使用它。
|
||||
|
||||
例如我選的是 Yamagata University 的mirror server,如下:
|
||||
```cmd
|
||||
qt-unified-windows-x64-4.7.0-online.exe --mirror https://ftp.yz.yamagata-u.ac.jp/pub/qtproject/
|
||||
```
|
||||
|
||||
下載速度從1 ~ 2 MB/s 進步到 25MB/s 左右。
|
||||
2
20.01. Programming/QT/界面外觀.md
Normal file
2
20.01. Programming/QT/界面外觀.md
Normal file
@@ -0,0 +1,2 @@
|
||||
- `QApplication.setStyle()` 可以設定視窗風格(Windows、Vista、Fusion)
|
||||
-
|
||||
Reference in New Issue
Block a user