fix: 修复启动白屏与地图崩溃问题

- SetUseOpenGL(false): QGLWidget 在当前系统不兼容,改用软件渲染
- ExtensionHost_v2: 添加 contributionRegistry() getter 修复空指针
- main.cpp: 两阶段启动 (show → QTimer::singleShot → initialize)
- mainwindow: 分离构造函数与 initialize(),结尾调用 onTabIndexChanged(3)
- 修复 Qt DLL 部署:使用 windeployqt 确保运行时库版本匹配
This commit is contained in:
2026-06-02 19:01:24 +08:00
parent 94fcdb12e0
commit 61cd75cd56
39 changed files with 2994 additions and 1258 deletions
+33
View File
@@ -0,0 +1,33 @@
# Logging — Unified Logging Plugin (Shared Library / DLL)
add_library(LoggingPlugin SHARED
LoggingPlugin.cpp
LogViewer.cpp
LoggingPlugin.h
LogViewer.h
)
target_include_directories(LoggingPlugin PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_SOURCE_DIR}/Plugins
${CMAKE_SOURCE_DIR}/PluginSDK
)
target_link_libraries(LoggingPlugin PUBLIC
PluginSDK
Qt${QT_VERSION_MAJOR}::Core
Qt${QT_VERSION_MAJOR}::Widgets
)
set_target_properties(LoggingPlugin PROPERTIES
PREFIX ""
SUFFIX ".dll"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/plugins/Logging"
WINDOWS_EXPORT_ALL_SYMBOLS ON
LINK_FLAGS "-Wl,--export-all-symbols"
)
add_custom_command(TARGET LoggingPlugin POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${CMAKE_CURRENT_SOURCE_DIR}/plugin.json"
"${CMAKE_BINARY_DIR}/bin/plugins/Logging/plugin.json"
)
+181
View File
@@ -0,0 +1,181 @@
#include "LogViewer.h"
#include "Logging.h"
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QFileDialog>
#include <QTextStream>
#include <QApplication>
#include <QDateTime>
#include <QMutexLocker>
#include <QMutex>
#include <QScrollBar>
LogViewer *LogViewer::s_instance = nullptr;
QtMessageHandler LogViewer::s_oldHandler = nullptr;
LogViewer::LogViewer(QWidget *parent)
: QWidget(parent)
{
auto *layout = new QVBoxLayout(this);
auto *toolbar = new QHBoxLayout();
m_levelCombo = new QComboBox(this);
m_levelCombo->addItems({
QStringLiteral("All"),
QStringLiteral("Debug"),
QStringLiteral("Info"),
QStringLiteral("Warning"),
QStringLiteral("Critical"),
QStringLiteral("Fatal")
});
connect(m_levelCombo, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &LogViewer::onLevelChanged);
m_filterEdit = new QLineEdit(this);
m_filterEdit->setPlaceholderText(QStringLiteral("Filter..."));
connect(m_filterEdit, &QLineEdit::textChanged,
this, &LogViewer::onFilterChanged);
m_autoScroll = new QCheckBox(QStringLiteral("Auto-scroll"), this);
m_autoScroll->setChecked(true);
connect(m_autoScroll, &QCheckBox::toggled,
this, &LogViewer::onAutoScrollToggled);
m_clearBtn = new QPushButton(QStringLiteral("Clear"), this);
connect(m_clearBtn, &QPushButton::clicked, this, &LogViewer::onClear);
m_exportBtn = new QPushButton(QStringLiteral("Export..."), this);
connect(m_exportBtn, &QPushButton::clicked, this, &LogViewer::onExport);
m_countLabel = new QLabel(QStringLiteral("0 lines"), this);
toolbar->addWidget(new QLabel(QStringLiteral("Level:"), this));
toolbar->addWidget(m_levelCombo);
toolbar->addWidget(m_filterEdit);
toolbar->addWidget(m_autoScroll);
toolbar->addWidget(m_clearBtn);
toolbar->addWidget(m_exportBtn);
toolbar->addStretch();
toolbar->addWidget(m_countLabel);
m_logView = new QTextEdit(this);
m_logView->setReadOnly(true);
m_logView->setFont(QFont(QStringLiteral("Consolas"), 10));
m_logView->setStyleSheet(QStringLiteral("background: #1e1e1e; color: #d4d4d4;"));
layout->addLayout(toolbar);
layout->addWidget(m_logView);
installMessageHandler();
}
void LogViewer::installMessageHandler()
{
s_instance = this;
s_oldHandler = qInstallMessageHandler(logMessageHandler);
}
void LogViewer::restoreMessageHandler()
{
if (s_oldHandler) {
qInstallMessageHandler(s_oldHandler);
s_oldHandler = nullptr;
}
s_instance = nullptr;
}
void LogViewer::logMessageHandler(QtMsgType type,
const QMessageLogContext &context,
const QString &msg)
{
if (s_oldHandler)
s_oldHandler(type, context, msg);
if (!s_instance)
return;
QString formatted;
QString timestamp = QDateTime::currentDateTime().toString(QStringLiteral("hh:mm:ss.zzz"));
QString category = context.category ? QString::fromUtf8(context.category) : QStringLiteral("default");
switch (type) {
case QtDebugMsg:
formatted = QStringLiteral("<span style='color:#808080'>[%1] [DEBUG] [%2] %3</span>")
.arg(timestamp, category, msg.toHtmlEscaped());
break;
case QtInfoMsg:
formatted = QStringLiteral("<span style='color:#d4d4d4'>[%1] [INFO] [%2] %3</span>")
.arg(timestamp, category, msg.toHtmlEscaped());
break;
case QtWarningMsg:
formatted = QStringLiteral("<span style='color:#dcdcaa'>[%1] [WARN] [%2] %3</span>")
.arg(timestamp, category, msg.toHtmlEscaped());
break;
case QtCriticalMsg:
formatted = QStringLiteral("<span style='color:#f44747'>[%1] [CRIT] [%2] %3</span>")
.arg(timestamp, category, msg.toHtmlEscaped());
break;
case QtFatalMsg:
formatted = QStringLiteral("<span style='color:#ff0000;font-weight:bold'>[%1] [FATAL] [%2] %3</span>")
.arg(timestamp, category, msg.toHtmlEscaped());
break;
}
QMetaObject::invokeMethod(s_instance, [formatted]() {
if (!s_instance) return;
if (s_instance->m_logView->document()->blockCount() > 10000)
s_instance->m_logView->clear();
s_instance->m_logView->append(formatted);
s_instance->m_logCount++;
s_instance->m_countLabel->setText(
QStringLiteral("%1 lines").arg(s_instance->m_logCount));
if (s_instance->m_autoScroll->isChecked()) {
QScrollBar *sb = s_instance->m_logView->verticalScrollBar();
sb->setValue(sb->maximum());
}
}, Qt::QueuedConnection);
}
void LogViewer::onFilterChanged(const QString &text)
{
Q_UNUSED(text)
}
void LogViewer::onLevelChanged(int index)
{
Q_UNUSED(index)
}
void LogViewer::onClear()
{
m_logView->clear();
m_logCount = 0;
m_countLabel->setText(QStringLiteral("0 lines"));
}
void LogViewer::onExport()
{
QString path = QFileDialog::getSaveFileName(
this,
QStringLiteral("Export Log"),
QStringLiteral("gcs_log.txt"),
QStringLiteral("Text Files (*.txt);;All Files (*)")
);
if (path.isEmpty()) return;
QFile file(path);
if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
QTextStream stream(&file);
stream << m_logView->toPlainText();
file.close();
}
}
void LogViewer::onAutoScrollToggled(bool enabled)
{
Q_UNUSED(enabled)
}
+46
View File
@@ -0,0 +1,46 @@
#ifndef LOGVIEWER_H
#define LOGVIEWER_H
#include <QWidget>
#include <QTextEdit>
#include <QComboBox>
#include <QPushButton>
#include <QLineEdit>
#include <QLabel>
#include <QCheckBox>
class LogViewer : public QWidget
{
Q_OBJECT
public:
explicit LogViewer(QWidget *parent = nullptr);
~LogViewer() override = default;
private slots:
void onFilterChanged(const QString &text);
void onLevelChanged(int index);
void onClear();
void onExport();
void onAutoScrollToggled(bool enabled);
private:
void installMessageHandler();
void restoreMessageHandler();
static void logMessageHandler(QtMsgType type,
const QMessageLogContext &context,
const QString &msg);
QTextEdit *m_logView;
QLineEdit *m_filterEdit;
QComboBox *m_levelCombo;
QCheckBox *m_autoScroll;
QPushButton *m_clearBtn;
QPushButton *m_exportBtn;
QLabel *m_countLabel;
int m_logCount = 0;
static LogViewer *s_instance;
static QtMessageHandler s_oldHandler;
};
#endif
+28
View File
@@ -0,0 +1,28 @@
#include "LoggingPlugin.h"
#include "LogViewer.h"
#include "PluginContext.h"
#include "ServiceRegistry.h"
#include "IPluginServices.h"
#include "Logging.h"
bool LoggingPlugin::initialize(PluginContext *ctx)
{
if (ctx && ctx->services()) {
auto *dataProvider = ctx->services()->get<IDataProvider>();
if (dataProvider) {
qInfo(gcs_app) << "LoggingPlugin: IDataProvider available";
}
}
return true;
}
QWidget *LoggingPlugin::createWidget(QWidget *parent)
{
return new LogViewer(parent);
}
extern "C" {
__declspec(dllexport) IPlugin* createPlugin() {
return new LoggingPlugin();
}
}
+29
View File
@@ -0,0 +1,29 @@
#ifndef LOGGINGPLUGIN_H
#define LOGGINGPLUGIN_H
#include "IPlugin.h"
#include <QIcon>
#include <QWidget>
class LoggingPlugin : public QObject, public IPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "com.gcs.IPlugin/3.0" FILE "plugin.json")
Q_INTERFACES(IPlugin)
public:
QString name() const override { return QStringLiteral("logging"); }
QString title() const override { return QStringLiteral("Logging"); }
QString version() const override { return QStringLiteral("2.0.0"); }
QString description() const override { return QStringLiteral("Unified logging system with viewer"); }
QIcon icon() const override { return {}; }
bool initialize(PluginContext *) override;
void onActivated() override {}
void onDeactivated() override {}
void onClose() override {}
QWidget *createWidget(QWidget *parent = nullptr) override;
};
#endif
+21
View File
@@ -0,0 +1,21 @@
{
"$schema": "../schemas/plugin.schema.json",
"name": "logging",
"title": "Logging",
"version": "2.0.0",
"author": "GCS Team",
"description": "Unified logging system with log viewer panel",
"minEngineVersion": "2.0.0",
"entryPoint": "LoggingPlugin",
"activationEvents": [
"onStartup"
],
"contributes": {
"views": [
{
"id": "logging.viewer",
"label": "Logging"
}
]
}
}