Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > С/С++: Кроссплатформенное программирование, Qt/Gtk+/wxWidgets > рисование в MainWindow, ООП, MVC, архитектура App


Автор: Aurus 20.6.2012, 06:11
Запутался с классами, кого откуда наследовать. Задача: загрузка данных в модель->расчитывается график-> отображается график; если данные поменялись-> пересчитать график->перерисовать график.

Есть несколько классов: 
MyModel:QAbstractTableModel (с данными)
myWindow:QMainWindow (рисование, отображение) - рисование надо убрать.
Predict (расчёты графика из данных) 
Plot (пересчёт координат) - рисование надо добавить. 

Сейчас имею примерно следующее:
Код

myWindow::myWindow(QWidget *parent) : QMainWindow(parent){
    setupUi(this);
        // создаю объект модели и получаю оттуда данные в вектор.
        tableModel=new MyModel(source,this);
        tableView->setModel(tableModel);
        QVector<QPointF> points;
        for(int n=0; n< tableModel->getValues().size(); ++n){
            points.append(tableModel->getValues().at(n));
        }
        //создаю объект класса Pedict чтобы получить рассчитанные данные
        Predict *predict = new Predict(this);
        QList th;
        th.append(predict->GradDesc(points));
        QVector<QPointF> hx(predict->Hypothesis(points,th));
    //рисование
    ...
    QPixmap *pm =new QPixmap(500,500);
    pm->fill(Qt::white);
    QPainter *p = new QPainter(pm);
    p->drawLine(...);
        QLabel *label = new QLabel;
        label->setPixmap(*pm);
    //устанавливаю свой рисунок на CentralWidget
        QWidget *mainWidget = new QWidget(this);
        QGridLayout *gridLayout = new QGridLayout(mainWidget);
            gridLayout->addWidget(label,1,1,1,5);
            gridLayout->addWidget(textLabel,2,1,1,5);
            ...
        setCentralWidget(mainWidget);
}

Всё хорошо,но перерисовать график в случае изменения данных в модели не имею. Подумал рисовать в классе Plot на QLabel(из класса myWindow). Попробывал создать QLabel в mywindow.ui, рисовать на нём в классе Plot, выводить label вклассе  myWindow
Код

plot.h: class Plot : public QObject, public Ui::myWindow // чтобы иметь доступ к QLabel из mywindow.ui

plot.cpp:
Plot::Plot(...)
{
    QPixmap *pm =new QPixmap(500,500);
    QPainter *p = new QPainter(pm);
    p->drawLine(...);
 qDebug()<<"hello1"; //выводит
    label->setPixmap(*pm);
 qDebug()<<"hello2"; //уже не выводит
}

Код

mywindow.h: class myWindow : public QMainWindow, public Ui::myWindow

mywindow.cpp:
myWindow::myWindow(QWidget *parent) : QMainWindow(parent){
        setupUi(this);
        // создаю объект модели и получаю оттуда данные в вектор.
        tableModel=new MyModel(source,this);
        tableView->setModel(tableModel);
        QVector<QPointF> points;
        for(int n=0; n< tableModel->getValues().size(); ++n){
            points.append(tableModel->getValues().at(n));
        }
        //создаю объект класса Pedict чтобы получить рассчитанные данные
        Predict *predict = new Predict(this);
        QList th;
        th.append(predict->GradDesc(points));
        QVector<QPointF> hx(predict->Hypothesis(points,th));
    //рисование
    Plot *pl =  new Plot(hx, points, 0);
    
    //устанавливаю свой рисунок на CentralWidget
        QWidget *mainWidget = new QWidget(this);
        QGridLayout *gridLayout = new QGridLayout(mainWidget);
            gridLayout->addWidget(label,1,1,1,5);
            gridLayout->addWidget(textLabel,2,1,1,5);
            ...
        setCentralWidget(mainWidget);
}

К сожалению, мое решение заканчивается: The program has unexpectedly finished.
(предположительно ошибка в классе Plot в строчке label->setPixmap(*pm);)

Автор: math64 20.6.2012, 07:39
Посмотри itemviews/chart из примеров Qt, класс PieView - там по модели рисуется диагамма. Аналогично можно рисовать и график.
Никакой Pixmap при изменении данных создавать не нужно - всё рисуется непосредственно в PieView::paintEvent(), в твоём случае
Код

class Plot : public QAbstractItemView
{
    Q_OBJECT
public:
    Plot(QWidget* parent = 0);

protected slots:
    // В этих слотах обрабатываешь изменения данных
    void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight);
    void rowsInserted(const QModelIndex &parent, int start, int end);
    void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end);

protected:
    // Здесь делаешь отрисовку графика
    void paintEvent(QPaintEvent *event);
    // Обрабатываешь изменения размеров графика
    void resizeEvent(QResizeEvent *event);
    // При необходимости перегружаешь другие методы QAbstractItemView
}


Добавлено через 12 минут и 49 секунд
PS: в твоём коде главная ошибка - наследование Plot от Ui::myWindow - оно не даёт доступа к QLabel из mywindow.ui, а создаёт собственную неинициализированную QLabel. Ui::myWindow должен использоваться только в myWindow и лучше не наследовать myWindow от Ui::myWindow. а оставить Ui::myWindow* ui; как в настройках делается по умолчанию. При необходимости доступа к виджетам, созданным в дизайнере из других классов создаётся метод доступа:
Код

QLabel* myWindow::getLabel()
{
    return ui->label;
}

Автор: Aurus 21.6.2012, 08:01
Цитата(math64 @ 20.6.2012,  07:39)
Посмотри itemviews/chart из примеров Qt, класс PieView - там по модели рисуется диагамма. Аналогично можно рисовать и график....

math64, спасибо за пример. Сижу теперь парюсь с QAbstractItemView, при наследовании надо переопределять 8 функций! сложно пока идёт с ними. 
Код

    QRect visualRect(const QModelIndex &index) const;
    void scrollTo(const QModelIndex &index, ScrollHint hint = EnsureVisible);
    QModelIndex indexAt(const QPoint &point) const;
    QModelIndex moveCursor(QAbstractItemView::CursorAction cursorAction,Qt::KeyboardModifiers modifiers);
    int horizontalOffset() const;
    bool isIndexHidden(const QModelIndex &index) const;
    void setSelection(const QRect&, QItemSelectionModel::SelectionFlags command);
    QRegion visualRegionForSelection(const QItemSelection &selection) const;

Автор: math64 21.6.2012, 10:31
visualRect() - оставить как PieView (вызывает itemRect() и учитывает полосы прокрутки)
scrollTo(), moveCursor(), horizontalOffset(), verticalOffset(), isIndexHidden(), setSelection(), visualRegionForSelection() - также
indexAt() - переписать самому. У меня для гистограммы:
Код

QModelIndex HistView::indexAt(const QPoint &point) const
{
    if (validItems == 0)
        return QModelIndex();
    int wx = point.x() + horizontalScrollBar()->value();
    int wy = point.y() + verticalScrollBar()->value();
    int listItem;
    if (wx < totalWidth) {
        if (wx < margin)
            return QModelIndex();
        listItem = int ((wx - margin) / columnWidth);
    } else {
        double itemHeight = QFontMetrics(viewOptions().font).height();
        listItem = int((wy - margin) / itemHeight);
    }
    int validRow = 0;
    for (int row = 0; row < model()->rowCount(rootIndex()); ++row) {
        QModelIndex index = model()->index(row, 1, rootIndex());
        if (model()->data(index).toDouble() > 0.0) {
            if (listItem == validRow)
                return model()->index(row, 0, rootIndex());
            validRow++;
        }
    }
    return QModelIndex();
}


Автор: Aurus 21.6.2012, 12:21
Код

QModelIndex Plot::indexAt(const QPoint &point) const
{
    qDebug()<<"hello";
    return QModelIndex();
}

даже hello не выводит, её кто-нибудь вызывает? или мне её надо вызывать в конструкторе самому когда надо? 
В документации написано, что функция indexAt(); возвращает индекс записи, расположенной в точке point, в модели. smile 

Автор: math64 21.6.2012, 12:57
indexAt() вызывается, например, из QAbstractItemView::mousePressedEvent() для определения куда пользоваетель нажал мышкой.
Если тебе в Plot нужно только нарисовать график - можешь использовать свою реализацию, тогда нажатия мыши будут игнорироваться.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)