Версия для печати темы

Нажмите сюда для просмотра этой темы в обычном формате

Форум на CrossPlatform.RU _ Qt Система рисования. Печать _ Рисование во вкладках

Автор: QMainWindow 1.8.2010, 15:42

Доброго дня!
Ситуация: делаю прогу для построения графиков. Графики хочу, чтобы рисовались во вкладках (одна вкладка - один график). Не знаю, как заставить рисовальщик рисовать в нужной мне вкладке. Создаю, соответственно, в главном окне QTabWidget, в котором создаю вкладку. Сразу же после ее создания должен в ней отобразиться график. Как это сделать?

Автор: Алексей1153 1.8.2010, 17:15

Если нет никакого подвоха, то, казалось бы, всё элементарно:
в paintEvent вкладки посмотреть, что должна отображать вкладка, и нарисовать это.

Автор: Litkevich Yuriy 1.8.2010, 17:20

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

Автор: QMainWindow 1.8.2010, 20:21

Аха, простой QWidget и поместить его туда. Такс, а как его соединить с вкладкой? Т.е. чтобы виджет tab отвечал своей странице?

Автор: Алексей1153 1.8.2010, 20:26

QMainWindow, читай описание конструктора QWidget.

А как понять "чтобы виджет tab отвечал своей странице" ? :)

Автор: QMainWindow 1.8.2010, 21:00

Имел ввиду, что когда нажимаем на вкладку (на прямоугольник с названием вверху), то на экране выводится именно тот график (или что-то другое), который соответствует данной вкладке))

Автор: Litkevich Yuriy 1.8.2010, 21:49

Прочитай документацию по QTabWidget и всё поймёшь

Автор: QMainWindow 2.8.2010, 10:33

Прочитал еще в первый раз, не разобрался тогда. Теперь понятно как размещать страницы во вкладках. Но пейнтер все равно не рисует. Говорит, что не активирован. Вот код:

tabWidget = new QTabWidget(centralwidget);
    tabWidget->setObjectName(QString::fromUtf8("TabWidget"));
    tabWidget->setGeometry(QRect(5, 30, width()-10, height()-85));
    PageForGraphic = new QWidget;
    PageForGraphic->setGeometry(QRect(5, 30, width()-10, height()-85));

Этот код записан в конструкторе Главного окна. Далее:
void MainWindow::InTabs()
{
    tab = new QWidget(); //Создаем вкладку.
    PageForGraphic->setParent(tab); //Называем ее родителем.
    tabWidget->addTab(tab, QString::fromLocal8Bit("Ãðàôèê %1").arg(tabWidget->count()+1)); //Добавляем ее на TabWidget.
    tabWidget->setCurrentWidget(tab); //Подсвечивем.
}

Этот код записан в отдельной функции. В нее посылается сигнал из диалогового окна, приказывающий создать собственно вкладку. Далее:
void MainWindow::RunMNK(double *PointArrayX, double *PointArrayY, int N, int choise)
{
    //Здесь написан некоторый код. Для его выполнения посылается сигнал из того диалогового окна.
    ChooseGraphic(choise);
}

void MainWindow::ChooseGraphic(int choise)
{
    C=choise;
    update();
}

Это некоторое лирическое отступление, как программа доходит до update(). Далее:
void MainWindow::paintEvent(QPaintEvent *event)
{

    QPainter painter(PageForGraphic);

    switch(C)
    {
    case 1:
        {
            painter.setWindow(/*-LW*maxX-30, -LH*maxY-65,*/0,0, width(), height());
            painter.setRenderHint(QPainter::Antialiasing, true);
            painter.setPen(QPen(QColor(255, 0, 0), 7, Qt::SolidLine, Qt::RoundCap));
            painter.drawPoints(PointArrayXY, M);
        }
    case 2:
        {
            //
        }
    case 3:
        {
            //
        }
    }
}
Сам пейнтэвент. В нем указываю, где рисовать, но он не рисует))
Короче перепробовал все варианты переписи кода, которые приходили в голову, но ни один не помог. Подскажите, где ошибка? Или я чего ее не дописал...

Автор: Алексей1153 2.8.2010, 11:00

Может, оно и не оно, но одна ошибка (даже 3) точно есть: в твоём лирическом о. нет break после каждого case.

вот это тоже сильно смущает
QPainter painter(PageForGraphic);

обычно тут
QPainter painter(this);

Зачем окну рисовать в другом окне ? :)

Автор: QMainWindow 2.8.2010, 11:04

:blink: Эт по невнимательности. Исправил, но painter как не был активированным, так и не активирован... Странно, вот если написать QPainter painter(this);, то он все прекрасно рисует... Но только непосредственно в главном окне((

Автор: Алексей1153 2.8.2010, 11:13

Цитата(QMainWindow @ 2.8.2010, 14:04) *
Странно, вот если написать QPainter painter(this);, то он все прекрасно рисует... Но только непосредственно в главном окне((

А ничего странного. Ты про ООП слышал когда-нибудь ? :) КАЖДОЕ окно само себя должно рисовать. А ты пытался сделать из одного. Каждая вкладка рисует сама себя. Каждый виджет на каждой вкладке - аналогично

Автор: QMainWindow 2.8.2010, 11:17

Ясно. И что тогда делать? Создать отдельный класс для моей PageForGraphic и уже в нем рисовать?

Автор: Алексей1153 2.8.2010, 12:05

QMainWindow, ну, начнём с того, что каждая вкладка у тебя - в общем случае отдельный класс. По крайней мере - разные экземпляры точно.
То есть, у тебя есть набор вкладок (которые ты можешь включить в ТАБ или не включать)

QMyTabPage_name1;
QMyTabPage_name2;
QMyTabPage_name3;
...

На каждой вкладке свои контролы. А контролам пофиг, где они лежат - они выполняют/отображают то, что должны :)

Автор: QMainWindow 2.8.2010, 12:56

И как это связано с paintevent?

Автор: Алексей1153 2.8.2010, 13:03

А зачем с ним связывать ? Его вообще надо будет переопределить только в том самом самописном контроле, в котором будет график рисоваться.

А для работы с вкладками его трогать не нужно

Автор: QMainWindow 2.8.2010, 13:18

А можно примерчик :) Туго доходит <_<

Автор: Алексей1153 2.8.2010, 13:28

QMainWindow, не совсем понимаю - пример чего? :)

Давай так: создай новый проект на основе диалога, добавь туда табконтрол, в него несколько вкладок.

Затем тебе нужен самописный (или какой там ты хотел применить) виджет. Его кидаешь на нужные вкладки.

И это всё. Остальное - детали реализации того виджета (в частности - рисование)

Проект прикрепи - где остановился скажи :)


[offtop]
Прикольная ситуация - класс QMainWindow задаёт вопросы про работу QWidget :))
[/offtop]

Автор: QMainWindow 2.8.2010, 16:29

Выкладываю непосредственно саму программу. Делать стал недавно, поэтому там мало чего еще написано. Все, что я показывал здесь находится в mainwindow.cpp. Вот ссылка на скачку: http://ifolder.ru/18745087. Если поможите, буду оч. благодарен :) Просто не возьму в толк, что писать-то надо?)

Автор: Litkevich Yuriy 2.8.2010, 16:43

QMainWindow, тебе уже говорили на прогорге, рисовать можно "только" в событии paintEvent. Под сделай виджет для рисования подразумевалось не
new QWidget
а создание собственного класса-наследника от QWidget или другого, более подходящего. В обработчике paintEvent этого класса и рисуй.

Цитата(Алексей1153 @ 2.8.2010, 17:28) *
Прикольная ситуация - класс QMainWindow задаёт вопросы про работу QWidget
да, к стати.

QMainWindow, Придумай себе новый ник, иначе в сообщениях будет каша.

Автор: QMainWindow 2.8.2010, 16:51

Так я это уже спрашивал, вот:

Цитата(QMainWindow @ 2.8.2010, 12:17) *
Ясно. И что тогда делать? Создать отдельный класс для моей PageForGraphic и уже в нем рисовать?

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

Автор: Litkevich Yuriy 2.8.2010, 17:27

Цитата(QMainWindow @ 2.8.2010, 20:51) *
вот и спрашиваю, что нужно дописать/создать
смотреть здесь: %QTDIR%\examples\painting\

Автор: QMainWindow 3.8.2010, 14:06

Короче создал класс для виджета, в котором буду рисовать. Сделал .h и .cpp файлы соответственно. Объявил все необходимое, соединил виджет через сигналы с главным окном. В mainwindow.h (заголовочный файл Главного окна) вписал следующее:

#include "PaintWidget.h"
PaintWidget.h - собственно з.ф. моего виджета)) В приват секции создал указатель на на виджет:
private:
PaintWidget *PageForGraphic;
чтобы его видели все слоты в главном окне. Соответственно в mainwindow.cpp написал команды, создающие вкладку и данный виджет(уже с графиком) в ней. В и все. Но он мне выдал ошибку: multiple types in one declaration. Че это такое? Никогда такой ошибки не получал ранее. Как избавиться - не знаю. Знаю, что если убрать из mainwindow.h надпись #include "PaintWidget.h", то ее не будет, но тогда не получится объявить мой виджет. Помогите плиз))

Могу выложить то, что сделал)

Автор: Алексей1153 3.8.2010, 14:19

напиши в самом начале файла "PaintWidget.h" строчку

#pragma once

Автор: Litkevich Yuriy 3.8.2010, 16:04

Где-то ты дважды один и тотже файл включаешь.
QMainWindow, ты заголовочник защитил от множественного включения?

Автор: QMainWindow 3.8.2010, 17:42

Странно, только что проверил еще раз - вроде нет... #ifndef и #endif Qt Creator пишет автоматически при создании заг. файла.

#ifndef PAINTWIDGET_H
#define PAINTWIDGET_H
#endif PAINTWIDGET_H
Так написано. Может скинуть файлы? :)

Точнее #endif // PAINTWIDGET_H
Описка...

Автор: QMainWindow 4.8.2010, 10:13

Короче вот: http://ifolder.ru/18764953, чтобы дело быстрее двигалось.

Автор: Алексей1153 4.8.2010, 10:29

QMainWindow, что ты там такое наколбасил, что сжатый проект не влазит в пост :)

Автор: QMainWindow 4.8.2010, 10:35

Там примерно 700КБ, а в пост разрешено максимум 100КБ.

Так что там? Где я накосячил? :)

Автор: Алексей1153 4.8.2010, 10:54

я не смог скачать - интер тупит сегодня, айфолдер, видимо, тоже

Автор: wiz29 4.8.2010, 10:56

Цитата(QMainWindow @ 2.8.2010, 12:04) *
:blink: Эт по невнимательности. Исправил, но painter как не был активированным, так и не активирован... Странно, вот если написать QPainter painter(this);, то он все прекрасно рисует... Но только непосредственно в главном окне((

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

Автор: QMainWindow 4.8.2010, 11:19

Может так: http://slil.ru/29530936.
wiz29, спасибо, но уже разобрались. Для каждого виджета - эксклюзивный paintEvent.))

Автор: Алексей1153 4.8.2010, 12:33

QMainWindow, тоже не качается. Попробую вечером из дома

скачал. Так я и думал - папки debug и release не удалил ))


Автор: QMainWindow 4.8.2010, 12:33

Цитата(Алексей1153 @ 4.8.2010, 13:22) *
Так я и думал - папки debug и release не удалил ))
ЭЭ, а они причем? :)

Автор: Алексей1153 4.8.2010, 12:34

Цитата(QMainWindow @ 4.8.2010, 15:33) *
ЭЭ, а они причем?

мусорный объём в архиве. А так - ни при чём )

Вот так, с ходу, не понял, где косяк. Щас копаться нет возможности, точно вечером

Автор: QMainWindow 4.8.2010, 12:36

Нет проблем. Главное чтобы косяк убрать, а то работать дальше нельзя. И все мозгИ сломал, не знаю, что делать...

Автор: Алексей1153 4.8.2010, 12:41

QMainWindow, времени у тебя, смотрю, вагон. Закомментируй всё любое, а потом открывай потихоньку, пока не заругается. Там и надо искать. Такой метод применим, когда голова уже квадратная, а компилятор всё ещё ругается ))

Только не забудь копию проекта сделать

Автор: QMainWindow 4.8.2010, 15:13

Я понял, в чем косяк был - я был слепым! :)
Когда мы в заголовочном файле пишем наш класс, то после закрывающей фигурной скопки }, надо ставить ночку с запятой ; !!! А у меня ее не было, и оттуда косяк(подказали прогеры с прогорг). Зато теперь вместо одной ошибки - целых 6! И все связаны с тем, что методы и поля, которые я использую в paintEvent моего виджета (и в частности массив с точками, которые я хочу отобразить) не декларированы! (они объявлены в заголовочном файле главного окна, и мой виджет их не видит). Будем думать как исправить.

Автор: Алексей1153 4.8.2010, 17:12

Цитата(QMainWindow @ 4.8.2010, 18:13) *
Когда мы в заголовочном файле пишем наш класс, то после закрывающей фигурной скопки }, надо ставить ночку с запятой ;

вообще то, по синтаксису C++, это надо делать после любого класса, структуры, юниона или енума (class,struct,union,enum) :)


Когда реализация функции пишется вне тела класса, нужно добавлять область видимости:
void PaintWidget::paintEvent(QPaintEvent *event)
{
}


Для того, чтоб было видно определение класса QPainter, нужно вставить инклуд
#include <QPainter>



PointArrayXY у тебя определён в MainWindow , а пытаешься его исользовать в PaintWidget::paintEvent() без указания экземпляра класса MainWindow. Для этого нужно получить указатель на эту переменную. Я сделал это через конструктор

PaintWidget::PaintWidget(QWidget* pParent,QPointF* pPointArrayXY)
    :QWidget(pParent)
{
    m_pPointArrayXY=pPointArrayXY;
}

(заодно и указатель на родитель приделал - а почему у тебя его не было ? )) )


Соответственно, всё это передаём в конструктор

PageForGraphic = new PaintWidget(this,PointArrayXY);



Но, надо сказать, это всё костыль. Не ООП. У тебя изначально кривоватая структура. Потом всё это всплывёт, понаступай на грабли, почитай книжки :)

И синтаксис C++ учи.

Вот, что у меня получилось. Не запускал, только скомпилировал

 MNK.zip ( 26.22 килобайт ) : 90
 

Автор: QMainWindow 5.8.2010, 11:00

Спасибо! Все эти глупые ошибки выявил еще с самого начала (они не не от незнания языка, а от тупой невнимательности). Сделал через сигналы и слоты. В общем, теперь он работает, рисует, но вот другая проблема: когда я создаю несколько графиков (и соответственно столько же вкладок), то во всех вкладках отображается только один последний созданный график. Я так понимаю, это из-за того, что за все мои вкладки отвечает только одна переменная tab. Встает вопрос: как заставить прогу создавать переменные?

Автор: Алексей1153 5.8.2010, 11:02

QMainWindow, ответ кроется в ООП: храни данные о графике в классе рисовальщика. Тогда данные будут автоматически свои в каждом графике. Можно также предусмотреть возможность рисовать не с внутренних данных, а через указатель с внешних

грабли №1 пройдены :)

Автор: QMainWindow 5.8.2010, 11:21

Закономерный вопрос: что нужно делать?

Автор: Алексей1153 5.8.2010, 11:27

QMainWindow, как что - я ж написал, что делать :) У меня бы это выглядело как-то так:

#include <vector>
QGraphWidget: public QWidget
{
   ...

public:
   typedef std::vector<QGraphElement> td_graph;

private:
   td_graph m_Data;//для внутренних данных
   td_graph* m_pOuterData;//для внешних
   bool m_bUseOuterData;//флаг - показывать внешние данные

public:
   QGraphWidget(QWidget* parent):QWidget(parent)
   {
        m_pOuterData=0;
        m_bUseOuterData=false;
   }

   ...
}


ну и методы для настройки всего этого

Автор: QMainWindow 6.8.2010, 10:13

Спешу поделиццо радостной новостью. Он зарисовал так, как надо! Только я сделал QList и без всяких тайпдефов. :) :) :)

Автор: Алексей1153 6.8.2010, 10:28

QMainWindow, ну, typedef - это лишь для удобства )

Автор: QMainWindow 20.8.2010, 21:49

У меня вопрос: когда я открываю вкладку с графиком, то painter ее снова рисует или мой виджет с графиком на нем просто сохраняется в памяти, и когда я ее открываю, то программа берет ее из памяти? Или мой вопрос не корректен, типа все зависит от реализации?))

Автор: Litkevich Yuriy 21.8.2010, 7:50

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

Что ты в нём делаешь известно только тебе.

Форум Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)