QT中自定义类时使用多重继承问题原因及解决方法
- 创建一个名为LogTextEditEx的类继承自QTextEdit和Destination,出现了多重继承的访问权限问题;原因:;
class LogTextEditEx : public QTextEdit,Destination{}在Destination前少写了public;继承方式不正确,需要添加public继承,class LogTextEditEx : public QTextEdit,public Destination {}; - 在自定义类头文件中 添加Q_OBJECT // 确保有Q_OBJECT宏
- error: 'staticMetaObject' is not a member of
'QsLogging::Destination'
QMetaObject::SuperData::linkDestination::staticMetaObject(),
原因:这个错误表明在moc生成的代码中,它试图访问QsLogging::Destination的staticMetaObject,但是Destination类没有这个成员。这是因为Destination可能不是QObject的子类,而我们的LogTextEditEx类试图同时继承QObject和Destination。
在Qt中,如果一个类要使用信号槽(即包含Q_OBJECT宏),它必须直接或间接继承QObject。而QsLogging::Destination不是一个QObject派生类(它只是一个接口类)。因此,我们不能让一个类同时继承QObject和Destination,然后使用Q_OBJECT宏,因为moc会认为Destination也是一个QObject(但实际上不是)。
解决方法:最简单的,将QTextEdit继承时放在最前面即可,其它复杂的没试过;
cpp
#ifndef LOGTEXTEDITEX_H
#define LOGTEXTEDITEX_H
#include "QsLogDest.h"
#include <QTextEdit>
#include <QMutex>
#include <QObject>
using namespace QsLogging;
class LogTextEditEx : public QTextEdit,public Destination
{
Q_OBJECT // 确保有Q_OBJECT宏
public:
explicit LogTextEditEx(QWidget* parent = nullptr);
~LogTextEditEx();
void write(const QString &message, QsLogging::Level level) override;
bool isValid() override;
private:
struct LogMessage {
QString message;
int level;
};
QList<LogMessage> m_messageBuffer;
QMutex m_bufferMutex;
QTimer* m_updateTimer;
void init();
void updateTextEdit();
};
#endif // LOGTEXTEDITEX_H
cpp
#include "logtexteditex.h"
#include <QScrollBar>
#include <QTimer>
#include <QMutexLocker>
LogTextEditEx::LogTextEditEx(QWidget *parent)
: QTextEdit(parent)
{
init();
}
LogTextEditEx::~LogTextEditEx()
{
}
void LogTextEditEx::init()
{
// 设置为只读
setReadOnly(true);
// 设置字体
QFont font("Consolas", 9);
setFont(font);
// 创建定时器,批量更新UI以提高性能
m_updateTimer = new QTimer(this);
m_updateTimer->setInterval(100); // 100ms更新一次
connect(m_updateTimer, &QTimer::timeout,
this, &LogTextEditEx::updateTextEdit);
m_updateTimer->start();
}
void LogTextEditEx::write(const QString &message, QsLogging::Level level)
{
QMutexLocker locker(&m_bufferMutex);
m_messageBuffer.append({message, static_cast<int>(level)});
}
bool LogTextEditEx::isValid()
{
return true;
}
void LogTextEditEx::updateTextEdit()
{
QMutexLocker locker(&m_bufferMutex);
if (m_messageBuffer.isEmpty())
return;
// 批量处理日志消息
QList<LogMessage> messages = m_messageBuffer;
m_messageBuffer.clear();
locker.unlock();
// 准备HTML内容
QString html;
for (const auto& msg : messages) {
QString color;
switch (msg.level) {
case 0: color = "gray"; break; // Trace
case 1: color = "blue"; break; // Debug
case 2: color = "green"; break; // Info
case 3: color = "orange"; break; // Warn
case 4: color = "red"; break; // Error
case 5: color = "darkred"; break; // Fatal
default: color = "black";
}
html += QString("<span style='color:%1'>%2</span><br>")
.arg(color)
.arg(msg.message.toHtmlEscaped());
}
// 更新文本编辑框
QTextCursor cursor(document());
cursor.movePosition(QTextCursor::End);
cursor.insertHtml(html);
// 限制最大行数
const int maxLines = 1000;
int lineCount = document()->lineCount();
if (lineCount > maxLines) {
cursor.movePosition(QTextCursor::Start);
cursor.movePosition(QTextCursor::Down, QTextCursor::KeepAnchor,
lineCount - maxLines);
cursor.removeSelectedText();
}
// 自动滚动
verticalScrollBar()->setValue(verticalScrollBar()->maximum());
}