【问题标题】:Qt custom SLOT of subclass not recognised by CONNECTCONNECT 无法识别子类的 Qt 自定义 SLOT
【发布时间】:2017-08-31 14:34:32
【问题描述】:

背景

我正在用 Qt 编写一个媒体播放器应用程序。我将 QMediaPlayer 子类化并创建了一个新的 SLOT,它能够解释一个 int 并将其作为 qint64 传递给 QMediaPlayer::SetPosition(qint64)。

QMediaPlayer::PositionChanged 向 cslider slider_playback(水平滑块子类)触发一个信号。这使滑块在播放歌曲时移动。还有一些子类标签(clabel)接收关于歌曲时长和歌曲播放位置的信号。

问题

我在构建和运行时遇到的问题,我收到以下错误:

正在启动 /home/daniel/DeveloperProjects/build-Player-Desktop_Qt_5_9_1_GCC_64bit-Debug/Player...

QObject::connect: No such slot QMediaPlayer::set_playback_position(int) in ../Player/mainwindow.cpp:23

QObject::connect:(发送者名称:'slider_playback')

滑块应该能够控制播放的位置。有问题的代码行之前是文件中的“// Player seek”注释。

我认为该错误表明 SLOT 引用了基类,而插槽实际上是派生类的一部分。

为什么会出现这个错误,什么操作可以解决这个问题?我的 clabel 和 cslider 类中的插槽可以正常工作。不同之处在于这些类具有构造函数和析构函数。我没有在 QMediaPlayer 子类中实现构造函数,因为我不想覆盖基类构造函数。

cmediaplayer.h(完整文件)

#ifndef CMEDIAPLAYER_H
#define CMEDIAPLAYER_H

#include <QMediaPlayer>
//#include <QObject>

class cmediaplayer : public QMediaPlayer
{
    Q_OBJECT

public slots:
    void set_playback_position(int);
};

#endif // CMEDIAPLAYER_H

cmediaplayer.cpp(完整文件)

#include "cmediaplayer.h"

void cmediaplayer::set_playback_position(int v) {
    this->setPosition( (qint64)v );
}

mainwindow.h(完整文件)

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QMediaPlayer>
#include "cmediaplayer.h"
#include "clabel.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private:
    Ui::MainWindow *ui;
    QPalette m_pal;
    QString media_file_str="/usr/share/example-content/Ubuntu_Free_Culture_Showcase/Jenyfa Duncan - Australia.ogg";
    //QMediaPlayer * player ;
    cmediaplayer * player; // My custom type

private slots:
    void on_pushButton_pressed();
    void on_pushButton_released();
    void on_button_playback_clicked();
};

mainwindow.cpp(完整文件)

#include "mainwindow.h"
#include "ui_mainwindow.h"


MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow) {
    ui->setupUi(this);

    //player = new QMediaPlayer;
    player = new cmediaplayer; // My custom type

    // set max time on playback slider
    connect(player, SIGNAL(durationChanged(qint64)), ui->slider_playback, SLOT(set_qint64_max(qint64)));

    // st max time on playback label
    connect(player, SIGNAL(durationChanged(qint64)), ui->label_track_length, SLOT(setIntText(qint64)));

    // set slider playback position
    connect(player, SIGNAL(positionChanged(qint64)), ui->label_track_position, SLOT(setIntText(qint64)));


    // Player seek
    connect(ui->slider_playback,
        SIGNAL(valueChanged(int)),
        player,
        SLOT(set_playback_position(int)));


    // Player volume
    connect(ui->slider_volume,SIGNAL(valueChanged(int)),player,SLOT(setVolume(int)));
    ui->slider_volume->setValue(50); // set player initial value
}

MainWindow::~MainWindow() {
    delete ui;
    delete player;
    //delete playlist;
}

void MainWindow::on_pushButton_pressed() {
    m_pal=this->palette().color(QPalette::Background);
    QPalette pal=palette();
    pal.setColor(QPalette::Background,Qt::gray);
    this->setAutoFillBackground(true);
    this->setPalette(pal);

    player->setMedia(QUrl::fromLocalFile(media_file_str));
    player->setPlaybackRate(1);
    player->play();
}

void MainWindow::on_pushButton_released() {
    QPalette pal=m_pal;
    this->setAutoFillBackground(true);
    this->setPalette(pal);
    //player->stop();
}

void MainWindow::on_button_playback_clicked()
{
    //player->play();
}

【问题讨论】:

  • 似乎在编译时另一行被注释掉了://QMediaPlayer * player ; cmediaplayer * player; // My custom type 并以大写字母开始类名(编码约定)。
  • @AlexanderVX QMediaPlayer 是原始对象。我用编译好的 cmedia 播放器替换它。我把它留在那里是为了发表评论
  • 好吧,它为你编译是令人鼓舞的@eyllanesc 我重新启动了 Qt(再次),现在它在抱怨:在函数 cmediaplayer::cmediaplayer() 中未定义对 cme​​diaplayer 的 vtable 的引用 collect2:error: ld 返回1 退出状态真的让我很困惑,因为我没有改变任何东西!
  • @eyllanesc drive.google.com/open?id=0B4QUZRlxzP4hUFQ0UkdzWEZCc00 我已经删除了 *.h 和 *.cpp 文件中的一些未使用的东西来整理一下
  • @eyllanesc 我已经删除了构建文件,并重新编译了所有内容,它清除了我遇到的错误。现在似乎可以工作了!

标签: c++ qt qt5 qt-signals qt-slot


【解决方案1】:

Qt 创建了一个新类,它实现了插槽和信号之间的实际连接,但很多时候这个类没有更新。它们引用的类具有类似于 moc_xxx.cpp 的名称,它们是在 build 文件夹中创建的。

要强制他们更新,我们必须单击位于 QtCreator 菜单构建中的 ma​​ke clean 子菜单,然后在同一菜单中run qmake

或者您可以手动删除构建文件夹并重新编译

【讨论】:

  • 在这种情况下,我必须使用 os 文件系统手动删除构建文件
【解决方案2】:

也许,它可以帮助某人。尝试在连接调用中使用 SLOT 函数时,我遇到了类似的问题。即使在子类中声明并定义了 slot,connect 函数也无法识别它,并发出一条消息,指出 slot 函数不是基类的一部分。

就我而言,问题在于我没有将Q_OBJECT 放在类声明的开头。之后,我不得不清理(否则在编译步骤中会出现各种错误)并再次构建项目以使插槽功能正常工作。

【讨论】:

  • 不再推荐使用 SLOT 宏,因为它有几个缺点,例如连接没有在编译时验证但在执行时,我建议使用新的连接语法:wiki.qt.io/New_Signal_Slot_Syntax .另一方面,只有在创建 MOC 生成的槽、信号、Q_INVOKABLE、Q_PROPERTY、Q_ENUMS 等时才需要使用 Q_OBJECT。你指出的问题很经典。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-05-20
  • 2017-09-20
  • 1970-01-01
  • 1970-01-01
  • 2014-06-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多