This commit is contained in:
zhuzichu 2024-01-04 18:00:44 +08:00
parent 3a0f6355c8
commit 833a8217f4
27 changed files with 339 additions and 31 deletions

View File

@ -2,6 +2,12 @@ cmake_minimum_required(VERSION 3.20)
project(FluentUI VERSION 1.0)
if(WIN32)
#Releasepdb
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /DEBUG /OPT:REF /OPT:ICF")
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /DEBUG /OPT:REF /OPT:ICF")
endif()
set(FLUENTUI_DIRECTORY ${CMAKE_CURRENT_LIST_DIR})
list(APPEND CMAKE_MODULE_PATH ${FLUENTUI_DIRECTORY}/.cmake/)

View File

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.20)
project(example VERSION 1.0)
project(example VERSION 1.0 LANGUAGES CXX)
#
set(CMAKE_CXX_STANDARD 17)
@ -50,6 +50,10 @@ foreach(filepath ${CPP_FILES})
list(APPEND sources_files ${filename})
endforeach(filepath)
if(WIN32)
list(APPEND sources_files "src/app_dmp.h")
endif()
if(QT_VERSION VERSION_GREATER_EQUAL "6.2")
#qml
file(GLOB_RECURSE QML_PATHS *.qml qmldir)

View File

@ -196,5 +196,7 @@
<file>qml/chart/T_ScatterChart.qml</file>
<file>qml/chart/T_BubbleChart.qml</file>
<file>qml/chart/T_PolarAreaChart.qml</file>
<file>res/image/ic_crash.png</file>
<file>qml/window/CrashWindow.qml</file>
</qresource>
</RCC>

View File

@ -36,12 +36,17 @@ Item {
"/about":"qrc:/example/qml/window/AboutWindow.qml",
"/login":"qrc:/example/qml/window/LoginWindow.qml",
"/hotload":"qrc:/example/qml/window/HotloadWindow.qml",
"/crash":"qrc:/example/qml/window/CrashWindow.qml",
"/singleTaskWindow":"qrc:/example/qml/window/SingleTaskWindow.qml",
"/standardWindow":"qrc:/example/qml/window/StandardWindow.qml",
"/singleInstanceWindow":"qrc:/example/qml/window/SingleInstanceWindow.qml",
"/pageWindow":"qrc:/example/qml/window/PageWindow.qml"
}
FluApp.initialRoute = "/"
FluApp.run()
var args = Qt.application.arguments
if(args.length>=2 && args[1].startsWith("-crashed=")){
FluApp.navigate("/crash",{crashFilePath:args[1].replace("-crashed=","")})
}else{
FluApp.navigate("/")
}
}
}

View File

@ -466,6 +466,13 @@ FluObject{
url:"qrc:/example/qml/page/T_3D.qml"
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"Test Crash"
visible: FluTools.isWin()
onTapListener: function(){
AppInfo.testCrash()
}
}
}
function getRecentlyAddedData(){

View File

@ -0,0 +1,72 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import FluentUI
import Qt.labs.platform
import "qrc:///example/qml/component"
FluWindow {
id:window
title:"友情提示"
width: 300
height: 400
fixSize: true
showMinimize: false
showStayTop: false
property string crashFilePath
onInitArgument:
(argument)=>{
crashFilePath = argument.crashFilePath
}
Image{
width: 540/2
height: 285/2
anchors{
horizontalCenter: parent.horizontalCenter
top: parent.top
topMargin: 40
}
source: "qrc:/example/res/image/ic_crash.png"
}
FluText{
id:text_info
anchors{
horizontalCenter: parent.horizontalCenter
top: parent.top
topMargin: 240
}
text:"发生意外错误\n给您带来的不便我们深表歉意"
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
RowLayout{
anchors{
horizontalCenter: parent.horizontalCenter
bottom: parent.bottom
bottomMargin: 20
}
FluButton{
text:"日志上报"
onClicked: {
FluTools.showFileInFolder(crashFilePath)
}
}
Item{
width: 30
height: 1
}
FluFilledButton{
text:"重启程序"
onClicked: {
FluApp.exit(931)
}
}
}
}

View File

@ -36,12 +36,17 @@ Item {
"/about":"qrc:/example/qml/window/AboutWindow.qml",
"/login":"qrc:/example/qml/window/LoginWindow.qml",
"/hotload":"qrc:/example/qml/window/HotloadWindow.qml",
"/crash":"qrc:/example/qml/window/CrashWindow.qml",
"/singleTaskWindow":"qrc:/example/qml/window/SingleTaskWindow.qml",
"/standardWindow":"qrc:/example/qml/window/StandardWindow.qml",
"/singleInstanceWindow":"qrc:/example/qml/window/SingleInstanceWindow.qml",
"/pageWindow":"qrc:/example/qml/window/PageWindow.qml"
}
FluApp.initialRoute = "/"
FluApp.run()
var args = Qt.application.arguments
if(args.length>=2 && args[1].startsWith("-crashed=")){
FluApp.navigate("/crash",{crashFilePath:args[1].replace("-crashed=","")})
}else{
FluApp.navigate("/")
}
}
}

View File

@ -466,6 +466,13 @@ FluObject{
url:"qrc:/example/qml/page/T_3D.qml"
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"Test Crash"
visible: FluTools.isWin()
onTapListener: function(){
AppInfo.testCrash()
}
}
}
function getRecentlyAddedData(){

View File

@ -0,0 +1,72 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import FluentUI 1.0
import Qt.labs.platform 1.0
import "qrc:///example/qml/component"
FluWindow {
id:window
title:"友情提示"
width: 300
height: 400
fixSize: true
showMinimize: false
showStayTop: false
property string crashFilePath
onInitArgument:
(argument)=>{
crashFilePath = argument.crashFilePath
}
Image{
width: 540/2
height: 285/2
anchors{
horizontalCenter: parent.horizontalCenter
top: parent.top
topMargin: 40
}
source: "qrc:/example/res/image/ic_crash.png"
}
FluText{
id:text_info
anchors{
horizontalCenter: parent.horizontalCenter
top: parent.top
topMargin: 240
}
text:"发生意外错误\n给您带来的不便我们深表歉意"
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
RowLayout{
anchors{
horizontalCenter: parent.horizontalCenter
bottom: parent.bottom
bottomMargin: 20
}
FluButton{
text:"日志上报"
onClicked: {
FluTools.showFileInFolder(crashFilePath)
}
}
Item{
width: 30
height: 1
}
FluFilledButton{
text:"重启程序"
onClicked: {
FluApp.exit(931)
}
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -10,3 +10,8 @@ AppInfo::AppInfo(QObject *parent)
{
version(APPLICATION_VERSION);
}
void AppInfo::testCrash(){
auto *crash = reinterpret_cast<volatile int *>(0);
*crash = 0;
}

View File

@ -14,6 +14,7 @@ private:
explicit AppInfo(QObject *parent = nullptr);
public:
SINGLETON(AppInfo)
Q_INVOKABLE void testCrash();
};
#endif // APPINFO_H

69
example/src/app_dmp.h Normal file
View File

@ -0,0 +1,69 @@
#ifndef APP_DUMP_H
#define APP_DUMP_H
#include <Windows.h>
#include <DbgHelp.h>
#include <QDateTime>
#include <QDir>
#include <QGuiApplication>
#include <QProcess>
#include <QStandardPaths>
#include <QString>
#pragma comment(lib, "Dbghelp.lib")
BOOL CALLBACK MyMiniDumpCallback(PVOID, const PMINIDUMP_CALLBACK_INPUT input, PMINIDUMP_CALLBACK_OUTPUT output) {
if (input == NULL || output == NULL)
return FALSE;
BOOL ret = FALSE;
switch (input->CallbackType) {
case IncludeModuleCallback:
case IncludeThreadCallback:
case ThreadCallback:
case ThreadExCallback:
ret = TRUE;
break;
case ModuleCallback: {
if (!(output->ModuleWriteFlags & ModuleReferencedByMemory)) {
output->ModuleWriteFlags &= ~ModuleWriteModule;
}
ret = TRUE;
} break;
default:
break;
}
return ret;
}
void WriteDump(EXCEPTION_POINTERS* exp, const std::wstring& path) {
HANDLE h = ::CreateFileW(path.c_str(), GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
MINIDUMP_EXCEPTION_INFORMATION info;
info.ThreadId = ::GetCurrentThreadId();
info.ExceptionPointers = exp;
info.ClientPointers = NULL;
MINIDUMP_CALLBACK_INFORMATION mci;
mci.CallbackRoutine = (MINIDUMP_CALLBACK_ROUTINE)MyMiniDumpCallback;
mci.CallbackParam = 0;
MINIDUMP_TYPE mdt = (MINIDUMP_TYPE)(MiniDumpWithIndirectlyReferencedMemory | MiniDumpScanMemory);
MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), h, mdt, &info, NULL, &mci);
::CloseHandle(h);
}
LONG WINAPI MyUnhandledExceptionFilter(EXCEPTION_POINTERS* exp) {
const QString dumpFileName = QString("%1_%2.dmp").arg("crash",QDateTime::currentDateTime().toString("yyyyMMdd_hhmmss"));
const QString dumpDirPath = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation)+"/dmp";
const QDir dumpDir(dumpDirPath);
if(!dumpDir.exists()){
dumpDir.mkpath(dumpDirPath);
}
QString dumpFilePath = dumpDir.filePath(dumpFileName);
WriteDump(exp, dumpFilePath.toStdWString());
QStringList arguments;
arguments << "-crashed=" + dumpFilePath;
QProcess::startDetached(qApp->applicationFilePath(), arguments);
return EXCEPTION_EXECUTE_HANDLER;
}
#endif // APP_DUMP_H

View File

@ -92,7 +92,7 @@ QString Log::prettyProductInfoWrapper()
return productName;
}
static inline void myMessageHandler(const QtMsgType type, const QMessageLogContext &context, const QString &message)
static inline void messageHandler(const QtMsgType type, const QMessageLogContext &context, const QString &message)
{
if(message == "Could not get the INetworkConnection instance for the adapter GUID."){
return;
@ -188,7 +188,7 @@ void Log::setup(const QString &app,int level)
logDir.mkpath(logDirPath);
}
g_file_path = logDir.filePath(logFileName);
qInstallMessageHandler(myMessageHandler);
qInstallMessageHandler(messageHandler);
qInfo()<<"===================================================";
qInfo()<<"[AppName]"<<g_app;
qInfo()<<"[AppVersion]"<<APPLICATION_VERSION;

View File

@ -23,12 +23,17 @@ Q_IMPORT_QML_PLUGIN(FluentUIPlugin)
#include <FluentUI.h>
#endif
#ifdef WIN32
#include "app_dmp.h"
#endif
int main(int argc, char *argv[])
{
qputenv("QT_QUICK_CONTROLS_STYLE","Basic");
#ifdef Q_OS_WIN
#ifdef WIN32
::SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);
qputenv("QT_QPA_PLATFORM","windows:darkmode=2");
#endif
qputenv("QT_QUICK_CONTROLS_STYLE","Basic");
#ifdef Q_OS_LINUX
//fix bug UOSv20 does not print logs
qputenv("QT_LOGGING_RULES","");

View File

@ -41,15 +41,22 @@ Item {
function handleItems(){
var _idx = 0
var data = []
var comEmpty = Qt.createComponent("FluPaneItemEmpty.qml");
if(items){
for(var i=0;i<items.children.length;i++){
var item = items.children[i]
if(item.visible !== true){
continue
}
item._idx = _idx
data.push(item)
_idx++
if(item instanceof FluPaneItemExpander){
for(var j=0;j<item.children.length;j++){
var itemChild = item.children[j]
if(itemChild.visible !== true){
continue
}
itemChild._parent = item
itemChild._idx = _idx
data.push(itemChild)
@ -58,20 +65,33 @@ Item {
}
}
if(footerItems){
var comEmpty = Qt.createComponent("FluPaneItemEmpty.qml");
for(var k=0;k<footerItems.children.length;k++){
var itemFooter = footerItems.children[k]
if (comEmpty.status === Component.Ready) {
var objEmpty = comEmpty.createObject(items,{_idx:_idx});
itemFooter._idx = _idx;
data.push(objEmpty)
_idx++
if(itemFooter.visible !== true){
continue
}
var objEmpty = comEmpty.createObject(items,{_idx:_idx});
itemFooter._idx = _idx;
data.push(objEmpty)
_idx++
}
}
}
return data
}
function handleFooterItems(){
var data = []
if(footerItems){
for(var i=0;i<footerItems.children.length;i++){
var item = footerItems.children[i]
if(item.visible !== true){
continue
}
data.push(item)
}
}
return data;
}
}
Component.onCompleted: {
d.displayMode = Qt.binding(function(){
@ -257,6 +277,9 @@ Item {
}
for(var i=0;i<model.children.length;i++){
var item = model.children[i]
if(item.visible !== true){
continue
}
if(item._idx === nav_list.currentIndex && !model.isExpand){
return true
}
@ -1039,11 +1062,7 @@ Item {
interactive: false
boundsBehavior: ListView.StopAtBounds
currentIndex: -1
model: {
if(footerItems){
return footerItems.children
}
}
model: d.handleFooterItems()
highlightMoveDuration: 150
highlight: Item{
clip: true

View File

@ -7,6 +7,7 @@ QtObject {
property int _idx
property var _ext
property var _parent
property bool visible: true
property string title
property var url
property bool disabled: false

View File

@ -7,4 +7,5 @@ QtObject {
property int _idx
property var _ext
property var _parent
property bool visible: true
}

View File

@ -5,6 +5,7 @@ import FluentUI 1.0
FluObject {
readonly property string key : FluTools.uuid()
property int _idx
property bool visible: true
property string title
property var icon
property bool disabled: false

View File

@ -5,6 +5,7 @@ import FluentUI 1.0
QtObject {
readonly property string key : FluTools.uuid()
property int _idx
property bool visible: true
property string title
property var parent
}

View File

@ -5,6 +5,7 @@ import FluentUI 1.0
QtObject {
readonly property string key : FluTools.uuid()
property int _idx
property bool visible: true
property var parent
property real spacing
property int size:1

View File

@ -42,15 +42,22 @@ Item {
function handleItems(){
var _idx = 0
var data = []
var comEmpty = Qt.createComponent("FluPaneItemEmpty.qml");
if(items){
for(var i=0;i<items.children.length;i++){
var item = items.children[i]
if(item.visible !== true){
continue
}
item._idx = _idx
data.push(item)
_idx++
if(item instanceof FluPaneItemExpander){
for(var j=0;j<item.children.length;j++){
var itemChild = item.children[j]
if(itemChild.visible !== true){
continue
}
itemChild._parent = item
itemChild._idx = _idx
data.push(itemChild)
@ -59,20 +66,33 @@ Item {
}
}
if(footerItems){
var comEmpty = Qt.createComponent("FluPaneItemEmpty.qml");
for(var k=0;k<footerItems.children.length;k++){
var itemFooter = footerItems.children[k]
if (comEmpty.status === Component.Ready) {
var objEmpty = comEmpty.createObject(items,{_idx:_idx});
itemFooter._idx = _idx;
data.push(objEmpty)
_idx++
if(itemFooter.visible !== true){
continue
}
var objEmpty = comEmpty.createObject(items,{_idx:_idx});
itemFooter._idx = _idx;
data.push(objEmpty)
_idx++
}
}
}
return data
}
function handleFooterItems(){
var data = []
if(footerItems){
for(var i=0;i<footerItems.children.length;i++){
var item = footerItems.children[i]
if(item.visible !== true){
continue
}
data.push(item)
}
}
return data;
}
}
Component.onCompleted: {
d.displayMode = Qt.binding(function(){
@ -258,6 +278,9 @@ Item {
}
for(var i=0;i<model.children.length;i++){
var item = model.children[i]
if(item.visible !== true){
continue
}
if(item._idx === nav_list.currentIndex && !model.isExpand){
return true
}
@ -1040,11 +1063,7 @@ Item {
interactive: false
boundsBehavior: ListView.StopAtBounds
currentIndex: -1
model: {
if(footerItems){
return footerItems.children
}
}
model: d.handleFooterItems()
highlightMoveDuration: 150
highlight: Item{
clip: true

View File

@ -7,6 +7,7 @@ QtObject {
property int _idx
property var _ext
property var _parent
property bool visible: true
property string title
property var url
property bool disabled: false

View File

@ -7,4 +7,5 @@ QtObject {
property int _idx
property var _ext
property var _parent
property bool visible: true
}

View File

@ -5,6 +5,7 @@ import FluentUI
FluObject {
readonly property string key : FluTools.uuid()
property int _idx
property bool visible: true
property string title
property var icon
property bool disabled: false

View File

@ -5,6 +5,7 @@ import FluentUI
QtObject {
readonly property string key : FluTools.uuid()
property int _idx
property bool visible: true
property string title
property var parent
}

View File

@ -5,6 +5,7 @@ import FluentUI
QtObject {
readonly property string key : FluTools.uuid()
property int _idx
property bool visible: true
property var parent
property real spacing
property int size:1