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:
@@ -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"
|
||||
)
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user