Affected files: .obsidian/workspace 03. 專注Study/Android/ADB 取得 APK 的 icon.md 03. 專注Study/Android/ADB.md 03. 專注Study/Android/AOSP.md 03. 專注Study/Android/Android programming.md 03. 專注Study/Android/AudioTrack.md 03. 專注Study/Android/Ktor.md 03. 專注Study/Android/Service.md 03. 專注Study/Android/Tools.md 03. 專注Study/Android/UI.md 03. 專注Study/C++/C++17.md 03. 專注Study/C++/Class template.md 03. 專注Study/C++/GCC.md 03. 專注Study/C++/Structured binding declaration.md 03. 專注Study/C++/for_each.md 03. 專注Study/C++/lambda.md 03. 專注Study/C++/lvalue.md 03. 專注Study/C++/move operator.md 03. 專注Study/C++/rvalue.md 03. 專注Study/C++/智慧指標.md 03. 專注Study/RxKotlin/20200207 - Study RxKotlin.md 04. Programming/COM/20210726 - COM Interface.md 04. Programming/DB/MySQL.md 04. Programming/DB/sqlite.md 04. Programming/Design Pattern.md 04. Programming/FFMPEG/00. Introduction.md 04. Programming/FFMPEG/01. Setup.md 04. Programming/FFMPEG/FFMpeg.md 04. Programming/Flask.md 04. Programming/Kotlin/class.md 04. Programming/Kotlin/run, let, with, also 和 apply.md 04. Programming/Media Foundation/20210604 - Windows media foundation.md 04. Programming/OpenCV.md 04. Programming/OpenGL.md 04. Programming/Python/argparse.ArgumentParser.md 04. Programming/Python/decorator.md 04. Programming/Python/logging.md 04. Programming/Python/opencv.md 04. Programming/Python/subprocess.md 04. Programming/Python/threading.md 04. Programming/Python/tkinter.md 04. Programming/Python/檢測工具.md 04. Programming/QT/Dropdown button.md 04. Programming/QT/QVariant.md 04. Programming/QT/Qt.md 04. Programming/UML.md 04. Programming/演算法.md 05. 資料收集/99. templates/blogHeader.md 05. 資料收集/99. templates/date.md 05. 資料收集/99. templates/front matter.md 05. 資料收集/99. templates/note.md 05. 資料收集/99. templates/table.md 05. 資料收集/99. templates/thisWeek.md 05. 資料收集/99. templates/日記.md 05. 資料收集/99. templates/讀書筆記.md 05. 資料收集/Linux/CLI/cut.md 05. 資料收集/Linux/CLI/scp.md 05. 資料收集/Linux/CLI/timedatectl.md 05. 資料收集/Linux/Programming.md 05. 資料收集/Linux/Ubuntu.md 05. 資料收集/Tool Setup/Hardware/RaspberryPi.md 05. 資料收集/Tool Setup/Software/Chrome.md 05. 資料收集/Tool Setup/Software/Obisidian.md 05. 資料收集/Tool Setup/Software/SublimeText.md 05. 資料收集/Tool Setup/Software/VirtualBox.md 05. 資料收集/Tool Setup/Software/Visual Studio Code.md 05. 資料收集/Tool Setup/Software/Windows Setup.md 05. 資料收集/Tool Setup/Software/Windows Terminal.md 05. 資料收集/Tool Setup/Software/freefilesync.md 05. 資料收集/Tool Setup/Software/vim.md 05. 資料收集/名言佳句.md 05. 資料收集/架站/Gitea.md 05. 資料收集/架站/HTTP Server/Apache.md 05. 資料收集/架站/HTTP Server/Nginx/Reverse Proxy(Layer4).md 05. 資料收集/架站/Pelican blog.md 05. 資料收集/架站/Proxmox VE.md 05. 資料收集/架站/SWAG Reverse proxy.md 05. 資料收集/架站/Storj.md 05. 資料收集/架站/Trojan.md 05. 資料收集/每週外食.md 05. 資料收集/科技/802.11.md 05. 資料收集/科技/HDR Sensor.md 05. 資料收集/科技/量子電腦.md 05. 資料收集/科技/鋰電池.md 05. 資料收集/興趣嗜好/RC/Traxxas Sledge.md 05. 資料收集/興趣嗜好/RC/好盈電變調整中立點.md 05. 資料收集/興趣嗜好/RC/差速器調教教學.md 05. 資料收集/興趣嗜好/模型/舊化作例.md 05. 資料收集/興趣嗜好/軍武/虎式.md 05. 資料收集/讀書筆記/20201201 - 學習如何學習.md 05. 資料收集/讀書筆記/20201218 - Kotlin權威2.0.md 05. 資料收集/讀書筆記/20201224 - 寫作是最好的自我投資.md 05. 資料收集/讀書筆記/20210119 - 中產悲歌.md 05. 資料收集/讀書筆記/20210220 - 最高學習法.md 05. 資料收集/讀書筆記/20210320 - 最高學以致用法.md 05. 資料收集/讀書筆記/20210406 - 精準購買.md 05. 資料收集/讀書筆記/20210723 - 高手學習.md 05. 資料收集/讀書筆記/20220526 - 深入淺出設計模式.md 05. 資料收集/讀書筆記/20220619 - 精確的力量.md 05. 資料收集/軟體工具/IPFS.md 05. 資料收集/軟體工具/MkDocs.md 05. 資料收集/軟體工具/Obsidian.md 05. 資料收集/軟體工具/docker.md 05. 資料收集/軟體工具/git/apply.md 05. 資料收集/軟體工具/git/submodule.md 05. 資料收集/軟體工具/youtube-dl.md 05. 資料收集/面試準備/技术面试最后反问面试官的话.md
20 KiB
Prepare
Windows 10 SDK
下載並安裝Windows 10 SDK,安裝
Debugging Tools for Windows就可以了。
!
Visual Studio 2017
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的情形。
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
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裡面
// 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
// 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前面加上一個字串以便分類。
#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
- 繼承自QThread。
- 重載
run()。 - 呼叫
start()來開始thread。
QWidget
設定signal與對應的slot
- 在class header裡面加入
Q_OBJECT。 - 在constructor裡,呼叫
connect()來建立對應關係:connect(SOURCE_OBJECT, SIGNAL(clicked()), DEST_OBJECT, SLOT(close()))。
Postion
QRect geometry();取得x, y, width, heightsetGeometry();設定x, y, width, heightx(),y(),width(),height()單獨取得x, y, width, heightmove(x, y);只設定x, yresize(width, height);只設定width, height
Window state
setWindowState(Qt::WindowMaximized);Qt::WindowMaximized->showMaximized()Qt::WindowMinimized->showMinimized()Qt::WindowNoState->showNormal()Qt::WindowFullScreen->showFullScreen()
Window Style
CustomizeWindowHint()setWindowFlags(Qt::WindowCloseButtonHint | Qt::WindowMinimizeButtonHint)- Qt::WindowCloseButtonHint
- Qt::WindowMinimizeButtonHint
setWindowFlag(Qt::WindowCloseButtonHint, false)// 取消close按鈕- Qt::WindowCloseButtonHint
- Qt::WindowMinimizeButtonHint
- 沒有邊框的視窗:
setWindowFlags(Qt::FramelessWindowHint) - 透明背景:
setAttribute(Qt::WA_TranslucentBackground, true) - Style sheet: https://doc.qt.io/qt-5/stylesheet-syntax.html#style-rules
Layout
-
QVBoxLayout
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
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; } }
- Iterate all items
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);
}
QListWidget
-
Insert a QLineEdit
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()
-
setHorizontalHeaderItem(column_index, new QTableWidgetItem("Header1"))
-
setColumnWidth(column_index, column_width)
-
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) constint 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
QJson
QFile
Read UTF-8 content from file.
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
- 對於n bytes的字元,第一個byte的前n個bits是1,第n+1個bit是0,第2個byte以後,都以
10開頭。- 例: 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。
- 例:
- 「A」是一個1 byte字元,編碼為
0x01000001。 - 「Á」是一個2 bytes字元,編碼為
0x11000011 0x10000001。 - 「好」是一個3 bytes字元,編碼為
0x11100101 0x10100101 0x10111101。
- 「A」是一個1 byte字元,編碼為
- UTF-8 to binary轉換網站
- BOM
- Big endian:
FE FF - Little endian:
FF FE
- Big endian:
QString
- 16 bits QChar(unsigned short), UNIDODE 4.0
==: compare stringisNull(): If has a valueisEmpty(): 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()。- 例:
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)
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
addShaderFromSourceCodebindAttributeLocation:設定傳入的變數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():修改textureglUniform1i(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);
檔案操作
開啟檔案對話框
QString selectedFilepath = QFileDialog::getOpenFileName(
this,
tr("Select test plan file"), // 檔案選擇對話框左上角的提示
tr("."), // 檔案選擇對話框一開始的路徑
"(*.json);;All files(*.*)"); // 可選擇的副檔名
使用者所選擇的檔名會放在selectedFilepath,可以用selectedFilepath.isEmpty()來判斷使用者是不是真的有選擇檔案或是按了取消鍵。
存檔對話框
QString fileName = QFileDialog::getSaveFileName(
this,
tr("Save Address Book"), "", // 檔案選擇對話框左上角的提示
tr("Address Book (*.abk);;All Files (*)")); // 存檔的副檔名





