可点击的QLabel类"multiply defined"函数

Clickable QLabel class "multiply defined" functions

本文关键字:multiply defined 函数 QLabel      更新时间:2023-10-16

从VC++到Qt风格的插槽/信号编程时遇到了问题。我想创建一个带有图像的按钮,当点击时,它会变为另一个图像,当释放时,它又会变回原来的图像。我创建了一个名为ClickableQLabel的类,它继承了QLabel,但它告诉我某些函数是重新定义的。具体地说,是emit-ted。

主程序.cpp

#include "MainProgram.h"
#include <QApplication>
int main(int argc, char *argv[]) {
    QApplication a(argc, argv);
    CodeVault w;
    w.show();
    return a.exec();
}

主程序.h

#ifndef MAINPROGRAM_H
#define MAINPROGRAM_H
#include <QMainWindow>
#include "clickableqlabel.h"
namespace Ui {
class MainProgram;
}
class MainProgram : public QMainWindow
{
    Q_OBJECT
public:
    explicit MainProgram(QWidget *parent = 0);
    ~MainProgram();
private:
    Ui::MainProgram *ui;
};
#endif // MAINPROGRAM_H

可点击标签.h

#ifndef CLICKABLEQLABEL_H
#define CLICKABLEQLABEL_H
#include <QLabel>
#include <QMouseEvent>
using namespace Qt;
class ClickableQLabel : public QLabel {
    Q_OBJECT
    QPixmap pushed;
    QPixmap unpushed;
public:
    ClickableQLabel(QWidget *parent = 0);
    void mousePressEvent(QMouseEvent *eve );
    void mouseReleaseEvent(QMouseEvent *eve );
    void setPushed(QPixmap &p);
    void setUnpushed(QPixmap &p);
signals:
    void leftButtonPressed(ClickableQLabel* sender);
    void leftButtonReleased(ClickableQLabel* sender);
};
#endif // CLICKABLEQLABEL_H

可点击qlabel.cpp

#include "clickableqlabel.h"
ClickableQLabel::ClickableQLabel(QWidget *parent) : QLabel(parent){
    // set up qlabel
}

void ClickableQLabel::setPushed(QPixmap &p){
    pushed = p;
}
void ClickableQLabel::setUnpushed(QPixmap &p){
    unpushed = p;
}
void ClickableQLabel::leftButtonPressed(ClickableQLabel* sender){
    if(!pushed.isNull())
        sender->setPixmap(pushed.scaledToWidth(sender->width()));
}
void ClickableQLabel::leftButtonReleased(ClickableQLabel* sender){
    if(!unpushed.isNull())
        sender->setPixmap(unpushed.scaledToWidth(sender->width()));
}
void ClickableQLabel::mousePressEvent(QMouseEvent *eve ){
    if(eve->button() == Qt::LeftButton){
        emit leftButtonPressed(this);
    }
}
void ClickableQLabel::mouseReleaseEvent(QMouseEvent *eve ){
    if(eve->button() == Qt::LeftButton){
        emit leftButtonReleased(this);
    }
}

我收到的是以下3个错误:

moc_clickableqlabel.obj:-1: error: LNK2005: "public: void __cdecl ClickableQLabel::leftButtonPressed(class ClickableQLabel *)" (?leftButtonPressed@ClickableQLabel@@QEAAXPEAV1@@Z) already defined in clickableqlabel.obj
moc_clickableqlabel.obj:-1: error: LNK2005: "public: void __cdecl ClickableQLabel::leftButtonReleased(class ClickableQLabel *)" (?leftButtonReleased@ClickableQLabel@@QEAAXPEAV1@@Z) already defined in clickableqlabel.obj
debugCodeVault.exe:-1: error: LNK1169: one or more multiply defined symbols found

导致错误的两个函数是clickableqlabel.h文件中的两个信号。我应该如何设置connect功能,在哪里?

您不应该为信号提供实现。您只需在类标头中声明信号。Qt-moc提供了一种实现,该实现负责在信号发出时调用时隙connected。因为您提供的是一个实现,而Qt-moc提供的是另一个,所以您最终会得到两个不同的实现,并且链接器会抱怨。

因此,要在发出信号时执行某段代码,可以将其放在连接到该信号的某个插槽中,也可以在发出信号之前手动执行。

另一件需要注意的事情是,您的信号有一个名为sender的参数。通常不需要这样做,QObject::sender()提供了类似的功能。

我应该如何设置连接功能以及在哪里设置?

例如,当您在MainProgram窗口中实例化ClickableQLabel时(您可以通过在.ui表单文件中使用ClickableQLabel来执行此操作),您可以将connect的信号MainProgram的插槽,如下所示。

主程序.h

#ifndef MAINPROGRAM_H
#define MAINPROGRAM_H
#include <QMainWindow>
#include "clickableqlabel.h"
namespace Ui {
class MainProgram;
}
class MainProgram : public QMainWindow
{
    Q_OBJECT
public:
    explicit MainProgram(QWidget *parent = 0);
    ~MainProgram();
public slots:
    void labelPressed();
    void labelReleased();
private:
    Ui::MainProgram *ui;
};
#endif // MAINPROGRAM_H

然后在构造函数connect中,ClickableQLabel的信号到MainProgram的插槽,类似于这样:

connect(clickableLabel, SIGNAL(leftButtonPressed()), this, SLOT(labelPressed()));

其中clickableLabel是您的ClickableQLabel对象。

您不应该显式定义信号"函数"——它们只是被发射的(就像您在mousePressEvent()mouseReleaseEvent()函数中所做的那样)。

如果要执行某些操作(如setPixmap),可以在连接到这些信号的插槽函数中执行,也可以直接在mousePressEventmouseReleaseEvent函数中执行。

不相关,但您可能还需要执行类似qRegisterMetaType<ClickableQLabel>()的操作,才能将该数据类型与信号/插槽机制一起使用。

您不需要对QLabel进行子类化即可实现这一点:在MainWindow类中放置一个onLabelButtonClicked插槽(方法),该插槽连接到QPushButton clicked()信号,并根据需要调用setText/setIcon。

如果你想重用这个可点击元素,你当然可以把它封装在一个类中,但只有在定义新类型的小部件时,Qt才需要子类化和处理原始事件;如果您只是编写标准功能(单击、调整外观),那么主窗口/对话框类上的槽通常就足够了。