[SOLVED] SIGNAL inherited from parent & Achievement pop up QWidget



  • Hi,

    I have a structure like this
    -Achievement (parent class)
    -AchievementRide2hours (child class)
    -ManagerAchievement (controller class)

    Achievement inherits from QObject, and AchievementRide2hours inhering from Achievement.
    I have defined this signal in Achievement (because all achievement needs to have this signal):
    @void achievementCompleted(Achievement achievement);@

    AchievementRide2Hours emit this achivement like this: (polymorphism doesn't seem to work here, so I cast) :
    @emit achievementCompleted((Achievement)this);@

    The problem arise when I try to connect AchievementRide2Hours SIGNAL with ManagerAchievement SLOT :
    @connect(achievement2hours, SIGNAL(achievementCompleted(Achievement)), this, SLOT(receiveAchievement(Achievement)));@

    cannot convert parameter 1 from 'AchievementRide2Hours' to 'const QObject *'

    So my question is this : Do I need my class to inherind directly from QObject to be able to use SIGNAL/SLOT? What is the problem with my structure? Coming from java, I don't see why it isn't working :)

    Thanks in advance!



  • Full code for reference :

    Achievement

    @class Achievement : public QObject
    {
    Q_OBJECT

    public:
    explicit Achievement(QObject *parent = 0);

    QString getName();
    

    signals:
    void achievementCompleted();

    protected :

    QString name;
    QString description;
    QString tooltip;
    bool completed;
    

    };
    @

    AchievementRide2Hours

    @class AchievementRide2Hours : public Achievement
    {
    Q_OBJECT

    public:
    AchievementRide2Hours();

    void setMinutesRode(int minutes);
    void updateMinutesRode(int minutes);
    

    private :
    void checkCompleted();

    int minuteRode;
    

    };
    @



  • Hi, first I think your AchievementRide2Hours class needs to define the Q_OBJECT macro, all QObjec based classes need that, also child classes.
    second, you try to cast Achievement* to Achievement as far as I can see that here!?
    @
    emit achievementCompleted((Achievement)this);
    @
    anyway in your signal you should use a reference (or better a pointer in this case), in your case you do most likely do a deep copy every time the signal is emitted and that might not be what you want?

    also c++ polymorphism should only be used with pointers, you cant simply cast an AchievementRide2Hours to Achievement, onyl if you have a pointer to that object (as far as I know at least).


  • Lifetime Qt Champion

    Hi,

    One more thing, you can't copy QObject nor QObject derived classes.

    Aside from the copy problem, why would you put the object itself has the signal parameter ? Just emit achieved and in the slot receiving that signal you can use sender() and retrieve the information you want from it.

    Hope it helps



  • Thanks guy for your valuable help, I used both your advice! source code updated up here.

    100% working :

    @ManagerAchievement::ManagerAchievement(QObject *parent)
    :QObject(parent) {

    achievement2hours = new AchievementRide2Hours();
    
    connect(achievement2hours, SIGNAL(achievementCompleted()), this, SLOT(receiveAchievement()));
    

    }

    void ManagerAchievement::receiveAchievement() {

    Achievement *achievement = ((Achievement*)sender());
    qDebug() << achievement->getName();
    

    }@


  • Lifetime Qt Champion

    Don't use a c-style cast for a QObject, use qobject_cast



  • Thanks, old java habits

    @Achievement *achievement = qobject_cast<Achievement *>(sender());@

    Now to learn how to make nice animation with Qt to show theses achievements :)


  • Lifetime Qt Champion

    QWidget ? QGraphicsView ? QML ?



  • All options are opens, I would just put a simple box popup in the center of a QDialog with some effect on it, any recommendation ? I'm using Qt 5.2.1 going to deploy on mac/win/linux not yet on mobile so I think i'd put QML outside for now.

    Thanks!


  • Lifetime Qt Champion

    AFAIK, the widgets are also running on mobile but might be less good looking.

    If you go the QML way, you might want to rebuild completely for it rather that have a separate product for mobile.



  • I was kinda surprised today when I found out the the base animation classes are part of the QtCore module itself (and not QtQuick or something).
    So you might be able to use the animation functions from QML in a widget project, but honestly I've not seen any examples for that anywhere, but it should be possible, if you don't want to use QML or already have a complex widget project and don't want to migrate that. Doing animation in QML is definitely easier and a major part of Qt Quick :)

    Even if you only want to build a desktop application I would still suggest using QML if you start the project fresh, but that is your choice of course. I don't want to do any weird comparisons but if you know Java you might want to compare Qt widgets projects to Java Swing and QML projects to JavaFX (or if you are a .net guy think of WIndows Forms/Qt widgets and WPF/QML), so it is a "complete" replacement for widget based projects. You can also embed a QML widget inside of your widget application if you need to.



  • Thanks guys,

    I'm pretty new with QML and QtQuick, if I want to use these things, I have to rewrite all source code for my interface correct? I was planning on using standard Qt and hope it works on mobile.. :) I already have too much source code done and i'm using outside libraries, Qwt, etc..

    I did a standard QWidget that appear at the bottom right corner of the QDialog.
    I'm trying to do something like Steam achievement (1:49 in" this video)":https://www.youtube.com/watch?v=zCO6uf6XXRw

    It is working good so far, only the position is hard-coded maybe i need to use the parentWidget size and figure out the bottom right corner somehow.

    Current code :

    @void AchievementWidget::startAnimate() {

    setVisible(true);
    
    /// Todo; put achievement icon here
    ui->label_icon->setStyleSheet("image: url(:/image/icon/burn)");
    

    // qDebug() << "X, y" << this->x() << this->y();
    // qDebug() << "width, height" << this->width() << this->height();

    QPropertyAnimation *animation = new QPropertyAnimation(this, "pos");
    animation->setDuration(1000);
    animation->setStartValue(QPoint(this->x() + this->width() - 190, this->y() + this->height() - 5) ) ;
    animation->setEndValue(QPoint(this->x() + this->width() - 190, this->y() + this->height() - 75 ) ) ;
    animation->start(QAbstractAnimation::DeleteWhenStopped);
    
    timerRemoveAnimation->start(2000);
    

    }

    /////////////////////////////////////////////////////////////////////////////////////////////
    void AchievementWidget::removeFromScreen() {

    QPropertyAnimation *animation = new QPropertyAnimation(this, "pos");
    animation->setDuration(1000);
    animation->setStartValue(QPoint(this->x() + this->width() - 190, this->y() + this->height() - 75 ) ) ;
    animation->setEndValue(QPoint(this->x() + this->width() - 190, this->y() + this->height() - 5) ) ;
    animation->start(QAbstractAnimation::DeleteWhenStopped);
    
    timerSetNotVisible->start(1000);
    

    }

    /////////////////////////////////////////////////////////////////////////////////////////////
    void AchievementWidget::setNotVisible() {

    setVisible(false);
    

    }
    @


  • Lifetime Qt Champion

    You should move the animation in the parent widget. AchievementWidget's task is just to show the achievements. The parent widget is responsible for showing it at the right place. Also moving the animation to the parent widget, you'll have access to the geometry of it and you can setup the animation cleanly.



  • Hey SGaist,
    I've been trying some idea on this AchievementWidget.

    Since the position of the Widget is always on the bottom right of the user screen, I coded the geometry directly in the Widget (not the parent). I also made the Widget parentless, so that it can be shown anywhere on the screen.

    Here is the result:
    https://www.dropbox.com/s/hvrgtvdx7f1s3pr/AchievementEx1.png

    As you can see, without a parent, the Widget is shown like a window, a taskbar item is added, as well with close, expand button on the window. and If I had a parent, the widget does not show because the location if outside of the parent widget geometry.

    I think I could fix it if I just find how to remove the QWidget frame and show it like it is when it has a parent (no frame, no topbar button..)

    Here is the current code :

    Instantiation in the parent class, notice no parent is passed here:
    @ achievementWidget = new AchievementWidget();
    achievementWidget->setAttribute(Qt::WA_TransparentForMouseEvents,true);
    achievementWidget->setVisible(false);@

    What is called when achievement is unlocked:
    @void AchievementWidget::startAnimate() {

    setVisible(true);
    
    /// Todo; put achievement icon here
    ui->label_icon->setStyleSheet("image: url(:/image/icon/burn)");
    
    
    /// Get bottom right corner of current screen
    QRect rectDesktop = QApplication::desktop()->availableGeometry();
    
    //    qDebug() << "rectDesktop size is" << rectDesktop;
    /// Widget Size is fixed to 190x75, bottom right corner
    QPoint bottonRight(rectDesktop.bottomRight());
    QPoint bottonRightBeforeAnim = QPoint(bottonRight.x() - 190, bottonRight.y());
    QPoint bottonRightAfterAnim =  QPoint(bottonRight.x() - 190, bottonRight.y() - 75);
    
    qDebug() << "point is" << bottonRightBeforeAnim;
    qDebug() << "point is" << bottonRightAfterAnim;
    
    QPropertyAnimation *animation = new QPropertyAnimation(this, "pos");
    animation->setDuration(1000);
    animation->setStartValue(bottonRightBeforeAnim) ;
    animation->setEndValue(bottonRightAfterAnim) ;
    animation->start(QAbstractAnimation::DeleteWhenStopped);
    
    timerRemoveAnimation->start(4000);
    

    }@

    Thanks!



  • Woot! fixed with theses flags in my QWidget :
    @ setAutoFillBackground(true);
    setAttribute(Qt::WA_NoMousePropagation);
    setWindowFlags(Qt::WindowStaysOnTopHint);
    setWindowFlags(Qt::X11BypassWindowManagerHint);
    setWindowFlags(Qt::FramelessWindowHint );@

    New result :
    https://www.dropbox.com/s/ei4w4796azo5boy/achievementV2Working.png


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.