LINUX.ORG.RU

Qt: Как получить доступ к ui из другого класса?

 ,


0

1

Всем доброго времени суток. Похожая тема уже звучала, но я так и не нашел в ней ответа на главный вопрос. Ситуация такая: подключил библиотеку QCustomPlot через элемент QWidget, создал отдельный класс-наследник от QCustomPlot, соответственно. Теперь я хочу реализовать всю работу с этой библиотекой в этом классе, оставив в MainWindow только создание элемента объекта этого класса и один метод, который будет только отправлять массив данных в этот объект. Усё. Тут у меня начинается головоломка:

-нужно обращаться к элементу в форме через ui->, которого нет в моем классе, он там не наследован и по ссылке не передан, и никто его там не видел, и никто там его не узнает) как это сделать понятия не имею. Пробовал: множественное наследование и создание там отдельного объекта - не вышло. Не исключено, что в силу моих ошибок. Сделать метод в MainWindow, возвращающий ссылку на объект ui - не вышло, хотя, народ пишет, что это вполне возможно, но нет нигде кода, у кого бы это вышло. Сейчас все работает допотопно: я создаю объект моего класса в MainWindow, и дергаю там методы моего класса. А мне нужно реализовать все там. Возможно, я могу передавать эту ссылку как-то в конструктор при создании объекта, но я не ведаю , как это сделать. Помогите, люди добрые, кто чем может) Код привожу ниже:

Это .cpp моего класса

Charts::Charts(QWidget *parent) : QCustomPlot(parent)
{}


void Charts::setupgraph(QCustomPlot *customPlot)

{
    // set dark background gradient:
    QLinearGradient gradient(0, 0, 0, 400);
    gradient.setColorAt(0, QColor(90, 90, 90));
    gradient.setColorAt(0.38, QColor(105, 105, 105));
    gradient.setColorAt(1, QColor(70, 70, 70));

    customPlot->setBackground(QBrush(gradient));

и т.д.

это его .h

#include <QtCore/QDebug>
#include <qcustomplot.h>

class MainWindow;

class Charts : public QCustomPlot {
    Q_OBJECT

signals:
    void getData(const QByteArray &data);

public:
    explicit Charts(QWidget *parent = nullptr);

protected:
private slots:  

public:
    void setupgraph(QCustomPlot *customPlot);    

private:
    QCPGraph *graphic;          // Объявляем график

};

В MainWindow все в штатном режиме, как Qt прописал.

private:
     Ui::MainWindow *ui;

Заранее благодарен каждому, кто испытает малейшее желание оказать помощь



Последнее исправление: Tumyq (всего исправлений: 7)

-нужно обращаться к элементу в форме через ui->, которого нет в моем классе

Криво спроектировал, вот и страдаешь. Выставляй сигналы и слоты из своего самопального класса. А передавать указатель на ui это дикий костыль.

И используй пожалуйста форматирование кода через lorcode, читать невозможно.

ox55ff ★★★★★
()
Ответ на: комментарий от ox55ff

Пардон за форматирование, не разобрался.

Не совсем понял, что с чем надо вставлять в этих коннектах, какой сигнал должен быть, если надо, скажем, оси красные на графике.

Насчет проектирования, я могу пойти по легкому пути, и пихнуть все в MainWindow , как это делают на всех примерах, но тогда неудобно, надо весь MainWindow перековыривать, если захочется убрать эту библиотеку

Tumyq
() автор топика
Ответ на: комментарий от Tumyq

если надо, скажем, оси красные на графике.

Делаешь у твоего класса Charts свойство axisColor или просто метод setAxisColor, например. Я не понимаю, зачем твоему классу прямой доступ к внешним контролам формы?

ox55ff ★★★★★
()
Ответ на: комментарий от ox55ff

Ну, сейчас у меня есть виждет от кастомплот, он как и другие виджеты находится на майнвиндоу и, соответственно, обращаться к нему нужно от ui.

Tumyq
() автор топика

ничего не понял, но ui наружу не выставляется. Ты явно что то делаешь не то

arcanis ★★★★
()

Замени

private: Ui::MainWindow *ui;
на
public: Ui::MainWindow *ui;
, и обращайся через
(static_cast<MainWindow*>(this->parent()))->ui
лол.

fluorite ★★★★★
()
Ответ на: комментарий от fluorite

Попробовал, начиная с "->ui", ничего не находится

ошибка: invalid static_cast from type 'QObject*' to type 'MainWindow*'

setupgraph((static_cast<MainWindow*>(this->parent()))->ui->customPlot); 

Tumyq
() автор топика

Передавай данные с помощью механизма сигнал слот, и не надо передавать никакие указатели на ui

Silerus ★★★★
()
Ответ на: комментарий от Silerus

И используй пожалуйста форматирование кода через lorcode, читать невозможно.

исправлено

Сигнал, как я понимаю, срабатывает на событие. А мне надо просто нарисовать поле для графика.Посмотрите на метод

void Charts::setupgraph(QCustomPlot *customPlot)
По указателю customPlot я рисую форму. Напишите, пожалуйста, какой коннект то нужен, и с чем его коннектить, в таком случае.

Tumyq
() автор топика
Ответ на: комментарий от fluorite

Он никак не связан, это класс, который наследуется от библиотеки QCustomPlot. В этом вся соль.

Догадываюсь, что эта библиотека, в свою очередь, унаследована от Q_OBJECT

Tumyq
() автор топика
Ответ на: комментарий от Tumyq

Вы сами формируете событие, когда данные готовы делаете emit mysignal(тут ваш массив данных ну пусть const qvector<чего то тут> & он был объявлен); В вашем классе отображение делаете слот который примет эти данные и пошлет на добавление, ну и связать их естественно надо. Например:

void myclass::incrementator(){
emit MyUpdateCounterSignal(++i);

}
где то там этот метод во время работы дергается, возможно даже в другом потоке
void myclass2::updateincrementator(const int &value){ // это слот у нас будет
ui->spinbox->setValue(value);
}

Silerus ★★★★
()
Ответ на: комментарий от fluorite

так оно и создано там в Мейне, и оттуда (в Мейне) можно вызывать методы моего класса(так оно и работает сейчас). А в моем классе обратиться к форме Мейна нельзя. А мне нужно все сделать в моем классе, поэтому и спрашиваю, как обратиться к той форме.

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{

    ui->setupUi(this);
    Charts* charts = new Charts;
    charts->setupgraph(ui->customPlot);
}

customPlot-название моего виджета в форме MainWindow

Tumyq
() автор топика
Ответ на: комментарий от Silerus

понимаете, оси графика не дергаются они появляются, и стоят на месте с момента запуска окна, а чтобы работать с их прорисовкой, нужно обращаться к форме, где стоит виджет. Вопрос, к чему коннектить то?

Tumyq
() автор топика
Ответ на: комментарий от Tumyq

я запутался давайте заново. Опишите где что у вас происходит. Если б я делал какую-то графико рисовалку - то у меня это было бы как то так, есть центральный виджет, на нем лежит виджет построителя меню и прочая лабуда, данные на вывод об считываются отдельно в отдельном потоке и подаются на построитель по мере готовности.

Silerus ★★★★
()
Ответ на: комментарий от Tumyq
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    Charts* charts = new Charts(this);
    charts->setupgraph(charts);
    ui->customPlot = charts;
}
fluorite ★★★★★
()
Ответ на: комментарий от Silerus

Ясно-понятно, идея ясна. У меня все следующим образом: работает терминал, который опрашивает по ComPort-у прибор, в MainWindow реализована работа с ком портом и всяческими запрос-ответами по протоколу обмена, и эта часть будет сохранена для других устройств, НО, меняться будет визуальное отображение полученных данных, то есть, в данном случае, это график, поэтому мне удобнее вынести его в отдельный класс, и отключать -подключать когда вздумается.

Теперь в своем классе я все оформил(разметка осей, прорисовка графиков, доп инфа и т.д.), чтобы это отобразить, надо обратиться к ui, а его не видно в моем классе. Об этом суть моего вопроса.

Tumyq
() автор топика
Ответ на: комментарий от Tumyq

Кажется я понял, и так там где на форме у вас должен быть виджет графиков у вас там должен быть layout и больше ничего, возможно стоит на то место поставить qstackwidget - чтоб сразу загрузить в него все возможные вариации вашего виджета, прокручивая на нужный по мере надобности - над этим надо думать. Далее в конструкторе класса mainwindow вы просто добавляте в layout свой widget и все и не надо вообще больше к ui обращаться, если надо сменить виджет очищаяет layout и загружает новый (но тут как раз стоит подумать о stackwidget)

Silerus ★★★★
()

Попробуйте то же самое, но на Basic или Pascal...

anonymous
()
Ответ на: комментарий от Silerus

о, боги))) с остальными виджетами я разберусь. вопрос не в этом) В моем классе идет работа с изображением графика, то есть я его внешний вид настраиваю там! И мне нужно для этого обращаться к форме.

Посмотрите, что я делаю в методе setupgraph в последней строке: я обращаюсь по ссылке к ui->customPlot. после этого график рисуется (не данные по коннектам, а поле графика:оси, разметка, доп. инфа....) короче, похоже, надо передавать в конструктор ссылку на форму. Может, кто-нибудь подскажет, как это правильно сделать по с++

Tumyq
() автор топика
Ответ на: комментарий от Tumyq

да не нужна вам эта форма, что вы к ней привязались, как только вы выложили виджет на форму все он сам себя отрисует и отрисует все изменения которые вы внесете, если же вам нужно чтобы все перерисовалось срочно - то пошлите в основной класс игнал, а в слоте сделайте update формы.

Silerus ★★★★
()
Ответ на: комментарий от fluorite

создаем объект, вызываем его метод, в который передаем этот же объект, потом этот объект присваиваем форме.. Объясните, пожалуйста, для чего это

Charts* charts = new Charts(this);
charts->setupgraph(charts);
ui->customPlot = charts;

Tumyq
() автор топика
Ответ на: комментарий от Tumyq

Создаём объект твоего супер-пупер класса — наследника QCustomPlot

Charts* charts = new Charts(this);

Настраиваем твой супер-пупер класс твоим методом, принимающим указатель на QCustomPlot

charts->setupgraph(charts);

Устанавливаем настроенный объект твоего супер-пупер класса взамен стандартного QCustomPlot, который лежит у тебя на форме.

ui->customPlot = charts;

Теперь твой супер-пупер класс — наследник QCustomPlot — настроен и лежит на форме.

fluorite ★★★★★
()
Ответ на: комментарий от Tumyq

Вот только что посмотрел исходники, обычная библиотека из не qt там только algorithm - из std - и вести оно обязано также как и другие виджиты написанные на qt тем или иным образом вот например их рисовальщик

class QCP_LIB_DECL QCPPainter : public QPainter
Как видим просто наследник кутешного паинтера

Silerus ★★★★
()
Ответ на: комментарий от fluorite

...и так мой метод настройки не работает. повторюсь,суть в том, что мне не нужны методы в Мейне, так просто работает сейчас, поэтому он там торчит!)

Tumyq
() автор топика
Ответ на: комментарий от Silerus

да просто скажите, чем заменить вызов ссылки *customPlot в моем классе

void Charts::setupgraph(QCustomPlot *customPlot)

{
    // set dark background gradient:
    QLinearGradient gradient(0, 0, 0, 400);
    gradient.setColorAt(0, QColor(90, 90, 90));
    gradient.setColorAt(0.38, QColor(105, 105, 105));
    gradient.setColorAt(1, QColor(70, 70, 70));

    customPlot->setBackground(QBrush(gradient));

Видите, нужно вставить ссылку на форму *customPlot? Вот туда передается ui->customPlot, и от него вызываются методы библиотеки, так работает, по-другому - не работает, по крайней мере у меня

Tumyq
() автор топика
Ответ на: комментарий от Tumyq

ui->customPlot скорее всего это сам объект, чтоб получить на него указатель надо сделать вот так &(ui->customPlot) - но это блин кастыль, можно сделать наоборот

void Charts::setupgraph(QCustomPlot *customPlot)

{
    // set dark background gradient:
    QLinearGradient gradient(0, 0, 0, 400);
    gradient.setColorAt(0, QColor(90, 90, 90));
    gradient.setColorAt(0.38, QColor(105, 105, 105));
    gradient.setColorAt(1, QColor(70, 70, 70));

    --customPlot->setBackground(QBrush(gradient));
    ++emit BackGroundSignal(QBrush(gradient));
где 
signals:
void BackGoundSignal(const QBrush &);
//-----MainWindow
public slots:
void setBackGroundSignal(const QBrush &value){
ui->customPlot->setBackground(value);
}

Silerus ★★★★
()
Ответ на: комментарий от Silerus

Да, я ведь и говорю, что у меня есть объект, и он на форме, все изменения с ним приходиться делать через ui->customPlot.

И все остальное, а там не мало, сигналить - каждое обращение к Объекту?

  customPlot->xAxis->setLabel("Date and Time");
    customPlot->xAxis->setSubTicks(false);
    customPlot->xAxis->setTickLength(0, 4);
    customPlot->xAxis->setRange(0, 8);
    customPlot->xAxis->setBasePen(QPen(Qt::white));
    customPlot->xAxis->setTickPen(QPen(Qt::white));
    customPlot->xAxis->grid()->setVisible(true);
    customPlot->xAxis->grid()->setPen(QPen(QColor(130, 130, 130), 0, Qt::DotLine));
    customPlot->xAxis->setTickLabelColor(Qt::white);
    customPlot->xAxis->setLabelColor(Qt::white);


 и т.д........
Tumyq
() автор топика
Ответ на: комментарий от Silerus

Кстати, что плохого в том, чтобы передать указатель на объект в конструктор при создании экземлпляра в Мейне?

Tumyq
() автор топика
Ответ на: комментарий от Tumyq

В общем, я сделал именно так - указатель на объект передаю в конструктор своего класса. Если кому пригодится, описание ниже:

.h моего класса

class Charts : public QCustomPlot
{
    Q_OBJECT
public:
    explicit Charts(QCustomPlot *p = nullptr); //это, вроде как, нуль указатель
public:
    void someMethod(QCustomPlot *p); //метод на ваш вкус и цвет,которому нужно обращаться к объекту на форме из класса MainWindow
}

ниже его .cpp

#include "chart.h"

Charts::Charts(QCustomPlot *p)
{
    someMethod(p);
}

ну и сам .cpp MainWindow

MainWindow::MainWindow(QWidget *parent) :                                  
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    QCustomPlot *chart = new QCustomPlot(ui->customPlot);
}

MainWindow::~MainWindow()                                                  
{
    delete chart;    
    delete ui;
}

Работает. Милости просим ваши отзывы и предложения)

Tumyq
() автор топика
Ответ на: комментарий от Tumyq

пардон, надо строчку заменить

QCustomPlot *chart = new QCustomPlot (ui->customPlot);
на
Charts *chart = new Charts (ui->customPlot);

Tumyq
() автор топика

Ты очень невнятно излагаешь, что именно ты хочешь получить.

Поэтому дальше идут мои домыслы.

Ты через Qt Designer расположил на форме виджет (объект) класса QCustomPlot.

Но вместо него тебе нужен виджет (объект) твоего унаследованного класса Charts.

Если это действительно так, тебя спасёт Widget Promotion.

Смысл в том, что ты прямо в Designer указываешь, какой класс использовать для создания виджета вместо базового.

cdslow ★★
()
Ответ на: комментарий от cdslow

я про него знаю, и это все так и подключено - с Widget Promotion. Спасибо

Tumyq
() автор топика
Ответ на: комментарий от cdslow

Ты очень невнятно излагаешь, что именно ты хочешь получить.
Поэтому дальше идут мои домыслы.

Все просто: после подключения через промоушен, обратиться к своему новоиспечёному элементу придется через ui, которое создано в MainWindow. Отсюда начинается вся свистопляска: либо вы все делаете в MainWindow, либо как нужно мне - вытаскиваете этот указатель, либо извращаетесь со слотами и сигналами как панацеей от всех бед и невзгод

Tumyq
() автор топика
Ответ на: комментарий от Tumyq

Ты хочешь обращаться к объекту chart извне MainWindow, но не хочешь делать это через сигналы/слоты?

Тогда добавь в MainWindow метод GetChart(), который вернёт тебе указатель ui->chart, и делай с ним что душа пожелает.

Остаётся загадкой, зачем тебе отдельно объект customPlot и отдельно объект chart.

cdslow ★★
()
Ответ на: комментарий от cdslow

Charts - это класс, который настраивает добавленный виджет customPlot в приглядный вид. GetChart() возвращает указатель типа MainWindow, верно?

Tumyq
() автор топика
Ответ на: комментарий от Tumyq

Зачем тебе класс, который настраивает виджет, если ты делаешь свой собственный класс виджета?

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

cdslow ★★
()
Ответ на: комментарий от cdslow

покажите как.охота посмотреть, что он там умеет сам делать) извините, задайтесь вопросом, как изменить внешний вид виджета, не прибегая к вызову ссылки на его форму, и расскажите, пожалуйста, мне, я буду вам очень благодарен)

Tumyq
() автор топика
Ответ на: комментарий от Tumyq

Я кажись въехал в чем корень зла, я честно говоря не очень люблю пользоватся дезигнером и обычно собираю форму ручками, мне так проще. Теперь что у тебя выходит, через виджет промотион - ты создаешь свой собственный виджет и он тебе генерит заголовочный файл и сырцовый файл, который ты нам и показал. Теперь ты начинаешь описывать методы настройки собственного виджета и вот тут тебе нужна сылка на самого себя - рекрусия вышла. this или просто вызов метода, который был унаследован от базового класса тебя спасет и не надо вообще ничего передовать т.е этот кусок вырождается вот в это:

void Charts::setupgraph()

{
    // set dark background gradient:
    QLinearGradient gradient(0, 0, 0, 400);
    gradient.setColorAt(0, QColor(90, 90, 90));
    gradient.setColorAt(0.38, QColor(105, 105, 105));
    gradient.setColorAt(1, QColor(70, 70, 70));
setBackground(QBrush(gradient));

Silerus ★★★★
()
Ответ на: комментарий от Silerus

поправка: он мне ничего не генерит, он добавляет этот виджет и где-то у себя привязывает его к ui. Далее открываются непаханные горизонты возможностей... .cpp и .h я сам добавил, и расписал по мере представления. Во всех встречающихся мне описаниях работы с этой приблудой всё пишется в MainWindow, и там проблем нет, но мне надо вытащить, чтобы эти файлы остались подключаемыми. Нет, можно каждую прогу переписывать заново, но, спрашивается, а нафига тогда ООП.

Tumyq
() автор топика
Ответ на: комментарий от Silerus

метод не вырождается, он остается лежащим камнем методом где-то там, если в нем не появится ui-> , и не вдохнет в него жизнь

Tumyq
() автор топика
Ответ на: комментарий от Tumyq

скорее всего он подвязал ваш хедер, просто попробуйте. На крайняк как я и писал можно вообще без дезигнера обойтись, просто прикрутив ваш виджет(я имею ввиду не тот что на форме, а тот что является вашим сорс хедер файлами) к лайоуту оставленному на форме

Silerus ★★★★
()
Ответ на: комментарий от Silerus

Спасибо за отклик, в общем-то, да, можно и на лайаут, я уже как-то прикрутил через конструктор, работает как надо. Хотелось бы услышать мнение знатоков С++ по этому поводу, Герберт Шилд не против.

И да, спасибо всем еще раз, что ринулись на помощь. Если понадобятся новые предложения, буду рад их обсудить

Tumyq
() автор топика
Ответ на: комментарий от Tumyq

как изменить внешний вид виджета, не прибегая к вызову ссылки на его форму

redlabel.h:

#ifndef REDLABEL_H
#define REDLABEL_H

#include <QLabel>

class RedLabel : public QLabel
    {
    Q_OBJECT
    public:
    explicit RedLabel(QWidget *parent = 0);

    signals:

    public slots:
    };

#endif // REDLABEL_H

redlabel.c:

#include "redlabel.h"

RedLabel::RedLabel(QWidget *parent) : QLabel(parent)
    {
        QPalette pal;
        pal.setColor(QPalette::Normal, QPalette::WindowText, QColor(255, 0, 0));
        setPalette(pal);
    }

Размещаем в MainWindow QLabel, делаем ему промоушен до RedLabel.

cdslow ★★
()
Ответ на: комментарий от cdslow
Charts::Charts(QWidget *parent) : QCustomPlot(parent)
{
    QCustomPlot ch;
    QLinearGradient gradient(0, 0, 0, 400);
    gradient.setColorAt(0, QColor(90, 90, 90));
    gradient.setColorAt(0.38, QColor(105, 105, 105));
    gradient.setColorAt(1, QColor(70, 70, 70));
    ch.setBackground(QBrush(gradient));
}

выводит базовую форму без всего. Понимаете, все эти методы заливки и т.д. относятся к библиотеке QCustomPlot, чтобы ими манипулировать, так сказать, и получать результат на QWidget, нужно найти точку соприкосновения с формой или он выведет стандартное окно, которое ничего не понимает.

Tumyq
() автор топика
Ответ на: комментарий от Tumyq

Твой класс уже унаследован от QCustomPlot, зачем тебе нужен QCustomPlot ch;?

Что мешает сделать просто setBackground(QBrush(gradient)); (без ch)?

cdslow ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.