#include "MainPanel.h" #include #include #include #include #include #include #include #include #include "widgets/bubbletip.h" #include "widgets/chatView/chatwindow.h" #include "widgets/functionbutton.h" #include "widgets/maskoverlay.h" #include "widgets/statswidget.h" #include "widgets/userprofilewidget.h" #include "AVPlayer/avplayerwidget.h" #include "api/roomapi.h" #include "appevent.h" #include "widgets/recorderwidget.h" #include #include #include namespace IconUtils { QIcon createSettingsIcon() { QPixmap icon(24, 24); icon.fill(Qt::transparent); QPainter painter(&icon); painter.setRenderHint(QPainter::Antialiasing); // 绘制齿轮形状 painter.setPen(Qt::white); painter.setBrush(Qt::white); painter.drawEllipse(4, 4, 16, 16); painter.setPen(Qt::NoPen); painter.setBrush(QColor(64, 158, 255)); painter.drawEllipse(8, 8, 8, 8); painter.setBrush(Qt::white); painter.drawRect(11, 2, 2, 6); painter.drawRect(11, 16, 2, 6); painter.drawRect(2, 11, 6, 2); painter.drawRect(16, 11, 6, 2); return QIcon(icon); } QIcon createSearchIcon() { QPixmap icon(24, 24); icon.fill(Qt::transparent); QPainter painter(&icon); painter.setRenderHint(QPainter::Antialiasing); // 绘制放大镜 painter.setPen(Qt::white); painter.setBrush(Qt::white); painter.drawEllipse(2, 2, 14, 14); painter.setPen(Qt::NoPen); painter.setBrush(QColor(64, 158, 255)); painter.drawEllipse(4, 4, 10, 10); painter.setBrush(Qt::white); QPolygon handle; handle << QPoint(14, 14) << QPoint(20, 20) << QPoint(18, 22) << QPoint(12, 16); painter.drawPolygon(handle); return QIcon(icon); } QIcon createUserIcon() { QPixmap icon(24, 24); icon.fill(Qt::transparent); QPainter painter(&icon); painter.setRenderHint(QPainter::Antialiasing); // 绘制用户轮廓 painter.setPen(Qt::white); painter.setBrush(Qt::white); painter.drawEllipse(4, 2, 16, 16); // 头部 painter.drawRect(6, 18, 12, 4); // 身体 return QIcon(icon); } QIcon createAudioDeviceIcon() { QPixmap icon(24, 24); icon.fill(Qt::transparent); QPainter painter(&icon); painter.setRenderHint(QPainter::Antialiasing); // 绘制音频设备图标(麦克风+扬声器组合) painter.setPen(QPen(Qt::white, 1.5)); painter.setBrush(Qt::white); // 麦克风部分 painter.drawRoundedRect(3, 2, 6, 8, 2, 2); painter.drawLine(6, 10, 6, 13); painter.drawLine(4, 13, 8, 13); // 扬声器部分 painter.drawRect(13, 8, 3, 3); painter.drawPolygon(QPolygon() << QPoint(16, 8) << QPoint(19, 6) << QPoint(19, 13) << QPoint(16, 11)); painter.drawArc(20, 7, 2, 4, 0, 180 * 16); return QIcon(icon); } } // namespace IconUtils MainPanel::MainPanel(QWidget *parent) : QWidget(parent) , userProfile(nullptr) , chatView(nullptr) { // 初始化防抖定时器 m_debounceTimer = new QTimer(this); m_debounceTimer->setSingleShot(true); m_debounceTimer->setInterval(500); // 500ms防抖延迟 connect(m_debounceTimer, &QTimer::timeout, this, &MainPanel::handleDebouncedPlay); // setupUI userProfile = new UserProfileWidget(this); webSocketClient = new WebSocketClient(this); chatView = new ChatWindow(webSocketClient); chatView->setMinimumWidth(400); statsWidget = new StatsWidget(this); QWidget *rightWidget = new QWidget; QVBoxLayout *vbox = new QVBoxLayout(rightWidget); vbox->setContentsMargins(0, 0, 0, 0); vbox->addWidget(userProfile, 0); vbox->addWidget(statsWidget, 0); vbox->addWidget(chatView, 1); splitter = new QSplitter(Qt::Horizontal, this); playerContainer = new QWidget(this); splitter->addWidget(playerContainer); splitter->addWidget(rightWidget); splitter->setStretchFactor(0, 60); splitter->setStretchFactor(1, 30); QVBoxLayout *mainLayout = new QVBoxLayout(this); mainLayout->addWidget(splitter, 1); mainLayout->setContentsMargins(0, 0, 0, 0); mainLayout->setSpacing(0); setLayout(mainLayout); // 为playerContainer设置初始布局 QVBoxLayout *playerLayout = new QVBoxLayout(playerContainer); playerLayout->setContentsMargins(0, 0, 0, 0); buttonGroup = new PopoverButtonGroup(Qt::Horizontal, playerContainer); // 添加功能按钮 FunctionButton *settingsBtn = new FunctionButton(IconUtils::createSettingsIcon(), "设置", this); Popover *settingsPopover = new Popover(this); // settingsPopover->setContentWidget(settingsContent); buttonGroup->addButton(settingsBtn, settingsPopover); FunctionButton *searchBtn = new FunctionButton(IconUtils::createSearchIcon(), "搜索", this); Popover *searchPopover = new Popover(this); // searchPopover->setContentWidget(searchContent); buttonGroup->addButton(searchBtn, searchPopover); FunctionButton *userBtn = new FunctionButton(IconUtils::createUserIcon(), "用户", this); Popover *userPopover = new Popover(this); // userPopover->setContentWidget(userContent); buttonGroup->addButton(userBtn, userPopover); // 添加音频设备选择按钮 FunctionButton *audioDeviceBtn = new FunctionButton(IconUtils::createAudioDeviceIcon(), "音频设备", this); Popover *audioDevicePopover = new Popover(this); // // 使用解耦合版本的音频设备选择器 // m_audioDeviceSelectorDecoupled = new AudioDeviceSelectorIconDecoupled(this); // audioDevicePopover->setContentWidget(m_audioDeviceSelectorDecoupled); // 使用 RecorderAudioWidget 作为 Popover 内容(麦克风 + 扬声器) QWidget *audioContent = new QWidget(audioDevicePopover); QVBoxLayout *audioLayout = new QVBoxLayout(audioContent); audioLayout->setContentsMargins(8, 8, 8, 8); audioLayout->setSpacing(8); // 麦克风区域 QLabel *micTitle = new QLabel(tr("麦克风"), audioContent); micTitle->setStyleSheet("font-weight:600;"); m_micWidget = new QComboBox(audioContent); m_micWidget->setEditable(false); audioLayout->addWidget(micTitle); audioLayout->addWidget(m_micWidget); // 扬声器区域 QLabel *spkTitle = new QLabel(tr("扬声器"), audioContent); spkTitle->setStyleSheet("font-weight:600; margin-top:4px;"); m_speakerWidget = new QComboBox(audioContent); m_speakerWidget->setEditable(false); audioLayout->addWidget(spkTitle); audioLayout->addWidget(m_speakerWidget); // 新增:编码器区域 QLabel *encTitle = new QLabel(tr("视频编码器"), audioContent); encTitle->setStyleSheet("font-weight:600; margin-top:4px;"); m_encoderWidget = new QComboBox(audioContent); m_encoderWidget->setEditable(false); audioLayout->addWidget(encTitle); audioLayout->addWidget(m_encoderWidget); // 新增:录制控制区域 QLabel *controlTitle = new QLabel(tr("录制控制"), audioContent); controlTitle->setStyleSheet("font-weight:600; margin-top:8px;"); audioLayout->addWidget(controlTitle); // 选项区域 m_drawCursorCheckBox = new QCheckBox(tr("绘制鼠标指针"), audioContent); m_drawCursorCheckBox->setChecked(true); m_syncRecordCheckBox = new QCheckBox(tr("推流时同步录制"), audioContent); audioLayout->addWidget(m_drawCursorCheckBox); audioLayout->addWidget(m_syncRecordCheckBox); // 按钮区域 QHBoxLayout *buttonLayout = new QHBoxLayout(); m_recordButton = new QPushButton(tr("开始录制"), audioContent); m_streamButton = new QPushButton(tr("开始推流"), audioContent); m_settingsButton = new QPushButton(tr("设置"), audioContent); buttonLayout->addWidget(m_recordButton); buttonLayout->addWidget(m_streamButton); buttonLayout->addWidget(m_settingsButton); audioLayout->addLayout(buttonLayout); audioDevicePopover->setContentWidget(audioContent); // 将按钮与 Popover 关联 buttonGroup->addButton(audioDeviceBtn, audioDevicePopover); // 设备枚举与填充逻辑 auto populateAudioDevices = [this]() { // 清空缓存 m_micDevices.clear(); m_speakerDevices.clear(); // 获取麦克风列表 AMRECORDER_DEVICE *micArray = nullptr; int micCount = recorder_get_mics(&micArray); QStringList micNames; int defaultMicIndex = -1; for (int i = 0; i < micCount; ++i) { m_micDevices.push_back(micArray[i]); micNames << QString::fromUtf8(micArray[i].name); if (micArray[i].is_default && defaultMicIndex < 0) defaultMicIndex = i; } if (micArray) recorder_free_array(micArray); // 获取扬声器列表 AMRECORDER_DEVICE *spkArray = nullptr; int spkCount = recorder_get_speakers(&spkArray); QStringList spkNames; int defaultSpkIndex = -1; for (int i = 0; i < spkCount; ++i) { m_speakerDevices.push_back(spkArray[i]); spkNames << QString::fromUtf8(spkArray[i].name); if (spkArray[i].is_default && defaultSpkIndex < 0) defaultSpkIndex = i; } if (spkArray) recorder_free_array(spkArray); // 更新 UI 列表 if (m_micWidget) { m_micWidget->clear(); m_micWidget->addItems(micNames); } if (m_speakerWidget) { m_speakerWidget->clear(); m_speakerWidget->addItems(spkNames); } // 恢复或设置默认选择 if (m_micWidget) { if (defaultMicIndex >= 0 && defaultMicIndex < m_micDevices.size()) { m_micWidget->setCurrentText(QString::fromUtf8(m_micDevices[defaultMicIndex].name)); } else if (!micNames.isEmpty()) { m_micWidget->setCurrentIndex(0); } } if (m_speakerWidget) { if (defaultSpkIndex >= 0 && defaultSpkIndex < m_speakerDevices.size()) { m_speakerWidget->setCurrentText( QString::fromUtf8(m_speakerDevices[defaultSpkIndex].name)); } else if (!spkNames.isEmpty()) { m_speakerWidget->setCurrentIndex(0); } } // 将当前选择传递给 RecorderWidget(若存在) if (RecorderWidget *rec = qobject_cast(playerWidget)) { // 选中麦克风 if (m_micWidget) { const QString sel = m_micWidget->currentText(); for (const auto &d : m_micDevices) { if (sel == QString::fromUtf8(d.name)) { rec->setMicDevice(d); break; } } } // 选中扬声器 if (m_speakerWidget) { const QString sel = m_speakerWidget->currentText(); for (const auto &d : m_speakerDevices) { if (sel == QString::fromUtf8(d.name)) { rec->setSpeakerDevice(d); break; } } } } }; // 新增:编码器枚举与填充逻辑 auto populateEncoders = [this]() { m_encoderList.clear(); m_selectedEncoderId = -1; AMRECORDER_ENCODERS *encArray = nullptr; int encCount = recorder_get_vencoders(&encArray); QStringList encNames; for (int i = 0; i < encCount; ++i) { m_encoderList.push_back(encArray[i]); encNames << QString::fromUtf8(encArray[i].name); } if (encArray) recorder_free_array(encArray); if (m_encoderWidget) { m_encoderWidget->clear(); m_encoderWidget->addItems(encNames); if (!m_encoderList.isEmpty()) { m_encoderWidget->setCurrentIndex(0); m_selectedEncoderId = m_encoderList[0].id; } } if (RecorderWidget *rec = qobject_cast(playerWidget)) { if (m_selectedEncoderId >= 0) rec->setVideoEncoderId(m_selectedEncoderId); } }; // 首次填充设备和编码器 populateAudioDevices(); populateEncoders(); // 连接设备选择变化 -> 传给 RecorderWidget connect(m_micWidget, &QComboBox::currentTextChanged, this, [this](const QString &deviceName) { if (RecorderWidget *rec = qobject_cast(playerWidget)) { for (const auto &d : m_micDevices) { if (deviceName == QString::fromUtf8(d.name)) { rec->setMicDevice(d); break; } } } }); connect(m_speakerWidget, &QComboBox::currentTextChanged, this, [this](const QString &deviceName) { if (RecorderWidget *rec = qobject_cast(playerWidget)) { for (const auto &d : m_speakerDevices) { if (deviceName == QString::fromUtf8(d.name)) { rec->setSpeakerDevice(d); break; } } } }); // 新增:编码器选择变化 -> 传给 RecorderWidget connect(m_encoderWidget, QOverload::of(&QComboBox::currentIndexChanged), this, [this](int index) { if (index >= 0 && index < m_encoderList.size()) { m_selectedEncoderId = m_encoderList[index].id; if (RecorderWidget *rec = qobject_cast(playerWidget)) { rec->setVideoEncoderId(m_selectedEncoderId); } } }); // 新增:录制控制按钮信号连接 connect(m_recordButton, &QPushButton::clicked, this, &MainPanel::onRecordButtonClicked); connect(m_streamButton, &QPushButton::clicked, this, &MainPanel::onStreamButtonClicked); connect(m_settingsButton, &QPushButton::clicked, this, &MainPanel::onSettingsButtonClicked); // 维持原有的AudioDeviceSelectorIcon兼容代码(保持注释) // m_audioDeviceSelector = new AudioDeviceSelectorIcon(this); // connect(m_audioDeviceSelector, &AudioDeviceSelectorIcon::microphoneDeviceSelected, // this, [this](const AudioDeviceInfo& device) { // qDebug() << "[MainPanel] 麦克风设备已选择(兼容模式):" << device.name; // // 通知AvRecorder进行设备切换 // if (AvRecorder *avRecorder = qobject_cast(playerWidget)) { // //avRecorder->switchMicrophoneDevice(device.id, device.name); // } // }); // connect(m_audioDeviceSelector, &AudioDeviceSelectorIcon::speakerDeviceSelected, // this, [this](const AudioDeviceInfo& device) { // qDebug() << "[MainPanel] 扬声器设备已选择:" << device.name; // // 通知AvRecorder进行设备切换 // if (AvRecorder *avRecorder = qobject_cast(playerWidget)) { // // avRecorder->switchSpeakerDevice(device.id, device.name); // } // }); // 添加一个动作按钮到按钮组(没有Popover) FunctionButton *actionButton = new FunctionButton(IconUtils::createSettingsIcon(), "执行操作", this); buttonGroup->addButton(actionButton, nullptr); // 将buttonGroup添加到playerContainer的布局中 playerLayout = qobject_cast(playerContainer->layout()); if (!playerLayout) { playerLayout = new QVBoxLayout(playerContainer); playerLayout->setContentsMargins(0, 0, 0, 0); } playerLayout->addStretch(1); // 添加弹性空间,将buttonGroup推到底部 playerLayout->addWidget(buttonGroup, 0); // 添加buttonGroup到底部,不拉伸 buttonGroup->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); // 使用固定大小策略 // initConnect connect(AppEvent::instance(), &AppEvent::connectionStateChanged, this, [this](bool connected) { if (userProfile) { userProfile->setStatus(connected ? "在线" : "离线"); } }); connect(userProfile, &UserProfileWidget::logoutClicked, this, &MainPanel::logoutClicked); connect(webSocketClient, &WebSocketClient::statsUpdate, statsWidget, &StatsWidget::updateStats); connect(webSocketClient, &WebSocketClient::liveStatus, this, [this](const QString &msg) { // 这里可以处理 liveStatus 相关逻辑 QJsonParseError err; QJsonDocument doc = QJsonDocument::fromJson(msg.toUtf8(), &err); if (err.error != QJsonParseError::NoError || !doc.isObject()) { qDebug() << "[MainPanel] liveStatus: 解析失败" << err.errorString(); return; } QJsonObject obj = doc.object(); int liveStatus = obj.value("liveStatus").toInt(0); // 默认-1 if (liveStatus == 1) { qDebug() << "[MainPanel] liveStatus: 直播中" << chatView; if (chatView) { const QString id = webSocketClient->roomId(); // 使用防抖机制处理频繁的请求 m_pendingRoomId = id; m_debounceTimer->start(); // 重新开始计时,如果在500ms内再次收到请求,会重置定时器 } // 你的处理逻辑 } else if (liveStatus == 2) { qDebug() << "[MainPanel] liveStatus: 未开播"; // 你的处理逻辑 } else { qDebug() << "[MainPanel] liveStatus: 未知状态" << liveStatus; } }); } MainPanel::~MainPanel() { if (userProfile) { delete userProfile; userProfile = nullptr; } if (m_recorderStandalone) { m_recorderStandalone->deleteLater(); m_recorderStandalone = nullptr; } if (m_avPlayerStandalone) { m_avPlayerStandalone->deleteLater(); m_avPlayerStandalone = nullptr; } if (m_chatStandalone) { m_chatStandalone->deleteLater(); m_chatStandalone = nullptr; } } void MainPanel::setRole(const QStringList &roleList) { QWidget *newPlayer = nullptr; if (roleList.contains("role.admin")) { newPlayer = new RecorderWidget(this); } else { newPlayer = new AVPlayerWidget(this); } setPlayerWidget(newPlayer); // 设置初始化信息 const QString &name = AppEvent::instance()->userName(); userProfile->setUsername(name); } void MainPanel::setPushRoomId(const QString &id) { // 推流配置 if (RecorderWidget *recorderWidget = qobject_cast(playerWidget)) { RecorderWidget::Settings settings; settings.liveUrl = "rtmp://106.55.186.74:1935/stream/V1"; settings.liveName = id.toStdString(); recorderWidget->setSettings(settings); } // 重新进入房间 chatView->initWebsocket(id); if (m_chatStandalone) { m_chatStandalone->initWebsocket(id); } if (AVPlayerWidget *playWidget = qobject_cast(playerWidget)) { MaskOverlay::instance()->show(nullptr, 0, MaskOverlay::ActiveWindow); QFuture getRoomFuture = getRoomApi(id); QtPromise::QPromise roomListPromise = QtPromise::resolve(getRoomFuture); roomListPromise .then([this, playWidget, id](const HttpResponse &response) { qDebug() << response.code << response.data << response.message; if (response.code != 0) { BubbleTip::showTip(this, response.message, BubbleTip::Top, 3000); return; } RoomInfo roomInfo = JsonMapper::formJsonEx(response.data.toObject()); qDebug() << "roomInfo.liveStatus.has_value()" << roomInfo.liveStatus.has_value(); int status = roomInfo.liveStatus.value_or(0); if (status == 1) { qDebug() << "open" << ("rtmp://106.55.186.74:1935/stream/V1/" + id); playWidget->play("rtmp://106.55.186.74:1935/stream/V1/" + id); } }) .finally([]() { MaskOverlay::instance()->hide(); }); } } void MainPanel::setPlayerWidget(QWidget *newPlayer) { if (playerWidget) { playerWidget->setParent(nullptr); playerWidget->deleteLater(); } playerWidget = newPlayer; playerWidget->setParent(playerContainer); // 获取现有布局并清理(保留buttonGroup) QVBoxLayout *vbox = qobject_cast(playerContainer->layout()); if (vbox) { // 清理除了buttonGroup之外的所有项目 QLayoutItem *item; while (vbox->count() > 0) { item = vbox->takeAt(0); if (item->widget() && item->widget() != buttonGroup) { item->widget()->setParent(nullptr); } if (item->spacerItem()) { delete item; // 删除spacer } else if (item->widget() != buttonGroup) { delete item; } } } else { // 如果没有布局或布局类型不对,创建新的 if (playerContainer->layout()) { delete playerContainer->layout(); } vbox = new QVBoxLayout(playerContainer); vbox->setContentsMargins(0, 0, 0, 0); } // 重新添加组件:播放器在上,buttonGroup在下 vbox->addWidget(playerWidget, 1); // 添加拉伸因子,让播放器组件占据所有可用空间 vbox->addWidget(buttonGroup, 0); // 添加buttonGroup到底部,不拉伸 // 确保播放器组件能够正确拉伸 playerWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); // 确保buttonGroup固定在底部 buttonGroup->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); // 使用固定大小策略 // 如果新的 player 是 RecorderWidget,则同步当前选择的音频设备 if (RecorderWidget *rec = qobject_cast(playerWidget)) { if (m_micWidget) { const QString sel = m_micWidget->currentText(); for (const auto &d : m_micDevices) { if (sel == QString::fromUtf8(d.name)) { rec->setMicDevice(d); break; } } } if (m_speakerWidget) { const QString sel = m_speakerWidget->currentText(); for (const auto &d : m_speakerDevices) { if (sel == QString::fromUtf8(d.name)) { rec->setSpeakerDevice(d); break; } } } // 同步编码器 if (m_selectedEncoderId >= 0) { rec->setVideoEncoderId(m_selectedEncoderId); } else if (m_encoderWidget && m_encoderWidget->count() > 0 && !m_encoderList.isEmpty()) { int idx = m_encoderWidget->currentIndex(); if (idx >= 0 && idx < m_encoderList.size()) { rec->setVideoEncoderId(m_encoderList[idx].id); } } } } void MainPanel::handleDebouncedPlay() { // 防抖处理后的播放逻辑 if (m_pendingRoomId.isEmpty() || !chatView) { return; } if (AVPlayerWidget *playWidget = qobject_cast(playerWidget)) { if (!m_isStartingPlay) { m_isStartingPlay = true; qDebug() << "[MainPanel] 防抖处理后开始播放:" << m_pendingRoomId; playWidget->play("rtmp://106.55.186.74:1935/stream/V1/" + m_pendingRoomId); m_isStartingPlay = false; // 如果 startToPlay 是同步的 } } // 清空待处理的房间ID m_pendingRoomId.clear(); } void MainPanel::initAudioDeviceSelectors() { // 注册音频设备选择器工厂 // DeviceManager* deviceManager = DeviceManager::instance(); // AudioDeviceSelectorFactory* audioFactory = new AudioDeviceSelectorFactory(this); // deviceManager->registerFactory("audio", audioFactory); // // 创建麦克风和扬声器选择器 // m_microphoneSelector = deviceManager->createSelector("audio", "microphone"); // m_speakerSelector = deviceManager->createSelector("audio", "speaker"); // // 设置到解耦版本的UI组件 // if (m_audioDeviceSelectorDecoupled) { // m_audioDeviceSelectorDecoupled->setMicrophoneSelector(m_microphoneSelector); // m_audioDeviceSelectorDecoupled->setSpeakerSelector(m_speakerSelector); // } qDebug() << "[MainPanel] 音频设备选择器初始化完成"; } void MainPanel::showRecorderStandalone() { if (!m_recorderStandalone) { m_recorderStandalone = new RecorderWidget(nullptr); m_recorderStandalone->setAttribute(Qt::WA_DeleteOnClose, false); connect(m_recorderStandalone, &QObject::destroyed, this, [this]() { m_recorderStandalone = nullptr; }); m_recorderStandalone->setWindowTitle(tr("RecorderWidget")); } m_recorderStandalone->show(); m_recorderStandalone->raise(); m_recorderStandalone->activateWindow(); } void MainPanel::showPlayerStandalone() { if (!m_avPlayerStandalone) { m_avPlayerStandalone = new AVPlayerWidget(nullptr); m_avPlayerStandalone->setAttribute(Qt::WA_DeleteOnClose, false); connect(m_avPlayerStandalone, &QObject::destroyed, this, [this]() { m_avPlayerStandalone = nullptr; }); m_avPlayerStandalone->setWindowTitle(tr("AVPlayerWidget")); } m_avPlayerStandalone->show(); m_avPlayerStandalone->raise(); m_avPlayerStandalone->activateWindow(); } void MainPanel::showChatStandalone() { if (!m_chatStandalone) { m_chatStandalone = new ChatWindow(webSocketClient); m_chatStandalone->setAttribute(Qt::WA_DeleteOnClose, false); connect(m_chatStandalone, &QObject::destroyed, this, [this]() { m_chatStandalone = nullptr; }); m_chatStandalone->setMinimumWidth(400); m_chatStandalone->setWindowTitle(tr("ChatWindow")); // 同步当前房间 if (webSocketClient) { const QString rid = webSocketClient->roomId(); if (!rid.isEmpty()) { m_chatStandalone->initWebsocket(rid); } } } m_chatStandalone->show(); m_chatStandalone->raise(); m_chatStandalone->activateWindow(); } void MainPanel::showChatEmbedded() { if (chatView) { chatView->show(); chatView->raise(); } if (m_chatStandalone) { m_chatStandalone->hide(); } } // 新增:录制控制按钮的槽函数实现 void MainPanel::onRecordButtonClicked() { if (RecorderWidget *rec = qobject_cast(playerWidget)) { // 同步选项设置到RecorderWidget // 注意:这里需要RecorderWidget提供设置选项的接口 // 调用RecorderWidget的录制方法 rec->onRecordButtonClicked(); // 更新按钮文本 if (m_recordButton) { if (m_recordButton->text() == tr("开始录制")) { m_recordButton->setText(tr("停止录制")); } else { m_recordButton->setText(tr("开始录制")); } } } } void MainPanel::onStreamButtonClicked() { if (RecorderWidget *rec = qobject_cast(playerWidget)) { // 同步选项设置到RecorderWidget // 调用RecorderWidget的推流方法 rec->onStreamButtonClicked(); // 更新按钮文本 if (m_streamButton) { if (m_streamButton->text() == tr("开始推流")) { m_streamButton->setText(tr("停止推流")); } else { m_streamButton->setText(tr("开始推流")); } } } } void MainPanel::onSettingsButtonClicked() { if (RecorderWidget *rec = qobject_cast(playerWidget)) { // 调用RecorderWidget的设置方法 rec->onSettingsButtonClicked(); } }