Получение сообщения об ошибке «выделение объекта типа абстрактного класса в Juce Framework? - PullRequest
0 голосов
/ 01 апреля 2020

Я новичок в juce и получаю сообщение об ошибке типа «выделение объекта абстрактного класса типа« CreateAccount »». Я новичок в c ++. я пытаюсь вызвать класс из главного окна Juce и получаю ошибку, как это. Ниже мой код

Main. cpp файл

#include <JuceHeader.h>
#include "CreateAccount.h"

//==============================================================================
class TestApplication  : public JUCEApplication
{
public:
    //==============================================================================
    TestApplication() {
    }

    const String getApplicationName() override  {
        return "Test";
    }
    const String getApplicationVersion() override    { return "1.0.0"; }

    void initialise (const String&) override         {
        mainWindow.reset (new MainWindow ("Test", new CreateAccount(), *this));
     //  splash = new SplashScreen("Welcome to Screen!",ImageFileFormat::loadFrom(File("/Resources/bell.png")),
                             //    true);

       // splash->deleteAfterDelay(RelativeTime::seconds(5), false);
    }

       void shutdown() override {
        mainWindow = nullptr;
    }

private:
    class MainWindow    : public DocumentWindow
    {
    public:
        MainWindow (const String& name, Component* c, JUCEApplication& a)
                : DocumentWindow (name, Desktop::getInstance().getDefaultLookAndFeel()
                                          .findColour (ResizableWindow::backgroundColourId),
                                  DocumentWindow::allButtons),
                  app (a)
        {
            setUsingNativeTitleBar (true);
            setContentOwned (c, true);

#if JUCE_ANDROID || JUCE_IOS
            setFullScreen (true);
#else
            setResizable (true, false);
            setResizeLimits (300, 250, 10000, 10000);
            centreWithSize (getWidth(), getHeight());
#endif

            setVisible (true);
        }

        void closeButtonPressed() override
        {
            app.systemRequestedQuit();
        }


    private:
        JUCEApplication& app;


        //==============================================================================
        JUCE_DECLARE_NON_COPYABLE (MainWindow)
    };

    std::unique_ptr<MainWindow> mainWindow;


};

//==============================================================================
START_JUCE_APPLICATION (TestApplication)

CreateAccount.h файл

#include <JuceHeader.h>

//new page for create profile
class CreateAccount : public Component,
                        public Button::Listener

        {
public:
    CreateAccount() {

        addAndMakeVisible(lblloginwithfb);
        lblloginwithfb.setFont(Font(18.0f));
        lblloginwithfb.setText("Login with Facebook", dontSendNotification);
        lblloginwithfb.setColour(Label::textColourId, Colours::white);

        //ready to play button
        btncreteprofile.setButtonText("Create your profile");
        btncreteprofile.setColour(TextButton::textColourOffId, Colours::white);
        btncreteprofile.setColour(TextButton::textColourOnId, Colours::white);
        btncreteprofile.setColour(TextButton::buttonColourId,  Colour::fromRGB(235,135,15));
        btncreteprofile.setColour(TextButton::buttonOnColourId, Colour::fromRGB(235,135,15));
        addAndMakeVisible(btncreteprofile);

    }
    //==============================================================================
    void paint(Graphics &g) override {
        g.fillAll(Colours::black);
    }

    void resized() override {

        /*Rectangle<int> bounds = getLocalBounds();
        FlexBox flexBox;

        flexBox.flexDirection = FlexBox::Direction::column;
        flexBox.flexWrap = FlexBox::Wrap ::noWrap;
        flexBox.alignContent = FlexBox::AlignContent::center;

        Array<FlexItem> itemarray;
        itemarray.add(FlexItem(80,50,btncreteprofile));
        itemarray.add(FlexItem(getWidth(),50,lblloginwithfb));


        flexBox.items = itemarray;
        flexBox.performLayout(bounds.removeFromBottom(200));*/
        Rectangle<int> bounds = getLocalBounds();
        const int insetX = getWidth() / 4;
        const int insetY = getHeight() / 4;


        btncreteprofile.setBounds(insetX,bounds.getCentre().y+80,getWidth() - insetX * 2, 50);
        lblloginwithfb.setBounds(insetX,insetY,getWidth() - insetX * 2,getHeight());

    }

private:
    //==============================================================================
    // Your private member variables go here...
    Label lblloginwithfb;
    TextButton btncreteprofile;

    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CreateAccount)
};

Пожалуйста, помогите мне, когда я попытаюсь добавить список в файл createaccount, тогда получит ошибку.

Ответы [ 2 ]

2 голосов
/ 04 апреля 2020

В JUCE большинство вещей, связанных с пользовательским интерфейсом, реализованы как подкласс компонента.

Некоторые из подклассов имеют концепцию компонента содержимого: все подклассы ResizableWindow, который добавляет setContentOwned() и setContentNonOwned() методы, унаследованные всеми подклассами ResizableWindow (особенно DocumentWindow).

Чтобы определить содержание DocumentWindow, пример кода в вашем вопросе использует setContentOwned() в MainWindow конструктор, который он получает из initialise() в TestApplication.

Для реализации навигации вы можете сделать следующее (есть другие способы сделать это):

1. Реализуйте навигацию в MainWindow, чтобы у вас была навигационная логика c в одном центральном месте

2. Дайте каждой из ваших «Страниц» (давайте на один шаг назовем Страницу) указатель на MainWindow. Для CreateAccount это будет

Файл CreateAccount.h:

void setMainWindow(MainWindow * _mainWindow)
{
  mainWindow = _mainWindow;
}

3. Также добавьте переменную экземпляра где-нибудь в класс CreateAccount:

MainWindow * mainWindow;

и обновите конструктор:

CreateAccount()
  : mainWindow(nullptr)
{
  // ...
}

4. Измените код создания

и замените

mainWindow.reset (new MainWindow ("Test", new CreateAccount(), *this));

на:

CreateAccount * ca = new CreateAccount();
MainWindow * mw = new MainWindow ("Test", ca, *this)
ca->setMainWindow(mw);
mainWindow.reset(mw);

5. Реализуйте навигацию с помощью набора пользовательских методов (необходимо опубликовать c) в MainWindow, например,

public:
void createProfileClicked()
{
   // ...get entered data...
   // ...process entered data...
   // ...implement next navigation step...
   // (you would create or recycle the "Page" for the next step here)
   setContentOwned(
     // ...
   );
}

6. Вызовите этот метод из обработчика событий buttonClicked() в CreateAccount:

mainWindow->createProfileClicked();

Это только один способ реализовать то, что вы хотите. Все зависит от сложности вашего проекта.


Редактировать:

Мое предложение, данное в этом ответе, вводит циклические c зависимости классов.

Позвольте мне сначала переформулируйте то, что, по моему мнению, у вас сейчас есть, исходя из ваших комментариев:

mainwindow.h

#include "splashpage.h"

class MainWindow : public DocumentWindow
{
public:
    // ...

    void alaramReadyBtnClicked()
    {
        setContentOwned(new SplashPage(), false);
    }

    // ...
};

splashpage.h:

#include "mainwindow.h"

class SplashPage : public Component, public Button::Listener
{
public:
    SplashPage()
        : mainWindow(nullptr)
    {}

    void setMainWindow(MainWindow * _mainWindow)
    { mainWindow = _mainWindow; }

    void buttonClicked (Button *) override
    {
        if (button == &tvbtnSomething) {
            mainWindow->splashSomethingClicked();
        }
    }

private:
    MainWindow * mainWindow;
};

Есть цикл c зависимость объявлений между MainWindow и классами Page. Когда компилятор видит

mainWindow->splashSomethingClicked();

, он должен увидеть объявление MainWindow, но в mainwindow.h ему нужно объявление SplashPage для этого:

void alaramReadyBtnClicked()
{
    setContentOwned(new SplashPage(), false);
}

Сначала Хорошая практика заключается в использовании в ваших заголовочных файлах элементов защиты

например, mainwindow.h

// you need these include guards to prevent that the compiler
// sees this file a second time; it's a very good rule of thumb to always do this
// in you header files

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include "splashpage.h"

class MainWindow : public DocumentWindow
{
    // ...
};

#endif // !defined(MAINWINDOW_H)

В C ++ есть определенные c ситуации, для которых компилятору не требуется знать полное объявление: если вы используете только указатели или ссылки и не ссылаетесь на них. Затем вы можете использовать предварительное объявление имен классов.

Но вы не можете делать это только со всеми файлами заголовков. Потому что существует понятие «модуля компиляции».

Чтобы разорвать зависимость cycli c, измените свою ... Page.h:

#ifndef SPLASHPAGE_H
#define SPLASHPAGE_H

// don't include mainwindow.h here

class MainWindow; // forward declaration


class SplashPage : public Component, public Button::Listener
{
public:
    SplashPage()
        : mainWindow(nullptr)
    {}

    void setMainWindow(MainWindow * _mainWindow)
    {
        mainWindow = _mainWindow; // pointer copy does not need full declaration
    }

    // note: implementation not in this header file anymore
    void buttonClicked (Button *) override;

private:
    // ...
    MainWindow * mainWindow; // does not need full declaration
};

#endif // !defined(SPLASHPAGE_H)

splashpage. cpp:

#include "mainwindow.h"
#include "splashpage.h"

void SplashPage::buttonClicked (Button *) override
{
    if (button == &tvbtnSomething) {
        mainWindow->splashSomethingClicked();
    }
}

Если вы используете инструмент JUCE Projucer, вы можете легко добавить пары этих файлов, которые уже должны содержать элементы include guard.

enter image description here

2 голосов
/ 01 апреля 2020

Вам нужно реализовать все чисто виртуальные методы в Button::Listener, чтобы сделать ваш класс не абстрактным. Button::Listener содержит эти два метода

virtual void    buttonClicked (Button *)=0
virtual void    buttonStateChanged (Button *)

Второй метод не является чисто виртуальным, поэтому вам не нужно его реализовывать.

Поэтому добавьте метод в свой класс

virtual void    buttonClicked (Button *) override {}

и добавьте код, необходимый при нажатии кнопки.

В зависимости от используемой версии C ++, override может не быть принят компилятором. В этом случае просто опустите его. Он используется, чтобы позволить компилятору выдавать предупреждения / ошибки относительно переопределенных методов.

...