Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Рисование во вкладках
Форум на CrossPlatform.RU > Библиотеки > Qt > Qt Система рисования. Печать
QMainWindow
Доброго дня!
Ситуация: делаю прогу для построения графиков. Графики хочу, чтобы рисовались во вкладках (одна вкладка - один график). Не знаю, как заставить рисовальщик рисовать в нужной мне вкладке. Создаю, соответственно, в главном окне QTabWidget, в котором создаю вкладку. Сразу же после ее создания должен в ней отобразиться график. Как это сделать?
Алексей1153
Если нет никакого подвоха, то, казалось бы, всё элементарно:
в paintEvent вкладки посмотреть, что должна отображать вкладка, и нарисовать это.
Litkevich Yuriy
QMainWindow, сделай виджет, на котором будет рисоваться график и помести его в QTabWidget в качестве страницы
QMainWindow
Аха, простой QWidget и поместить его туда. Такс, а как его соединить с вкладкой? Т.е. чтобы виджет tab отвечал своей странице?
Алексей1153
QMainWindow, читай описание конструктора QWidget.

А как понять "чтобы виджет tab отвечал своей странице" ? :)
QMainWindow
Имел ввиду, что когда нажимаем на вкладку (на прямоугольник с названием вверху), то на экране выводится именно тот график (или что-то другое), который соответствует данной вкладке))
Litkevich Yuriy
Прочитай документацию по QTabWidget и всё поймёшь
QMainWindow
Прочитал еще в первый раз, не разобрался тогда. Теперь понятно как размещать страницы во вкладках. Но пейнтер все равно не рисует. Говорит, что не активирован. Вот код:
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
Может, оно и не оно, но одна ошибка (даже 3) точно есть: в твоём лирическом о. нет break после каждого case.

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

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

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

А ничего странного. Ты про ООП слышал когда-нибудь ? :) КАЖДОЕ окно само себя должно рисовать. А ты пытался сделать из одного. Каждая вкладка рисует сама себя. Каждый виджет на каждой вкладке - аналогично
QMainWindow
Ясно. И что тогда делать? Создать отдельный класс для моей PageForGraphic и уже в нем рисовать?
Алексей1153
QMainWindow, ну, начнём с того, что каждая вкладка у тебя - в общем случае отдельный класс. По крайней мере - разные экземпляры точно.
То есть, у тебя есть набор вкладок (которые ты можешь включить в ТАБ или не включать)

QMyTabPage_name1;
QMyTabPage_name2;
QMyTabPage_name3;
...

На каждой вкладке свои контролы. А контролам пофиг, где они лежат - они выполняют/отображают то, что должны :)
QMainWindow
И как это связано с paintevent?
Алексей1153
А зачем с ним связывать ? Его вообще надо будет переопределить только в том самом самописном контроле, в котором будет график рисоваться.

А для работы с вкладками его трогать не нужно
QMainWindow
А можно примерчик :) Туго доходит <_<
Алексей1153
QMainWindow, не совсем понимаю - пример чего? :)

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

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

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

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


[offtop]
Прикольная ситуация - класс QMainWindow задаёт вопросы про работу QWidget :))
[/offtop]
QMainWindow
Выкладываю непосредственно саму программу. Делать стал недавно, поэтому там мало чего еще написано. Все, что я показывал здесь находится в mainwindow.cpp. Вот ссылка на скачку: http://ifolder.ru/18745087. Если поможите, буду оч. благодарен :) Просто не возьму в толк, что писать-то надо?)
Litkevich Yuriy
QMainWindow, тебе уже говорили на прогорге, рисовать можно "только" в событии paintEvent. Под сделай виджет для рисования подразумевалось не
new QWidget
а создание собственного класса-наследника от QWidget или другого, более подходящего. В обработчике paintEvent этого класса и рисуй.

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

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

Имел в виду, конечно, не просто QWidget, а свой класс, который унаследует все от QWidget. И то, что рисовать можно только в paintEvent это я тоже знаю, вот и спрашиваю, что нужно дописать/создать, чтобы в нем рисовать график для моей вкладки.
Litkevich Yuriy
Цитата(QMainWindow @ 2.8.2010, 20:51) *
вот и спрашиваю, что нужно дописать/создать
смотреть здесь: %QTDIR%\examples\painting\
QMainWindow
Короче создал класс для виджета, в котором буду рисовать. Сделал .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
напиши в самом начале файла "PaintWidget.h" строчку

#pragma once
Litkevich Yuriy
Где-то ты дважды один и тотже файл включаешь.
QMainWindow, ты заголовочник защитил от множественного включения?
QMainWindow
Странно, только что проверил еще раз - вроде нет... #ifndef и #endif Qt Creator пишет автоматически при создании заг. файла.
#ifndef PAINTWIDGET_H
#define PAINTWIDGET_H
#endif PAINTWIDGET_H
Так написано. Может скинуть файлы? :)

Точнее #endif // PAINTWIDGET_H
Описка...
QMainWindow
Короче вот: http://ifolder.ru/18764953, чтобы дело быстрее двигалось.
Алексей1153
QMainWindow, что ты там такое наколбасил, что сжатый проект не влазит в пост :)
QMainWindow
Там примерно 700КБ, а в пост разрешено максимум 100КБ.

Так что там? Где я накосячил? :)
Алексей1153
я не смог скачать - интер тупит сегодня, айфолдер, видимо, тоже
wiz29
Цитата(QMainWindow @ 2.8.2010, 12:04) *
:blink: Эт по невнимательности. Исправил, но painter как не был активированным, так и не активирован... Странно, вот если написать QPainter painter(this);, то он все прекрасно рисует... Но только непосредственно в главном окне((

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

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

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

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

Вот так, с ходу, не понял, где косяк. Щас копаться нет возможности, точно вечером
QMainWindow
Нет проблем. Главное чтобы косяк убрать, а то работать дальше нельзя. И все мозгИ сломал, не знаю, что делать...
Алексей1153
QMainWindow, времени у тебя, смотрю, вагон. Закомментируй всё любое, а потом открывай потихоньку, пока не заругается. Там и надо искать. Такой метод применим, когда голова уже квадратная, а компилятор всё ещё ругается ))

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

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

грабли №1 пройдены :)
QMainWindow
Закономерный вопрос: что нужно делать?
Алексей1153
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
Спешу поделиццо радостной новостью. Он зарисовал так, как надо! Только я сделал QList и без всяких тайпдефов. :) :) :)
Алексей1153
QMainWindow, ну, typedef - это лишь для удобства )
QMainWindow
У меня вопрос: когда я открываю вкладку с графиком, то painter ее снова рисует или мой виджет с графиком на нем просто сохраняется в памяти, и когда я ее открываю, то программа берет ее из памяти? Или мой вопрос не корректен, типа все зависит от реализации?))
Litkevich Yuriy
когда ты открываешь вкладку, то вызывается обработчик paintEvent() этой вкладки и тех виджетов, что размещены на ней.
И, соответственно, исполняется код этого обработчика.

Что ты в нём делаешь известно только тебе.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Форум IP.Board © 2001-2024 IPS, Inc.